Provided by: manpages-pl-dev_0.7-2_all bug

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)):

       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  semtimeop()  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  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 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.

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ń 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(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ć
       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.

       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 w ją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);
           }

ZOBACZ TAKŻE

       clone(2),  semctl(2), semget(2), sigaction(2), capabilities(7), sem_overview(7), svipc(7),
       time(7)

O STRONIE

       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/.

TŁUMACZENIE

       Autorami polskiego tłumaczenia niniejszej strony podręcznika man są: Rafał  Lewczuk  (PTM)
       <R.Lewczuk@elka.pw.edu.p>,  Andrzej  Krzysztofowicz  (PTM)  <ankry@mif.pg.gda.pl>,  Robert
       Luberda <robert@debian.org> i Michał Kułach <michal.kulach@gmail.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.