Provided by: manpages-ja-dev_0.5.0.0.20221215+dfsg-1_all bug

名前

       semop, semtimedop - System V セマフォの操作

書式

       #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);

   glibc 向けの機能検査マクロの要件 (feature_test_macros(7)  参照):

       semtimedop(): _GNU_SOURCE

説明

       System V セマフォ集合 (semaphore set) のメンバーの各セマフォは 以下の関連情報を持っている:

           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

       semop()  は semid で指定されたセマフォ集合の選択されたセマフォに対して操作を行う。 sopsnsops 個の要素の配列を指し、配列の各要素は個々のセマフォに対する操作を示す構造体である。そ
       の型は struct sembuf で、次のメンバを持つ:

           unsigned short sem_num;  /* セマフォ番号 */
           short          sem_op;   /* セマフォ操作 */
           short          sem_flg;  /* 操作フラグ */

       sem_flg には IPC_NOWAITSEM_UNDO が設定できる。 SEM_UNDO が指定された操作は、そのプロセ
       スが終了した時に自動的に取り消される。

       sops に含まれる操作の集合は、 配列の順序 で、 アトミックに 実行される。 すなわち、全ての操
       作が完全に実行されるか、全く実行されないかの どちらかとなる。 全ての操作が直ちに実行できな
       い場合のこのシステムコールの振る舞いは 個々の操作の sem_flg フィールドに IPC_NOWAIT が存在
       するかによって決まり、後述のようになる。

       それぞれの操作はセマフォ集合の  sem_num番目 のセマフォに対して実行される。セマフォ集合の最
       初のセマフォには 番号 0 が振られる。 そして操作は三種類あり、 sem_op の値で区別される。

       sem_op  が正の整数の場合、その値をセマフォの値  (semval)  に加算する。  さらに、この操作で
       SEM_UNDO  が指定されていた場合は、 システムはこのセマフォのの調整値 (semadj) から値 sem_op
       を減算する。 この操作は必ず実行でき、 スレッドの停止は起こらない。  呼び出し元プロセスは対
       象のセマフォ集合を変更する許可がなければならない。

       sem_op  が 0 の場合、「ゼロまで待つ」操作である。この場合、プロセスは そのセマフォ集合に対
       する読み込み許可がなければならない。 semval が 0 ならば、操作は直ちに行われる。 semval  が
       0  でない場合、  sem_flgIPC_NOWAIT が指定されていれば、 semop()  は失敗し、 errnoEAGAIN が設定される (このとき sops に対する操作は全く実行されない)。 sem_flgIPC_NOWAIT
       が指定されていない場合、 semzcnt (セマフォ値が 0 になるのを待っているスレッドの数) を 1 増
       加させて、 以下のいずれかが起こるまでスレッドを停止 (sleep) する。

       • semval が 0 になった: このとき semzcnt の値は 1 減算される。

       • セマフォ集合が削除された: このとき semop()  は失敗し、 errnoEIDRM が設定される。

       • 呼び出し元スレッドがシグナルを捕獲した: このとき semzcnt の値は 1 減算され、 semop()  は
         失敗し errnoEINTR が設定される。

       sem_op  が  0  未満の場合、プロセスにはそのセマフォ集合を変更する許可がなければ ならない。
       semvalsem_op の絶対値以上の場合は、操作は直ちに実行される: semval から sem_op の絶対値
       を減算し、さらに、この操作に     SEM_UNDO     が指定されている場合は、このセマフォの調整値
       (semadj) に sem_op の絶対値を加算する。 semvalsem_op の絶対値より小さく、  sem_flgIPC_NOWAIT が指定された場合は、 semop()  は失敗し、 errnoEAGAIN が設定される (このとき
       sops の操作は全く実行されない)。 semvalsem_op の絶対値より小さく、 IPC_WAIT が指定され
       ていない場合は、  semncnt (このセマフォの値が増加するのを待っているスレッド数のカウンター)
       を 1 増加させて、以下のいずれかが起こるまでスレッドを停止 (sleep) する。

       • semvalsem_op の絶対値以上になった。この時点で、操作は上述の通り実行される。

       • セマフォ集合がシステムから削除された: このとき semop()  は失敗し errnoEIDRM が設定さ
         れる。

       • 呼び出したスレッドがシグナルを捕獲した: このとき semncnt が 1 減算され、 semop()  は失敗
         し errnoEINTR が設定される。

       操作が成功した場合、 sops が指す配列によって操作対象となった各セマフォの sempid メンバーに
       は呼び出し元のプロセス ID が設定される。さらに sem_otime に現在時刻が設定される。

   semtimedop()
       semtimedop()   関数の振る舞いは  semop()  と全く同じだが、呼び出し元  スレッドが停止する場
       合、停止期間の上限が timeout 引数の指す timespec  構造体で指定された時間となる点だけが異な
       る  (この停止期間は システムクロックの粒度に切り上げられ、カーネルのスケジューリング遅延に
       より、この停止期間は少しだけ長くなる可能性がある)。       指定した制限時間に達した場合は、
       semtimedop()  は失敗し、  errnoEAGAIN が設定される (このとき sops の操作は実行されな
       い)。 timeout 引数が NULL の場合、 semtimedop() 関数の振る舞いは semop()  関数と全く同じに
       なる。

       semtimedop()  がシグナルにより割り込まれた場合、呼び出しはエラー  EINTR で失敗し、 timeout
       の内容は変更されないままとなる点に注意すること。

