SEMGET(2) Podręcznik programisty Linuksa SEMGET(2)

semget - pobranie identyfikatora zestawu semaforów Systemu V

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

The semget() system call returns the System V semaphore set identifier associated with the argument key. It may be used either to obtain the identifier of a previously created semaphore set (when semflg is zero and key does not have the value IPC_PRIVATE), or to create a new set.

Nowy zestaw składający się z nsems semaforów zostanie utworzony, jeśli parametr key będzie mieć wartość IPC_PRIVATE lub gdy zestaw semaforów skojarzony z key nie istnieje, a w parametrze semflg zostanie przekazany znacznik IPC_CREAT.

Jeśli w parametrze semflg podano zarówno IPC_CREAT, jak i IPC_EXCL oraz już istnieje zestaw semaforów o kluczu key, to semget() kończy się błędem, ustawiając errno na wartość EEXIST. (Działa to analogicznie do O_CREAT | O_EXCL w open(2)).

Podczas tworzenia 9 najmniej znaczących bitów argumentu semflg określa prawa dostępu do zestawu semaforów (dla właściciela, grupy i innych). Bity te mają ten sam format i takie samo znaczenie, jak parametr mode wywołania open(2) (prawa uruchamiania nie są istotne dla semaforów, natomiast prawa zapisu oznaczają możliwość zmiany wartości semaforów).

Podczas tworzenia nowego zestawu semaforów semget() inicjuje związaną z zestawem semaforów strukturę semid_ds (patrz semctl(2)) w następujący sposób:

  • sem_perm.cuid i sem_perm.uid przyjmują wartość efektywnego identyfikatora właściciela procesu wywołującego.
  • sem_perm.cgid i sem_perm.gid przyjmują wartość efektywnego identyfikatora grupy procesu wywołującego.
  • 9 najmniej znaczących bitów pola sem_perm.mode jest kopiowanych z 9 najmniej znaczących bitów semflg.
  • sem_nsems jest ustawiane na wartość nsems.
  • sem_otime przyjmie wartość 0.
  • sem_ctime przypisywany jest bieżący czas.

Parametr nsems może mieć wartość 0 (nie jest brany pod uwagę), jeśli nie będzie tworzony zestaw semaforów. W przeciwnym przypadku parametr nsems musi być większy od 0 i mniejszy lub równy maksymalnej liczbie semaforów w zestawie (SEMMSL).

Jeżeli zestaw semaforów już istnieje, to weryfikowane są uprawnienia.

W przypadku pomyślnego zakończenia, funkcja zwraca identyfikator zestawu semaforów (liczbę nieujemną), a w przeciwnym przypadku zwraca -1 i przypisuje zmiennej errno stosowną wartość.

W przypadku niepowodzenia, zmiennej errno zostanie przypisana jedna z następujących wartości:
EACCES
A semaphore set exists for key, but the calling process does not have permission to access the set, and does not have the CAP_IPC_OWNER capability in the user namespace that governs its IPC namespace.
EEXIST
IPC_CREAT i IPC_EXCL określono w semflg, lecz zestaw semaforów dla key już istnieje.
EINVAL
nsems jest mniejsze niż 0 lub większe niż ograniczenie liczby semaforów w zestawie (SEMMSL)
EINVAL
Zestaw semaforów, do którego odnosi się key już istnieje, lecz nsems jest większe niż liczba semaforów w tym zestawie.
ENOENT
Nie ma zestawu semaforów o identyfikatorze key i znacznik IPC_CREAT nie został przekazany w parametrze semflg.
ENOMEM
Zestaw semaforów powinien zostać utworzony, ale w systemie brak jest pamięci na utworzenie nowej struktury danych.
ENOSPC
Nastąpiła próba przekroczenia ograniczenia liczby zestawów (SEMMNI) lub łącznej liczby semaforów w systemie (SEMMNS).

SVr4, POSIX.1-2001.

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.

IPC_PRIVATE nie jest znacznikiem, ale szczególną wartością typu key_t. Jeśli wartość ta zostanie użyta jako parametr key, to system uwzględni jedynie 9 najniższych bitów parametru msgflg i (w razie powodzenia) utworzy nowy zestaw semaforów.

Wartości semaforów w nowo utworzonym zestawie są nieokreślone (POSIX.1-2001 jasno o tym mówi, choć POSIX.1-2008 określa, że przyszła wersja tego standardu może wymagać implementacji inicjującej semafory z wartością 0). Mimo że Linux, tak jak i wiele innych implementacji, nadaje im wartość początkową równą 0, to przenośne aplikacje nie powinny zależeć od tego zachowania i zamiast tego powinny wyraźnie inicjować semafory żądanymi wartościami.

