SEMGET(2) | Linux Programmer's Manual | 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) を参照):
セマフォ集合の作成を行わない場合は、引数 nsems に (don't care を意味する) 0 を指定してもよい。 そうでない場合は、 nsems は 0 より大きい値でなければならず、セマフォ集合あたりのセマフォの最大数 (SEMMSL) 以下でなければならない。
セマフォ集合が既に存在した場合は、アクセス許可の検査が行われる。
成功した場合、セマフォ集合の識別子 (非負の整数) が返り値となる。 失敗した場合は -1 が返され、 errno にエラーを示す値が設定される。
失敗した場合は errno には以下の値のどれかが設定される:
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() に影響を及ぼすものを以下に挙げる:
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/ に書かれている。
2020-04-11 | Linux |