semop(2)

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;   /* semaphore value */
    unsigned short  semzcnt;  /* # waiting for zero */
    unsigned short  semncnt;  /* # waiting for increase */
    pid_t           sempid;   /* PID of process that last
                                 modified the semaphore value */

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.

If sem_op is a positive integer, the operation adds this value to the semaphore value (semval). Furthermore, if SEM_UNDO is specified for this operation, the system subtracts the value sem_op from the semaphore adjustment (semadj) value for this semaphore. This operation can always proceed—it never forces a thread to wait. The calling process must have alter permission on the semaphore set.

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

Note that if semtimedop() is interrupted by a signal, causing the call to fail with the error EINTR, the contents of timeout are left unchanged.

WARTOŚĆ ZWRACANA
On success, semop() and semtimedop() return 0. On failure, they return -1, and set errno to indicate the error.

BŁĘDY

E2BIG
    Wartość nsops przekracza SEMOPM, maksymalną liczbę operacji wykonywanych w jednym wywołaniu.

EACCES
    The calling process does not have the permissions required to perform the specified semaphore operations, and does not have the CAP_IPC_OWNER capability in the user namespace that governs its IPC namespace.

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 (backported into Linux 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.

A semaphore adjustment (semadj) value is a per-process, per-semaphore integer that is the negated sum of all operations performed on a semaphore specifying the SEM_UNDO flag. Each process has a list of semadj values—one value for each semaphore on which it has operated using SEM_UNDO. When a process terminates, each of its per-semaphore semadj values is added to the corresponding semaphore, thus undoing the effect of that process's operations on the semaphore (but see BUGS below). When a semaphore's value is directly set using the SETVAL or SETALL request to semctl(2), the corresponding semadj values in all processes are cleared. The clone(2) CLONE_SYSVSEM flag allows more than one process to share a semadj list; see clone(2) for details.

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
    Maximum number of operations allowed for one semop() call. Before Linux 3.19, the default value for this limit was 32. Since Linux 3.19, the default value is 500. On Linux, this limit can be read and modified via the third field of /proc/sys/kernel/sem. Note: this limit should not be raised above 1000, because of the risk of that semop() fails due to kernel memory fragmentation when allocating memory to copy the sops array.

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.

In Linux 2.6.x, x <= 10, there is a bug that in some circumstances prevents a thread that is waiting for a semaphore value to become zero from being woken up when the value does actually become zero. This bug is fixed in Linux 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;

    /* Code to set semid omitted */

    sops[0].sem_num = 0;        /* Operate on semaphore 0 */
    sops[0].sem_op = 0;         /* Wait for value to equal 0 */
    sops[0].sem_flg = 0;

    sops[1].sem_num = 0;        /* Operate on semaphore 0 */
    sops[1].sem_op = 1;         /* Increment value by one */
    sops[1].sem_flg = 0;

    if (semop(semid, sops, 2) == -1) {
        perror("semop");
        exit(EXIT_FAILURE);
    }

A further example of the use of semop() can be found in 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 (https://www.gnu.org/licenses/gpl-3.0.html) 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.