Provided by: manpages-pl-dev_0.6-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;   /* identyfikator procesu, który wykonał
                                        ostatnią operację */

       semop()  wykonuje  operacje  na  wybranych  semaforach z zestawu wskazywanego przez semid.
       Każdy z nsops elementów tablicy wskazywanej przez parametr sops określa 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.

       •  Upłynął limit czasu podany  w  parametrze  timeout  wywołania  semtimedop():  wywołanie
          systemowe  kończy się niepowodzeniem, ustawiając zmienną errno na EAGAIN.

       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.

       •  Upłynął limit czasu podany  w  parametrze  timeout  wywołania  semtimedop():  wywołanie
          systemowe  kończy się niepowodzeniem, ustawiając zmienną errno na EAGAIN.

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

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

       SVr4, POSIX.1-2001.

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.

       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 operacji dozwolonych dla pojedynczego wywołania semop(): 32 (pod
              Linuksem to ograniczenie można odczytać i zmienić, używając trzeciego pola w  pliku
              /proc/sys/kernel/sem).

       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  3.71  projektu Linux man-pages. Opis
       projektu, informacje dotyczące zgłaszania błędów, oraz najnowszą  wersję  oryginału  można
       znaleźć pod adresem http://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ą    3.71
       oryginału.