Provided by: manpages-pl-dev_4.23.1-1_all bug

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.8                              2 maja 2024 r.                                         semop(2)