SEMGET(2)

名前
semget - System 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.

key の値が IPC_PRIVATE の場合、もしくは semflg に IPC_CREAT が指定されていて、 key に対応するセマフォ集合が存在しない場合、 nsems 個のセマフォからなる新しい集合が作成される。

semflg に IPC_CREAT と IPC_EXCL の両方が指定された場合、 key に対応するセマフォ集合が既に存在すると、 semget() は失敗し、 errno に EEXIST が設定される (これは open(2) に O_CREAT | O_EXCL が指定された場合の動作と同じである)。

セマフォ集合作成時に、引数 semflg の下位 9 ビットは、そのセマフォ集合の (所有者 (owner)、グループ (group)、 他人 (others) に対する) アクセス許可の定義として使用される。 これらのビットは open(2) の引数 mode と同じ形式で同じ意味である (但し、実行 (execute) 許可はセマフォでは意味を持たず、 書き込み (write) 許可はセマフォ値の変更 (alter) 許可として機能する)。

新規のセマフォ集合を作成する際、 semget() はセマフォ集合の情報を保持するデータ構造体 semid_ds を次のように初期化する (semid_ds については semctl(2) を参照):

•   sem_perm.cuid と sem_perm.uid に、呼び出し元のプロセスの実効 (effective) ユーザー ID を設定する。

•   sem_perm.cgid と sem_perm.gid に、呼び出し元のプロセスの実効 (effective) グループ ID を設定する。

•   sem_perm.mode の下位 9 ビットに semflg の下位 9 ビットを設定する。

•   sem_nsems に nsems の値を設定する。

•   sem_otime に 0 を設定する。

•   sem_ctime に現在の時刻を設定する。

セマフォ集合の作成を行わない場合は、引数 nsems に (don't care を意味する) 0 を指定してもよい。 そうでない場合は、 nsems は 0 より大きい値でなければならず、セマフォ集合あたりのセマフォの最大数 (SEMMSL) 以下でなければならない。

セマフォ集合が既に存在した場合は、アクセス許可の検査が行われる。

返り値
成功した場合、セマフォ集合の識別子 (非負の整数) が返り値となる。 失敗した場合は -1 が返され、 errno にエラーを示す値が設定される。

エラー
失敗した場合は errno には以下の値のどれかが設定される:

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
    semflg に IPC_CREAT と IPC_EXCL が指定されたが、 key に対応するセマフォ集合はすでに存在する。

EINVAL
    nsems が 0 より小さいか、 セマフォ集合あたりのセマフォの最大数 (SEMMSL) より大きい。

EINVAL
    key に対応するセマフォ集合が既に存在するが、 nsems がその集合のセマフォ数よりも大きい。

ENOENT
    key に対応するセマフォ集合が存在せず、 semflg に IPC_CREAT が指定されてもいない。

ENOMEM
    セマフォ集合を作成しようとしたが、新しいデータ構造体を 作成するのに十分なメモリーがシステムに存在しない。

ENOSPC
    セマフォ集合を作成しようとすると、システムのセマフォ集合の 最大数 (SEMMNI) か、システム全体のセマフォの最大数 (SEMMNS) のいずれかを超えてしまう。

準拠
SVr4, POSIX.1-2001.

注意
Linux や POSIX の全てのバージョンでは、 <sys/types.h> と <sys/ipc.h> のインクルードは必要ない。しかしながら、いくつかの古い実装ではこれらのヘッダーファイルのインクルードが必要であり、 SVID でもこれらのインクルードをするように記載されている。このような古いシステムへの移植性を意図したアプリケーションではこれらのファイルをインクルードする必要があるかもしれない。

IPC_PRIVATE はフラグフィールドに指定するものではなく、 key_t 型である。 この特別な値が key に指定されると、 semget() semflg の下位 9 ビット以外は全て無視し、 (成功した場合は) 新しいセマフォ集合を作成する。

  セマフォの初期化
新しく作成されたセマフォ集合の各セマフォの値は不定である。 (この点は POSIX.1-2001 と POSIX.1-2008 に明記されている。ただし、POSIX.1-2008 では POSIX の将来のバージョンではセマフォを 0 に初期化するように実装に要求する可能性が注記されている。) Linux は他の多くの実装と同様にセマフォ値を 0 に初期化するが、 移植性を考慮したアプリケーションではこの動作を前提にすべきではない。 アプリケーションは明示的にセマフォを希望の値で初期化すべきである。

semctl(2) の SETVAL か SETALL 操作を使って初期化することができる。 複数箇所からセマフォ集合の操作が行われる場面では、 誰が最初に集合を初期化すればよいか分からない。 この状況を避けるには、 semctl(2) の IPC_STAT 操作で取得できるセマフォのデータ構造体の sem_otime が 0 以外になっているかをチェックすればよい。

  セマフォの上限
セマフォ集合のリソースに関する上限のうち、 semget() に影響を及ぼすものを以下に挙げる:

SEMMNI
    System-wide limit on the number of semaphore sets. On Linux systems before version 3.19, the default value for this limit was 128. Since Linux 3.19, the default value is 32,000. On Linux, this limit can be read and modified via the fourth field of /proc/sys/kernel/sem.

SEMMSL
    Maximum number of semaphores per semaphore ID. On Linux systems before version 3.19, the default value for this limit was 250. Since Linux 3.19, the default value is 32,000. On Linux, this limit can be read and modified via the first field of /proc/sys/kernel/sem.

SEMMNS
    システム全体のセマフォ数の上限値: 方針依存 (Linux では、この上限値は /proc/sys/kernel/sem の第 2 フィールドであり、読み出しも変更もできる)。 システム全体のセマフォ数には、 SEMMSL と SEMMNI の積という上限もある。

バグ
IPC_PRIVATE という名前を選んだのはおそらく失敗であろう。 IPC_NEW の方がより明確にその機能を表しているだろう。

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

この文書について
この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。