Aby zainicjować semafory, należy na zestawie semaforów użyć operacji SETVAL lub SETALL wywołania semctl(2). W sytuacji gdy wiele procesów nie wie, który pierwszy zainicjuje zestaw semaforów, to aby uniknąć sytuacji wyścigu, można sprawdzić, czy pole sem_otime powiązanej struktury danych zwracanej przez operację IPC_STAT wywołania semctl(2) ma wartość niezerową.

Wywołania semget() dotyczą następujące ograniczenia zasobów związanych z zestawami semaforów:
SEMMNI
Limit liczby zestawów semaforów w systemie. W systemach Linux przed wersją 3.19 domyślna wartość tego limitu wynosiła 128. Od Linuksa 3.19 jest to 32 000. Pod Linuksem to ograniczenie można odczytać i zmienić, używając czwartego pola pliku /proc/sys/kernel/sem).
SEMMSL
Maksymalna liczba semaforów dla danego ID semafora. W systemach Linux przed wersją 3.19 domyślna wartość tego limitu wynosiła 250. Od Linuksa 3.19 jest to 32 000. Pod Linuksem to ograniczenie można odczytać i zmienić, używając pierwszego pola pliku /proc/sys/kernel/sem).
SEMMNS
Limit liczby semaforów w systemie: wartość zależna od lokalnych ustawień (pod Linuksem to ograniczenie można odczytać i zmienić, używając drugiego pola pliku /proc/sys/kernel/sem). Proszę zauważyć, że systemowa liczba semaforów jest również ograniczona przez iloczyn SEMMSL i SEMMNI.

Nazwa IPC_PRIVATE prawdopodobnie nie jest najszczęśliwsza. IPC_NEW w sposób bardziej przejrzysty odzwierciedlałoby rolę tej wartości.

The program shown below uses semget() to create a new semaphore set or retrieve the ID of an existing set. It generates the key for semget() using ftok(3). The first two command-line arguments are used as the pathname and proj_id arguments for ftok(3). The third command-line argument is an integer that specifies the nsems argument for semget(). Command-line options can be used to specify the IPC_CREAT (-c) and IPC_EXCL (-x) flags for the call to semget(). The usage of this program is demonstrated below.

We first create two files that will be used to generate keys using ftok(3), create two semaphore sets using those files, and then list the sets using ipcs(1):


$ touch mykey mykey2
$ ./t_semget -c mykey p 1
ID = 9
$ ./t_semget -c mykey2 p 2
ID = 10
$ ipcs -s
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x7004136d 9          mtk        600        1
0x70041368 10         mtk        600        2

Next, we demonstrate that when semctl(2) is given the same key (as generated by the same arguments to ftok(3)), it returns the ID of the already existing semaphore set:


$ ./t_semget -c mykey p 1
ID = 9

Finally, we demonstrate the kind of collision that can occur when ftok(3) is given different pathname arguments that have the same inode number:


$ ln mykey link
$ ls -i1 link mykey
2233197 link
2233197 mykey
$ ./t_semget link p 1       # Generates same key as 'mykey'
ID = 9

/* t_semget.c
   Licensed under GNU General Public License v2 or later.
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void
usage(const char *pname)
{
    fprintf(stderr, "Usage: %s [-cx] pathname proj-id num-sems\n",
            pname);
    fprintf(stderr, "    -c           Use IPC_CREAT flag\n");
    fprintf(stderr, "    -x           Use IPC_EXCL flag\n");
    exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
    int semid, nsems, flags, opt;
    key_t key;
    flags = 0;
    while ((opt = getopt(argc, argv, "cx")) != -1) {
        switch (opt) {
        case 'c': flags |= IPC_CREAT;   break;
        case 'x': flags |= IPC_EXCL;    break;
        default:  usage(argv[0]);
        }
    }
    if (argc != optind + 3)
        usage(argv[0]);
    key = ftok(argv[optind], argv[optind + 1][0]);
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }
    nsems = atoi(argv[optind + 2]);
    semid = semget(key, nsems, flags | 0600);
    if (semid == -1) {
        perror("semget");
        exit(EXIT_FAILURE);
    }
    printf("ID = %d\n", semid);
    exit(EXIT_SUCCESS);
}

semctl(2), semop(2), ftok(3), capabilities(7), sem_overview(7), sysvipc(7)

Angielska wersja tej strony pochodzi z wydania 5.10 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/.

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 manpages-pl-list@lists.sourceforge.net.

11 kwietnia 2020 r. Linux