[ Pobierz całość w formacie PDF ]
znaków. Proces może za pomocą kodu, podobnego do poniżej przedstawionego, zablokować
stronę zawierającą dany łańcuch:
int ret;
/* zablokuj łańcuch znaków 'secret' w pamięci */
ret = mlock (secret, strlen (secret));
if (ret)
perror ("mlock");
Blokowanie całej przestrzeni adresowej
Jeśli proces wymaga zablokowania całej przestrzeni adresowej w pamięci fizycznej, wówczas
użycie funkcji mlock() staje się niewygodne. Aby zrealizować to zadanie powszechnie
wykonywane w przypadku aplikacji czasu rzeczywistego standard POSIX definiuje funkcję
systemową, która blokuje całą przestrzeń adresową:
#include
int mlockall (int flags);
292 | Rozdział 8. Zarządzanie pamięcią
Wywołanie funkcji mlockall() blokuje w pamięci fizycznej wszystkie strony przestrzeni adre-
sowej dla aktualnego procesu. Parametr flags steruje zachowaniem funkcji i jest równy sumie
bitowej poniższych znaczników:
MCL_CURRENT
Jeśli znacznik jest ustawiony, powoduje to, że funkcja mlockall() blokuje wszystkie aktu-
alnie odwzorowane strony w przestrzeni adresowej procesu. Stronami takimi może być stos,
segment danych, pliki odwzorowane itd.
MCL_FUTURE
Jeśli znacznik jest ustawiony, wówczas wykonanie funkcji mlockall() zapewnia, iż wszyst-
kie strony, które w przyszłości zostaną odwzorowane w przestrzeni adresowej, będą rów-
nież zablokowane w pamięci.
Większość aplikacji używa obu tych znaczników jednocześnie.
W przypadku sukcesu funkcja zwraca wartość 0. W przypadku błędu zwraca 1 oraz odpowied-
nio ustawia zmienną errno na jedną z poniższych wartości:
EINVAL
Parametr flags ma wartość ujemną.
ENOMEM
Proces wywołujący zamierzał zablokować więcej stron, niż wynosi ograniczenie zasobów
RLIMIT_MEMLOCK (szczegóły w podrozdziale Ograniczenia blokowania).
EPERM
Wartość ograniczenia zasobów RLIMIT_MEMLOCK była równa zeru, lecz proces nie posiadał
uprawnienia CAP_IPC_LOCK (podobnie, szczegóły w podrozdziale Ograniczenia blokowania).
Odblokowywanie pamięci
Aby umożliwić odblokowanie stron z pamięci fizycznej, pozwalając jądru w razie potrzeby
ponownie wyrzucać je na dysk, POSIX definiuje dwa dodatkowe interfejsy:
#include
int munlock (const void *addr, size_t len);
int munlockall (void);
Funkcja systemowa munlock() odblokowuje strony, które rozpoczynają się od adresu addr
i zajmują obszar len bajtów. Jest ona przeciwieństwem funkcji mlock(). Funkcja systemowa
munlockall() jest przeciwieństwem mlockall(). Obie funkcje zwracają zero w przypadku
sukcesu, natomiast w przypadku niepowodzenia zwracają 1 oraz ustawiają zmienną errno na
jedną z poniższych wartości:
EINVAL
Parametr len jest nieprawidłowy (tylko dla munlock()).
ENOMEM
Niektóre z podanych stron są nieprawidłowe.
EPERM
Wartość ograniczenia zasobów RLIMIT_MEMLOCK była równa zeru, lecz proces nie posiadał
uprawnienia CAP_IPC_LOCK (szczegóły w następnym podrozdziale Ograniczenia blokowania).
Blokowanie pamięci | 293
Blokady pamięci nie zagnieżdżają się. Dlatego też, bez względu na to, ile razy dana strona
została zablokowana za pomocą funkcji mlock() lub mlockall(), pojedyncze wywołanie funkcji
munlock() lub munlockall() spowoduje jej odblokowanie.
Ograniczenia blokowania
Ponieważ blokowanie pamięci może spowodować spadek wydajności systemu (faktycznie,
jeśli zbyt wiele stron zostanie zablokowanych, operacje przydziału pamięci mogą się nie powieść),
dlatego też w systemie Linux zdefiniowano ograniczenia, które określają, ile stron może zostać
zablokowanych przez jeden proces.
Proces, który posiada uprawnienie CAP_IPC_LOCK, może zablokować dowolną liczbę stron
w pamięci. Procesy nieposiadające takiego uprawnienia, mogą zablokować wyłącznie tyle bajtów
pamięci, ile wynosi ograniczenie RLIMIT_MEMLOCK. Domyślnie, ograniczenie to wynosi 32 kB
jest ono wystarczające, aby zablokować jeden lub dwa tajne klucze w pamięci, lecz nie tak duże,
aby skutecznie wpłynąć na wydajność systemu (w rozdziale 6. omówiono ograniczenia zasobów
oraz metody pozwalające na pobieranie i ustawianie tych parametrów).
Czy strona znajduje się w pamięci fizycznej?
Aby ułatwić uruchamianie programów oraz usprawnić diagnostykę, Linux udostępnia funkcję
mincore(), która może zostać użyta, by ustalić, czy obszar danych znajduje się w pamięci fizycz-
nej lub w pliku wymiany na dysku:
#include
#include
int mincore (void *start, size_t length, unsigned char *vec);
Wywołanie funkcji mincore() zwraca wektor bajtów, który opisuje, jakie strony odwzoro-
wania znajdują się w pamięci fizycznej w czasie jej użycia. Funkcja zwraca wektor poprzez
parametr vec oraz opisuje strony rozpoczynające się od adresu start (który musi być wyrów-
nany do granicy strony) i obejmujące obszar o wielkości length bajtów (który nie musi być
wyrównany do granicy strony). Każdy element w wektorze vec odpowiada jednej stronie
z dostarczonego zakresu adresów, poczynając od pierwszego bajta opisującego pierwszą stronę
i następnie przechodząc w sposób liniowy do kolejnych stron. Zgodnie z tym, wektor vec musi
być na tyle duży, aby przechować odpowiednią liczbę bajtów, równą wyrażeniu (length
- 1 + rozmiar strony)/rozmiar strony. Najmniej znaczący bit w każdym bajcie wektora
równy jest 1, gdy strona znajduje się w pamięci fizycznej lub 0, gdy jej tam nie ma. Inne bity
są obecnie niezdefiniowane i zarezerwowane do przyszłego wykorzystania.
W przypadku sukcesu funkcja zwraca 0. W przypadku błędu zwraca 1 oraz odpowiednio
ustawia zmienną errno na jedną z poniższych wartości:
EAGAIN
Brak wystarczających zasobów jądra, aby zakończyć tę operację.
EFAULT
Parametr vec wskazuje na błędny adres.
EINVAL
Parametr start nie jest wyrównany do granicy strony.
294 | Rozdział 8. Zarządzanie pamięcią
ENOMEM
Obszar [start, start + length) zawiera pamięć, która nie jest częścią odwzorowania
opartego na pliku.
Ta funkcja systemowa działa obecnie poprawnie jedynie dla odwzorowań opartych na plikach
i utworzonych za pomocą opcji MAN_SHARED. Bardzo ogranicza to jej zakres użycia.
Przydział oportunistyczny
W systemie Linux używana jest strategia przydziału oportunistycznego. Gdy proces żąda przy-
[ Pobierz całość w formacie PDF ]