shmid_ds, shminfo,
shm_info, vm_area_struct
oraz globalna tablica shm_segs
.
Struktury shminfo
i shm_info
sa wykorzystywane tylko
przez funkcje shmctl()
do przekazywania danych systemowych i
statystycznych.
Tablica shm_segs[SHMMNI]
trzyma wskazniki do strukur shmid_ds
, z ktorych kazda zawiera opis jednego segmentu pamieci dzielonej.
Ma ona miedzy innymi tablice wskaznikow do stron odpowiadajacych
danemu segmentowi oraz liste struktur vm_area_struct
,
odpowiadajacych podlaczeniom tego segmentu do procesow. Po szczegolowy
opis tej ostatniej struktury odsylam do czesci poswieconej pamieci w Linuxie.
Ponizszy rysunek przedstawia wyzej omowione zaleznosci:
include/asm/shmparam.h
:
#define SHMMNI 128 /* maksymalna liczba segmentow dzielonych w systemie */ #define SHMMAX 16MB /* maksymalna wielkosc segmentu pamieci wspolnej */ #define SHMMIN 1B /* minimalna wielkosc segmentu pamieci dzielonej */ /* segment nie moze zajac mniej niz 4KB - strone pamieci */ #define SHMALL 4194304 /* maksymalna liczba stron pamieci dzielonej w systemie */
shmid_ds
include/linux/shm.h
.
Jedna instancja tej struktury opisuje wlasciwosci jednego segmentu.
struct shmid_ds { struct ipc_perm shm_perm; /* struktura zdefiniowana w pliku linux/ipc.h * * zawiera informacje o prawach dostepu do segmentu * * a takze dane o jego zalozycielu */ int shm_segsz; /* wielkosc segmentu w bajtach */ time_t shm_atime; /* czas ostatniego przylaczenia segmentu */ time_t shm_dtime; /* czas ostatniego odlaczenia segmentu */ time_t shm_ctime; /* czas ostatniej operacji na segmencie */ unsigned short shm_cpid; /* pid zalozyciela segmentu */ unsigned short shm_lpid; /* pid procesu, ktory ostatnio dzialal na segmencie */ short shm_nattch; /* liczba biezacych przylaczen segmentu */ unsigned short shm_npages; /* wielkosc segmentu w stronach */ unsigned long *shm_pages; /* tablica wskaznikow do stron */ struct vm_area_struct *attaches; /* lista przylaczen segmentu */ };
shmget()
- sluzy do uzyskania identyfikatora segmentu uzywanego
pozniej przez pozostale funkcje jako pierwszy parametr,
shmctl()
- umozliwia ustawianie i pobieranie wartosci parametrow
zwiazanych z segmentami pamieci dzielonej oraz zaznaczanie segmentow do skasowania,
shmat()
- dolacza segment pamieci dzielonej do przestrzeni
adresowej procesu,
shmdt()
- odlacza segment.
shmget()
DEFINICJA: int shmget(key_t key, int size, int shmflg) WYNIK: w przypadku sukcesu identyfikator segmentu pamieci dzielonej gdy blad -1 oraz na zmiennej errno: EACCESS (brak praw) EEXIST (segment o podanym kluczu istnieje, wiec niemozliwe jest jej utworzenie) EIDRM (segment jest zaznaczony do usuniecia) ENOENT (segment nie istnieje) ENOMEM (brak pamieci na segment) EINVAL (zla wielkosc segmentu)Pierwszym argumentem funkcji jest wartosc klucza, porownywana z wartosciami kluczy istniejacych segmentow. Zwracany jest identyfikator segmentu (odpowiednik plikowego deskryptora) o podanym kluczu, przy czym:
shmget()
.
size
nie moze przekraczac wartosci stalej SHMMAX
dla segmentow tworzonych, albo rozmiaru segmentu juz istniejacego, ale
nie musi byc rowny tej ostatniej wartosci (oznacza to, ze proces moze zazadac podlaczenia
tylko czesci segmentu).
Dzialanie funkcji jest analogiczne do odpowiednich funkcji na semaforach
oraz kolejkach komunikatow (patrz opis algorytmu *get w rozdziale
"Cechy wspolne IPC").
Najpierw sprawdzana jest poprawnosc podanych parametrow,
pozniej odnajduje sie zadany segment w tablicy, nastepnie kontroluje sie prawa
dostepu do segmentu i oblicza jego identyfikator.
W przypadku koniecznosci utworzenia nowgo segmentu pamieci dzielonej odnajduje
sie wolne miejsce w globalnej tablicy segmentow, przydzielana jest nowa
struktura typu shmid_ds
oraz alokowane sa strony pamieci. Jezeli
wszystkie te czynnosci powioda sie zapisuje sie dane o segmencie do niezainicjalizowanej
dotad struktury shmid_ds
, aktualizowane sa liczniki i zmienne
mowiace o uzywanych przez system zasobach, az wreszcie obliczany jest i zwracany
identyfikator nowego segmentu.
shmat()
DEFINICJA: char *shmat(int shmid, char *shmaddr, int shmflg) WYNIK: w przypadku sukcesu 0 oraz adres podlaczenia na zmiennej raddr gdy blad -1 oraz na zmiennej errno: EACCES (brak praw) EIDRM (segment zaznaczony do skasowania) EINVAL (zly identyfikator kolejki lub zly adres doczepienia) ENOMEM (brak pamieci na podlaczenie segmentu)Pierwszym argumentem funkcji jest identyfikator segmentu pamieci dzielonej. Drugi argument -
shmaddr
- jest propozycja wirtualnego adresu
procesu, pod ktory segment ma zostac podlaczony, adres zwrocony przez funkcje
przez nazewnik funkcji nie musi zawsze byc zgodny z shmaddr
(shmaddr
==0 oznacza, ze adres ten wybierze funkcja).
W przypadku pomyslnego przebiegu wartoscia zwracana przez funkcje jest
adres segmentu, a w przypadku niepomyslnego przebiegu jest to wartosc -1.
Dopuszczalne wartosci trzeciego argumentu - zmiennej shmflg
to:
shm_segs
(sprawdza sie, czy segment o podanym identyfikatorze
istnieje, a takze czy zostal juz w pelni poprawnie zainicjalizowany). W kolejnym
kroku funkcja sprawdza poprawnosc proponowanego adresu podlaczenia shmaddr
lub (gdy shmaddr
==0) sama wyszukuje taki adres i stosuje ewentualne
opcje zaokraglania.vm_area_struct
i wypelnia sie jej pola po czym wstawiana jest ona do drzewa AVL procesu oraz
listy odpowiadajacej segmentowi pamieci dzielonej. Struktura
vm_area_struct
zawiera przedefiniowane wskazniki
do funkcji wywolywanych w przypadku nieobecnosci segmentu w pamieci glownej,
zakonczenia dzialania procesu, wykonania fork()
itp, przy czym:
fork()
proces potomny dziedziczy
segmenty ojca, lacznie z segmentami pamieci dzielonej. Struktury
vm_area_struct
z drzewa AVL sa zatem kopiowane, przy czym
kazda taka struktura dotyczaca segmentu pamieci dzielonej jest wlaczana
do listy tych struktur odpowiadajacych temu segmentowi
exit()
lub exec()
segment pamieci dzielonej jest od procesu odlaczany.
shmdt()
DEFINICJA: int shmdt(char *shmaddr); WYNIK: w przypadku sukcesu 0 gdy blad -1 oraz na zmiennej errno EINVAL (podano zly adres podlaczenia)Jedynym argumentem funkcji jest adres podlaczenia segmentu pamieci dzielonej. O ile jest on poprawny, funkcja usuwa to podlaczenie.
Dzialanie tej funkcji jest niejako odwroceniem algorytmu shmat()
.
Poniewaz argumentem funkcji nie jest identyfikator segmentu klopotliwe jest
odnalezienie segmentu.
Nie wystarcza wprost siegnac do tablicy segmentow pod
indeks rowny identyfikatorowi, lecz nalezy przeszukiwac w procesie odpowiednia
liste, az do uzgodnienia adresow. Jezeli podany adres byl poprawny mozna odlaczyc
segment od procesu.
Wstawia sie nowy pid i czas ostatniej operacji.
Zmniejsza sie licznik odwolan do segmentu i gdy spada on
do 0 sprawdza sie, czy aby segment nie jest oznaczony do usuniecia. Jezeli tak
bylo usuwa sie segment zwalniajac zajmowana przez niego i wszystkie struktury
pomocnicze pamiec.
Algorytm konczy dzialanie.
shmctl()
DEFINICJA: int shmctl(int shmid, int cmd, struct shmid_ds *buf) WYNIK: w przypadku sukcesu 0 gdy blad -1 oraz na zmiennej errno: EACCES (brak praw czytania (IPC_STAT)) EFAULT (niepoprawny adres buf) EIDRM (segment zostal w miedzyczasie skasowany) EINVAL (zla wartosc argumentu shmqid) EPERM (brak praw zapisu (IPC_SET lub IPC_RMID))Pierwszy argument to oczywiscie identyfikator segmentu. Argument trzeci sluzy do wprowadzania lub wyprowadzania informacji z funkcji. Dopuszczalne komendy, czyli wartosci argumentu
cmd
to:
shminfo
z pliku include/linux/shm.h
i
umieszcajac ja pod zmienna buf
,
shm_info
z pliku include/linux/shm.h
,
shmid_ds
odpowiadajacej segmentowi pamieci dzielonej (zostaje ona skopiowana
pod adres wskazywany przez buf
),
ipc_perm
odpowiadajacej segmentowi, dane pobierane sa spod wskaznika buf
,
shmget()
przez wszystkie procesy,
Dzialanie funkcji sprowadza sie do sprawdzenia poprawnosci argumentow, a przy niektorych opcjach takze praw dostepu i wykonania zadanej czynnosci: przekopiowania odpowiednich wartosci od lub do uzytkownika, zaznaczenia segmentu do skasowania, zwrocenie wartosci 0, identyfikatora lub najwiekszego uzywanego przez system identyfikatora segmentu. Powyzej opisane jest dzialanie funkcji w roznych przypadkach.
include/linux/shm.h
(naglowki funkcji i definicje stalych),
asm/shmparam.h
(definicje stalych c.d.),
ipc/shm.c
(implementacja).
shmdt()
jako argument przekazuje
sie adres podlaczenia segmentu, a nie identyfikator segmentu, skoro to
drugie pozwala na latwiejsze znalezienie, a nastepnie odczepienie segmentu?
IPC_PRIVATE
) oraz jaki jest
sens tworzenia takich segmentow?
shmctl()
(moze to byc wada lub
zaleta).