Provided by: manpages-pl-dev_4.26.0-1_all 

NAZWA
semop, semtimedop - operacje na semaforach Systemu V
BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)
SKŁADNIA
#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 *_Nullable timeout);
Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):
semtimedop():
_GNU_SOURCE
OPIS
Z każ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
zmodyfikował 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 w
poszczegó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:
• 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, to operacja może być
kontynuowana bezzwłocznie: wartość semafora semval zostanie zmniejszona o wartość bezwzględną sem_op.
Ponadto, jeśli przekazano znacznik SEM_UNDO, to system 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, a w sem_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 semtimedop() zostanie przerwane przez sygnał, co spowoduje niepomyślne
zakończenie wywołania z błędem EINTR, zawartość timeout pozostanie bez zmian.
WARTOŚĆ ZWRACANA
semop() i semtimedop zwracają 0, jeśli zakończą się pomyślnie. W przypadku błędu zwracają -1 i ustawiają
errno wskazując błąd.
BŁĘDY
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 przywileju CAP_IPC_OWNER (ang. capability) w przestrzeni nazw użytkownika,
która zarządza jego przestrzenią nazw IPC.
EAGAIN Operacja opatrzona znacznikiem IPC_NOWAIT w sem_flg nie może być natychmiast wykonana lub upłynął
limit czasu określony w parametrze timeout.
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 w sem_flg dla pewnej operacji, a w systemie nie ma
wystarczającej ilości pamięci na utworzenie nowej struktury do przechowywania informacji o
zmianach.
ERANGE Dla pewnej operacji wartość sem_op+semval przekroczyła SEMVMX, czyli zależną od implementacji
maksymalną wartość semval.
STANDARDY
POSIX.1-2008.
WERSJE
Linux 2.5.52 (przeniesione również na Linuksa 2.4.22), glibc 2.3.3. POSIX.1-2001, SVr4.
UWAGI
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 USTERKI). Gdy wartość semafora jest ustawiane
bezpośrednio za pomocą żądań SETVAL 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 Linuksem, limit ten można
odczytać i zmodyfikować w trzecim polu pliku /proc/sys/kernel/sem. Uwaga: limit ten nie powinien
wynosić ponad 1000, ponieważ istnieje ryzyko, że semop() 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ć zablokowanie do chwili, gdy przeprowadzenie wszystkich zmian
semaforów będzie możliwe. Jest to jednakże niepożądane, gdyż spowodowałoby wymuszenie zablokowania
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.
Linux 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 w Linuksie 2.6.11.
PRZYKŁADY
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;
/* Pomięto kod służący do ustawienia semid */
sops[0].sem_num = 0; /* Działanie na semaforze 0 */
sops[0].sem_op = 0; /* Oczekiwanie na przyjęcie wartości 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Działanie na semaforze 0 */
sops[1].sem_op = 1; /* Zwiększenie wartości o jeden */
sops[1].sem_flg = 0;
if (semop(semid, sops, 2) == -1) {
perror("semop");
exit(EXIT_FAILURE);
}
Kolejny przykład użycia semop() znajduje się w podręczniku shmop(2).
ZOBACZ TAKŻE
clone(2), semctl(2), semget(2), sigaction(2), capabilities(7), sem_overview(7), sysvipc(7), time(7)
TŁUMACZENIE
Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Rafał Lewczuk <R.Lewczuk@elka.pw.edu.p>,
Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl>, Robert Luberda <robert@debian.org> i Michał Kułach
<michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać
zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ
ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-
list@lists.sourceforge.net.
Linux man-pages 6.9.1 2 maja 2024 r. semop(2)