NAZWA semop, semtimedop operacje na semaforach Systemu V SKÅADNIA #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semop(int semid, struct sembuf *sops, size_t nsops); int semtimedop(int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout); Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)): OPIS semtimedop(): _GNU_SOURCE Zkażdym semaforem w zestawie semaforã³w Systemu V sä skojarzone nastäpujäce wartoåci: unsigned short semval; /* wartoåä semafora */ unsigned short semzcnt; /* liczba oczekujäcych na zero */ unsigned short semncnt; /* liczba oczekujäcych na zwiäkszenie */ pid_t sempid; /* PID procesu, ktã³ry jako ostatni zmodyfikow aå wartoåä semafora */ semop() wykonuje operacje na wybranych semaforach z zestawu wskazywanego przez semid. Każdy z nsops elementã³w tablicy wskazywanej przez parametr sops jest strukturä okreålajäcä operacjä, ktã³ra ma byä wykonana na pojedynczym semaforze. Struktura struct sembuf zawiera nastäpujäce pola: unsigned short sem_num; /* numer semafora */ short sem_op; /* operacja na semaforze */ short sem_flg; /* znaczniki operacji */ W sem_flg mogä zostaä ustawione znaczniki operacji: IPC_NOWAIT i SEM_UNDO. JeÅli podano znaczniki SEM_UNDO, to operacja zostanie automatycznie cofniäta w chwili, gdy proces zakoåczy dziaåanie. Zestaw operacji zawartych w sops jest wykonywany w kolejnoåci elementã³w tablicy oraz atomowo, co oznacza, że operacje sä wykonywane albo w caåoåci, albo wcale. Zachowanie wywoåania systemowego w sytuacji, gdy nie wszystkie operacje mogä byä wykonane natychmiast, zaleå¼y od ustawienia znacznika IPC_NOWAIT wposzczegã³lnych polach sem_flg, jak to opisano poniå¼ej. Każda z operacji jest wykonywana na semaforze o numerze sem_num w zestawie, przy czym pierwszy semafor ma numer 0. SÄ trzy rodzaje operacji rozrã³å¼niane na podstawie wartoåci sem_op. JeÅli sem_op jest liczbä dodatniä, to wartoåä semafora (semval) zostanie zwiäkszona o tä liczbä. Ponadto jeåli przekazano znacznik SEM_UNDO, to system odejmuje wartoåä (semop) od wartoåci dopasowania (semadj) tego semafora. Operacja ta zawsze moå¼e byä wykonana nigdy nie spowoduje wstrzymania wätku. Proces wywoåujäcy funkcjä musi mieä prawo do modyfikacji zestawu semaforã³w. JeÅli sem_op jest rã³wne 0, proces musi mieä prawo do odczytu zestawu semaforã³w. Jest to operacja "oczekiwania na zero" (wait for zero): gdy semval ma wartoåä 0, operacja moå¼e byä kontynuowana bezzwåocznie. W przeciwnym razie, jeåli w sem_flg przekazany zostaå znacznik IPC_NOWAIT, wã³wczas semop() zgåosi båäd, zaå zmienna errno przyjmie wartoåä EAGAIN (i żadna z operacji z sops nie zostanie wykonana). Jeżeli proces zostanie wstrzymany przez system, wã³wczas wartoåä semzcnt (liczby wätkã³w oczekujäcych na osiägniäcie przez semafor wartoåci zero) zostanie zwiäkszona o 1, a wätek bädzie zawieszony aå¼ do chwili, gdy speåniony zostanie jeden z poniå¼szych warunkã³w: Linux 2016 03 15 1
semval osiägnie wartoåä 0; wã³wczas wartoåä pola semzcnt zostanie zmniejszona o 1. Zestaw semaforã³w zostanie usuniäty: semop() siä nie powiedzie i przypisze zmiennej errno wartoåä EIDRM. WÄtek wywoåujäcy funkcjä przechwyci sygnaå: wartoåä semzcnt zostanie zmniejszona, a semop() zakoåczy siä niepowodzeniem i przypisze zmiennej errno wartoåä EINTR. JeÅli sem_op ma wartoåä mniejszä od 0, to proces musi mieä prawo do modyfikacji zestawu semaforã³w. JeÅli wã³wczas wartoåä semafora semval jest wiäksza lub rã³wna wartoåci bezwzglädnej sem_op, tooperacja moå¼e byä kontynuowana bezzwåocznie: wartoåä semafora semval zostanie zmniejszona o wartoåä bezwzglädnä sem_op. Ponadto, jeåli przekazano znacznik SEM_UNDO, tosystem dodaje caåkowitä wartoåä sem_op do wartoåci dopasowania (semadj) tego semafora. JeÅli wartoåä bezwzglädna sem_op jest wiäksza niå¼ semval, awsem_flg przekazano znacznik IPC_NOWAIT, to semop() zakoåczy siä niepomyålnie, przypisujäc zmiennej errno wartoåä EAGAIN (i żadna z operacji z sops nie zostanie wykonana). W przeciwnym wypadku semncnt (licznik wätkã³w oczekujäcych na zwiäkszenie wartoåci tego semafora) zostanie zwiäkszony o 1, a wätek nie zostanie wznowiony aå¼ do chwili wystäpienia jednego z nastäpujäcych zdarzeå: semval staje siä wiäksza lub rã³wna wartoåci caåkowitej sem_op: operacja przebiega teraz zgodnie z opisem powyå¼ej. Zestaw zostanie usuniäty z systemu: semop() zwrã³ci båäd i ustawi zmiennä errno na wartoåä EIDRM. WÄtek wywoåujäcy funkcjä przechwyci sygnaå: wartoåä semncnt zostanie zmniejszona, a semop() zakoåczy siä niepowodzeniem i przypisze zmiennej errno wartoåä EINTR. JeÅli operacja zostanie zakoåczona pomyålnie, to wartoåci sempid kaå¼dego z semaforã³w wyszczegã³lnionych w tablicy wskazywanej przez sops przypisany zostanie identyfikator procesu (PID) wywoåujäcego. Ponadto polu sem_otime przypisany zostanie bieå¼äcy czas. semtimedop() semtimedop() zachowuje siä tak samo jak semop(), poza tym że w tych przypadkach, gdy wätek wywoåujäcy by spaå, czas trwania spania jest ograniczony przez czas okreålony w strukturze timespec, ktã³rej adres jest przekazywany w parametrze timeout (interwaå zostanie zaokräglony w gã³rä do dokåadnoåci zegara, a wystäpowanie opã³åºnienia planisty jädra oznacza, że ten interwaå moå¼e byä nieznacznie przekroczony). JeÅli osiägniäto okreålony limit czasu, to semtimedop() zwraca båäd, ustawiajäc errno na EAGAIN (i żadna z operacji w sops nie jest wykonywana). Jeżeli parametr timeout jest NULL, to semtimedop() zachowuje siä dokåadnie tak samo jak semop(). ProszÄ zauwaå¼yä, że jeåli semtimeop() zostanie przerwane przez sygnaå, co spowoduje niepomyålne zakoåczenie wywoåania z båädem EINTR, zawartoåä timeout pozostanie bez zmian. WART OÅÄ ZWRACANA semop() i semtimedop zwracajä 0, jeåli zakoåczä siä pomyålnie. W przeciwnym wypadku zwracajä 1 i przypisujä zmiennej errno wartoåä wskazujäcä na rodzaj båädu. BÅÄDY W przypadku wystäpienia båädu, zmiennej errno przypisywana jest jedna z nastäpujäcych wartoåci: E2BIG WartoÅÄ nsops przekracza SEMOPM, maksymalnä liczbä operacji wykonywanych w jednym wywoåaniu. EACCES Proces wywoåujäcy nie ma wystarczajäcych uprawnieå do wykonania podanych operacji na semaforach oraz nie ma ustawionego atrybutu CAP_IPC_OWNER. EAGAIN Operacja opatrzona znacznikiem IPC_NOWAIT w sem_flg nie moå¼e byä natychmiast wykonana lub upåynäå limit czasu okreålony wparametrze timeout. Linux 2016 03 15 2
EFAULT Adres wskazywany przez parametr sops lub timeout jest niedostäpny. EFBIG Numer semafora sem_num, do ktã³rego odnosi siä jedna z operacji, jest mniejszy od 0 albo wiäkszy lub rã³wny liczbie semaforã³w w zestawie. EIDRM Zestaw semaforã³w zostaå usuniäty. EINTR WÄtek przechwyciå sygnaå podczas oczekiwania na odebranie komunikatu; patrz signal(7). EINVAL Zestaw semaforã³w nie istnieje lub wartoåä semid jest mniejsza od zera, lub wartoåä nsops nie jest liczbä dodatniä. ENOMEM Znacznik SEM_UNDO zostaå ustawiony wsem_flg dla pewnej operacji, a w systemie nie ma wystarczajäcej iloåci pamiäci na utworzenie nowej struktury do przechowywania informacji ozmianach. ERANGE Dla pewnej operacji wartoåä sem_op+semval przekroczyåa SEMVMX, czyli zaleå¼nä od implementacji maksymalnä wartoåä semval. WERSJE semtimedop() po raz pierwszy pojawiåo siä w Linuksie 2.5.52, ale zostaåo przeniesione (backport) do jädra 2.4.22. Biblioteka glibc obsåuguje semtimedop() od wersji 2.3.3. ZGODNE Z POSIX.1 2001, POSIX.1 2008, SVr4. UWAGI DoÅÄczenie <sys/types.h> i <sys/ipc.h> nie jest wymagane na Linuksie ani przez żadnÄ z wersji POSIX. Jednak niektã³re stare implementacje wymagajä doåäczenia tych plikã³w nagåã³wkowych, SVID rã³wnieå¼ dokumentuje ich doåäczenie. Aplikacje ktã³re majä byä przenoåne na tego typu stare systemy mogä wymagaä doåäczenia omawianych plikã³w nagåã³wkowych. Struktury sem_undo nie sä dziedziczone przez dzieci tworzone za pomocä fork(2), ale sä dziedziczone przez wywoåanie systemowe execve(2). semop() nie jest nigdy automatycznie uruchamiana ponownie po przerwaniu przez funkcjä obsåugi sygnaåu, niezaleå¼nie od ustawieå znacznika SA_RESTART uå¼ywanego podczas tworzenia funkcji obsåugi sygnaåu. WartoÅÄ dopasowania semafora (semadj) jest przypisana do procesu i semafora i jest sumä wszystkich operacji na semaforze z flagä SEM_UNDO, ze znakiem przeciwnym. Każdy proces ma listä wartoåci semadj po jednej dla kaå¼dego semafora na ktã³rej operuje za pomocä SEM_UNDO. Gdy proces siä koåczy wszystkie jego wartoåci semadj przypisane do poszczegã³lnych semaforã³w sä do nich dodawane, co powoduje przywrã³cenie wartoåci semafora sprzed dziaåania procesu (zob. jednak na BÅÄDY). Gdy wartoåä semafora jest ustawiane bezpoårednio za pomocä żÄdaÅ SET- VAL lub SETALL do semctl(2), to odpowiadajäce wartoåci semadj we wszystkich procesach sä czyszczone. Flaga CLONE_SYSVSEM clone(2) pozwala to dzielenie listy semadj przez wiäcej niå¼ jeden proces, wiäcej szczegã³åã³w w podräczniku clone(2). WartoÅci semval, sempid, semzcnt i semnct dla semafora moå¼na odczytaä za pomocä odpowiednich wywoåaå semctl(2). Limity semaforã³w WywoÅania semop() dotyczä nastäpujäce ograniczenia zasobã³w zwiäzanych z zestawami semaforã³w: SEMOPM Maksymalna liczba dozwolonych operacji na jedno wywoåanie semop(). Przed Linuksem 3.19 domyålna wartoåä tego limitu wynosiåa 32. Od Linuksa 3.19 jest to 500. Pod Linux 2016 03 15 3
Linuksem, limit ten moå¼na odczytaä i zmodyfikow aä w trzecim polu pliku /proc/sys/kernel/sem. Uwaga: limit ten nie powinien wynosiä ponad 1000, poniewaå¼ istnieje ryzyko, że semop(2) nie powiedzie siä z powodu fragmentacji pamiäci jädra przy przydzielaniu pamiäci dla kopii tablicy sops. SEMVMX Maksymalna dozwolona wartoåä semval: zaleå¼y od implementacji (32767). Implementacja w systemie Linux nie nakåada wewnätrznych ograniczeå na zmianä wartoåci semafora podczas zakoåczenia procesu (SEMAEM), na ogã³lnosystemowä maksymalnä liczbä struktur przechowujäcych informacje o zmianach stanu semaforã³w (SEMMNU), ani na maksymalnä dla procesu liczbä struktur przechowujäcych informacje o zmianach stanu semaforã³w. USTERKI Gdy proces koåczy dziaåanie, zestaw skojarzonych z nim struktur semadj jest wykorzystywany do cofniäcia efektã³w wszystkich operacji na semaforach, ktã³re ten proces wykonaå z ustawionym znacznikiem SEM_UNDO. Wprowadza to trudnoåä: jeå¼eli jedna (lub wiäcej) spoårã³d tych zmian semaforã³w spowodowaåby prã³bä zmniejszenia wartoåci semafora poniå¼ej zera, to co implementacja powinna uczyniä? Jednym z moå¼liwych podejåä do tego zadadnienia mogåo by byä zablokow anie do chwili, gdy przeprowadzenie wszystkich zmian semaforã³w bädzie moå¼liwe. Jest to jednakå¼e niepoå¼ädane, gdyå¼ spowodowaåoby wymuszenie zablokow ania zakoåczenia procesu na dowolnie dåugi okres. InnÄ moå¼liwoåciä jest zignorowanie wszystkich takich zmian semaforã³w (nieco analogiczne do niepomyålnego zakoåczenia, gdy dla operacji na semaforze podany jest znacznik IPC_NOWAIT). Linux przyjäå trzecie rozwiäzanie: zmniejszenie wartoåci semafora na tyle, na ile jest to moå¼liwe (tzn. do zera) i umoå¼liwienie natychmiastowej kontynuacji koåczenia dziaåania procesu. JÄdra 2.6.x, gdzie x <= 10, zawierajä båäd, ktã³ry w pewnych okolicznoåciach spowoduje, że wätek czekajäcy na zmniejszenie wartoåci semafora do zera nie zostanie obudzony, gdy ta wartoåä rzeczywiåcie osiägnie zero. BÅÄd zostaå poprawiony wjädrze 2.6.11. PRZYKÅAD NastÄpujÄcy fragment kodu uå¼ywa semop() do atomowego oczekiwania na to, by wartoåä semafora 0 doszåa do zera. NastÄpnie wartoåä semafora jest zwiäkszana o jeden. struct sembuf sops[2]; int semid; /* PominiÄto kod ustawiajäcy semid */ sops[0].sem_num = 0; /* DziaÅaj na semaforze 0 */ sops[0].sem_op = 0; /* Czekaj na wartoåä rã³wnä 0 */ sops[0].sem_flg = 0; sops[1].sem_num = 0; /* DziaÅaj na semaforze 0 */ sops[1].sem_op = 1; /* ZwiÄksz wartoåä o jeden */ sops[1].sem_flg = 0; if (semop(semid, sops, 2) == 1) { perror("semop"); exit(exit_failure); } ZOBACZTAKÅ»E clone(2), semctl(2), semget(2), sigaction(2), capabilities(7), sem_overview(7), svipc(7), time(7) OSTRONIE Angielska wersja tej strony pochodzi z wydania 4.07 projektu Linux man pages. Opis projektu, informacje dotyczäce zgåaszania båädã³w, oraz najnowszä wersjä oryginaåu moå¼na znaleåºä pod adresem https://www.kernel.org/doc/man pages/. Linux 2016 03 15 4
TÅ UMACZENIE Autorami polskiego tåumaczenia niniejszej strony podräcznika man sä: RafaÅ Lewczuk (PTM) <R DOT Lewczuk AT elka DOT pw DOT edu DOT p>, Andrzej Krzysztofowicz (PTM) <ankry AT mif DOT pg DOT gda DOT pl>, Robert Luberda <robert AT debian DOT org> i MichaÅ KuÅach <michal DOT kulach AT gmail DOT com>. Polskie tåumaczenie jest czäåciä projektu manpages-pl; uwagi, pomoc, zgåaszanie båädã³w na stronie http://sourceforge.net/projects/manpages-pl/. Jest zgodne z wersjä 4.07 oryginaåu. Linux 2016 03 15 5