返り値

       成功した場合、 semop()  と semtimedop()  は 0 を返す。そうでなければ -1 を返し、  エラーを
       示す errno を設定する。

エラー

       失敗した場合、 errno に以下のどれかが設定される:

       E2BIG  nsops  引数が SEMOPM より大きい。 SEMOPM は一回のシステムコールで許される操作の最大
              個数である。

       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 操作を直ちに処理することができず、かつ  sem_flgIPC_NOWAIT  が指定されているか
              timeout で指定された制限時間が経過した。

       EFAULT 引数 sopstimeout が指しているアドレスにアクセスできない。

       EFBIG  ある操作で、 sem_num の値が 0 未満か、集合内のセマフォの数以上である。

       EIDRM  セマフォ集合が削除された。

       EINTR  このシステムコールで停止している時にスレッドがシグナルを捕獲した。 single(7) 参照。

       EINVAL セマフォ集合が存在しないか、 semid が 0 未満であるか、 nsops が正の数でない。

       ENOMEM ある操作で sem_flgSEM_UNDO が指定されたが、システムにアンドゥ構造体に割り当てる
              十分なメモリーがない。

       ERANGE ある操作で sem_op+semvalSEMVMX より大きい。 SEMVMXsemval の最大値で、その値
              は実装依存である。

バージョン

       semtimedop()   は  Linux  2.5.52 で初めて登場し、 それからカーネル 2.4.22 にも移植された。
       semtimedop()  の glibc でのサポートはバージョン 2.3.3 で初めて登場した。

準拠

       POSIX.1-2001, POSIX.1-2008, SVr4.

注意

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

       あるプロセスの  sem_undo  構造体は   fork(2)    で生成された子プロセスには継承されないが、
       execve(2) システムコールの場合は継承される。

       semop()   はシグナルハンドラーによって中断された後に、  決して自動的に再開することはない。
       たとえシグナルハンドラーの設定時に SA_RESTART フラグがセットされていても再開することはない

       セマフォの調整値 (semadj) は、プロセス毎のセマフォ毎の整数で、 SEM_UNDO フラグを指定して行
       われた、セマフォに対するすべての操作の合計値を反転したものである。  各プロセスは semadj の
       値のリストを保持する —  リストのそれぞれの値は  SEM_UNDO  を使って操作が行われた個々のセマ
       フォに対応する。 プロセスが終了する際、 セマフォ毎の semadj の各々の値が対応するセマフォに
       加算される。  これにより、そのプロセスがそのセマフォに対して行った操作の影響が取り消される
       (ただし、下記の「バグ」を参照)。  semctl(2) の SETVALSETALL を使ってセマフォの値が直接
       設定された場合、  すべてのプロセスの対応する  semadj  の値がクリアされる。   clone(2)   の
       CLONE_SYSVSEM フラグを使うと、 複数のプロセスがひとつの semadj リストを共有できる。 詳細は
       clone(2) を参照。

       あるセマフォの  semval,  sempid,  semzcnt,   semnct   の値はいずれも、適切な操作を指定して
       semctl(2)  を呼び出すことで取得できる。

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

       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 semval が取り得る最大値: 実装依存 (32767)。

       以下の値に関しては実装依存の制限はない。 終了時の調整 (adjust on exit) の最大値 (SEMAEM)、
       システム全体のアンドゥ構造体の最大数 (SEMMNU)、 プロセスあたりのアンドゥ構造体の最大数。

バグ

       プロセスが終了する際、プロセスに対応する semadj の集合を使って、 SEM_UNDO フラグ付きで実行
       された全てのセマフォ操作の影響を取り消す。 これによりある問題が発生する:  これらのセマフォ
       の調整を行っていると、  中にはセマフォの値が 0 未満の値にしようとする場合が出てくる。 この
       ような場合、どのように実装するべきか? ひとつの考えられる手法は、全てのセマフォ調整が実行さ
       れるまで 停止することである。しかし、この方法ではプロセスの終了が 長時間にわたって停止され
       ることがあるので望ましくない。 しかもどれくらい長時間になるかは分からない。 別の選択肢とし
       て、このようなセマフォ調整を完全に無視してしまう方法がある       (これはセマフォ操作として
       IPC_NOWAIT が指定するのと少し似ている)。 Linux は第三の手法を採用している:  セマフォの値を
       出来るだけ (つまり 0 まで) 減少させて、プロセスの終了を直ちに続行できるようにしている。

       カーネル  2.6.x (x <= 10) には、ある状況においてセマフォ値が 0 になるのを 待っているスレッ
       ドが、セマフォ値が実際に 0 になったときに起床 (wake up)   されない、というバグがある。この
       バグはカーネル 2.6.11 で修正されている。

       以下の部分的なコードは、  セマフォ 0 の値が 0 になるのを待ってから、 セマフォの値を 1 加算
       する処理を、 semop() を使ってアトミック (atomically) に行う。

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

関連項目

       clone(2),   semctl(2),   semget(2),   sigaction(2),   capabilities(7),    sem_overview(7),
       sysvipc(7), time(7)

この文書について

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