8 ŚRODOWISKO SYSTEMU UNIX_______
while (read(dp->fd, (char *) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)) { if (dirbuf.d_ino == 0) /* pusta pozycja */ continue;
d.ino = dirbuf.d_ino;
strncpy(d.name, dirbuf.d_name, DIRSIZ); d.namefDIRSIZ] = ’\0’; /* zapewnia poprawny koniec */ return &d;
return NULL;
Chociaż fsize jest programem raczej wyspecjalizowanym, ilustruje jednak kilka ważnych idei. Po pierwsze, nie wszystkie programy są „programami systemowymi”; niektóre po prostu korzystają z informacji udzielonych przez system operacyjny. Dla tych programów zasadnicze znaczenie ma to, że reprezentacja takich informacji „systemowych” występuje jedynie w standardowych nagłówkach, a zatem - zamiast wciskać do programu niezbędne deklaracje - w programie umieszcza się te nagłówki. I drugie spostrzeżenie: można - z pewną dozą ostrożności - zapewnić dostęp do obiektów zależnych od systemu w sposób względnie od systemu niezależny. Funkcje z biblioteki standardowej są tego najlepszym przykładem.
*
Ćwiczenie 8.5. Zmień program fsize tak, aby wypisywał również inne informacje pochodzące z węzła pliku.
W rozdziale 5 pokazaliśmy bardzo ograniczoną wersję dystrybutora pamięci, zrealizowaną metodą stosową. Wersja, którą teraz napiszemy, jest pozbawiona tych ograniczeń. Wywołania funkcji malloc i free mogą wystąpić w dowolnej kolejności; malloc zwraca się do systemu operacyjnego o dodatkową pamięć. Funkcje te ilustrują niektóre z naszych rozważań dotyczących tworzenia programów maszynowozależnych w sposób w miarę niezależny od maszyny. Demonstrują także autentyczne zastosowanie struktur, unii i definicji typów.
Zamiast przydzielać pamięć z tablicy o ustalonym rozmiarze, przydzielonej programowi podczas kompilacji, funkcja malloc będzie w miarę potrzeby pobierać pamięć od systemu operacyjnego. Różne fragmenty programu mogą niezależnie od siebie żądać przydziału pamięci, nie korzystając z tego dystrybutora, toteż obszar pamięci, którym zarządza funkcja malloc, może nie być ciągły. Z tego powodu wolna pamięć jest zorganizowana w łańcuch bloków. Każdy blok zawiera rozmiar, wskaźnik do następ-8.7 PRZYKŁAD - DYSTRYBUTOR PAMIĘCI
nego bloku oraz obszar wolnej pamięci. Bloki są uporządkowane w cych adresów pamięci, a ostatni blok (o najwyższym adresie) wskazuje na pierwszy.
lisia wolnych bloków
\ |
/_____ \ / ___N |
i | ||||||||||
• • • • • |
zajęte |
/ajętc |
/ajętc |
7- |
• .......... |
/ajętc |
u |
....... |
wolny blok. własność funkcji malloc
zajęte
zajęty blok. własność funkcji malloc
pamięć nic obsługiwana prze/ funkcję malloc
Żądanie przydziału pamięci powoduje wyszukanie w łańcuchu wolnych bloków obszaru o wystarczająco dużym rozmiarze. Ten algorytm jest nazywany „pierwszą przymiarką” (ang. first fit) w przeciwieństwie do algorytmu „najlepszej przymiarki” (ang. bestfit), w którym szuka się najmniejszego z bloków spełniających to żądanie. Jeżeli obszar ma dokładnie żądany rozmiar, to blok jest odłączany od łańcucha i przekazywany użytkownikowi. Zbyt duży obszar jest dzielony tak, aby wystarczająco dużą część przekazać użytkownikowi; reszta pozostaje w łańcuchu wolnych bloków. Gdy w łańcuchu nie ma dostatecznie dużego obszaru, wówczas od systemu operacyjnego pobiera się nowy, wielki kawał pamięci i przyłącza go do łańcucha.
Zwalnianie pamięci także powoduje przeszukanie łańcucha wolnych bloków w celu znalezienia właściwego miejsca dla zwolnionego bloku. Jeżeli ten blok przylega z którejkolwiek strony do innego wolnego bloku, to zrasta się z nim, tworząc jeden większy blok; pamięć nie będzie więc zbyt rozczłonkowana. Sprawdzanie przylegania jest proste, ponieważ łańcuch wolnych bloków jest uporządkowany w kolejności rosnących adresów.
Pozostaje do omówienia zasygnalizowany już w rozdz. 5 problem: czy położenie obszarów pamięci przydzielanych przez funkcję malloc odpowiada wymaganiom obiektów, które będą w nich umieszczane. Chociaż maszyny się różnią, to dla każdej istnieje typ nakładający najsilniejsze ograniczenia: jeśli obiekty tego typu mogą być umieszczone w pamięci pod pewnym szczególnym adresem, to mogą również obiekty wszystkich innych typów. Dla pewnych maszyn takim wymagającym typem jest double; dla innych wystarczy int lub long.
Każdy wolny blok zawiera wskaźnik do następnego bloku łańcucha, liczbę określającą rozmiar bloku oraz sam obszar wolnej pamięci; taka informacja sterująca na początku bloku nazywa się „nagłówkiem” (ang. heac/er). Dla uproszczenia kontroli
245