Provided by: manpages-ja-dev_0.5.0.0.20210215+dfsg-1_all
名前
wait, waitpid, waitid - プロセスの状態変化を待つ
書式
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); /* これは glibc と POSIX のインターフェイスである。 生のシステムコールについての情報は「注意」の節を参照。 */ glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照): waitid(): _SVID_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED || /* glibc 2.12 以降: */ _POSIX_C_SOURCE >= 200809L
説明
これらのシステムコールはいずれも、呼び出し元プロセスの子プロセスの 状態変化を待ち、状態が 変化したその子プロセスの情報を取得するのに 使用される。 状態変化とは以下のいずれかである: 子プロセスの終了、シグナルによる子プロセスの停止、 シグナルによる子プロセスの再開。 子プロ セスが終了した場合は、wait を実行することで、 システムがその子プロセスに関連するリソースを 解放できるようになる。 wait が実行されなかった場合には、終了した子プロセスは 「ゾンビ」状 態で残り続ける (下記の注意の章を参照のこと)。 子プロセスの状態変化がすでに発生していた場合、これらのコールは すぐに復帰する。それ以外の 場合は、子プロセスの状態変化が起こるか、 シグナルハンドラーによりシステムコールが中断され るまで、 停止 (block) する (後者は、 sigaction(2) の SA_RESTART フラグによりシステムコー ルが自動的に再スタートするようになっていない 場合の動作である)。 以下の説明では、状態変化 が起こったがこれらのシステムコールのいずれかに よって待たれていない子プロセスを waitable (待ち可能) と呼ぶ。 wait() と waitpid() wait() システムコールは、子プロセスのいずれかが終了するまで 呼び出し元のプロセスの実行を 一時停止する。 呼び出し wait(&status) は以下と等価である: waitpid(-1, &status, 0); waitpid() システムコールは、 pid 引き数で指定した子プロセスの状態変化が起こるまで、 呼び 出し元のプロセスの実行を一時停止する。デフォルトでは、 waitpid() は子プロセスの終了だけを 待つが、この動作は options 引き数により変更可能である。 pid に指定できる値は以下の通り: < -1 プロセスグループID が pid の絶対値に等しい子プロセスのいずれかが終了するまでを待 つ。 -1 子プロセスのどれかが終了するまで待つ。 0 プロセスグループID が呼び出したプロセスのものと等しい 子プロセスを待つ。 > 0 プロセスID が pid に等しい子プロセスを待つ。 options の値は次の定数の 0 個以上の論理和である: WNOHANG 状態変化が起こった子プロセスがない場合にすぐに復帰する。 WUNTRACED 子プロセスが停止した場合にも復帰する (子プロセスが ptrace(2) でトレースされて いる場合は除く)。 このオプションが指定されていない場合でも、停止したプロセスが 「トレース (traced)」されていれば、子プロセスの状態が報告される。 WCONTINUED (Linux 2.6.10 以降) 停止した子プロセスが SIGCONT の配送により再開した場合にも復帰する。 (Linux 専用オプションについては後述する) status が NULL でなければ、 wait() や waitpid() は status で指す int に状態情報を格納す る。 この整数は以下のマクロを使って検査できる。 (これらのマクロの引き数には、 wait() や waitpid() が書き込んだ整数そのものを指定する。ポインターではない!) WIFEXITED(status) 子プロセスが正常に終了した場合に真を返す。 「正常に」とは、 exit(3) か _exit(2) が呼び出された場合、もしくは main() から復帰した場合である。 WEXITSTATUS(status) 子プロセスの終了ステータスを返す。 終了ステータスは status 引き数の下位 8ビットで構 成されており、 exit(3) や _exit(2) の呼び出し時に渡された値、もしくは main() の return 文の 引き数として指定された値である。 このマクロを使用するのは WIFEXITED が 真を返した場合だけにすべきである。 WIFSIGNALED(status) 子プロセスがシグナルにより終了した場合に真を返す。 WTERMSIG(status) 子プロセス終了の原因となったシグナルの番号を返す。 このマクロを使用するのは WIFSIGNALED が真を返した場合だけにすべきである。 WCOREDUMP(status) 子プロセスがコアダンプを生成した場合に真を返す。 このマクロを使用するのは WIFSIGNALED が真を返した場合だけにすべきである。 このマクロは POSIX.1-2001 では規定 されておらず、 (AIX, SunOS などの) いくつかの UNIX の実装では利用できない。 必ず #ifdef WCOREDUMP ... #endif で括って使用すること。 WIFSTOPPED(status) 子プロセスがシグナルの配送により停止した場合に真を返す。 これが真になるのは、システ ムコールが WUNTRACED を指定して呼び出された場合か、子プロセスがトレースされている場 合 (ptrace(2) 参照) だけである。 WSTOPSIG(status) 子プロセスを停止させたシグナルの番号を返す。 このマクロを使用するのは WIFSTOPPED が 0 以外を返した場合だけにすべきである。 WIFCONTINUED(status) (Linux 2.6.10 以降) 子プロセスが SIGCONT の配送により再開した場合に真を返す。 waitid() waitid() システムコール (Linux 2.6.9 以降で利用可能) を使うと、 子プロセスのどの状態変化 を待つかについてより細かな制御ができる。 引き数 idtype と id でどの子プロセスを待つかを選択する: idtype == P_PID プロセスID が id と一致する子プロセスを待つ。 idtype == P_PGID プロセスグループID が id と一致する子プロセスを待つ。 idtype == P_ALL 子プロセス全部を対象に待つ。 id は無視される。 子プロセスのどの状態変化を待つかは以下のフラグで指定する (options には 1個以上のフラグの論 理和をとって指定する): WEXITED 子プロセスの終了を待つ。 WSTOPPED 子プロセスがシグナルの配送により停止するのを待つ。 WCONTINUED (停止していた) 子プロセスが SIGCONT が配送されて再開するのを待つ。 さらに以下のフラグを論理和の形で options に指定できる: WNOHANG waitpid() と同様。 WNOWAIT waitable 状態のプロセスをそのままにする。この後で wait コールを 使って、同じ子 プロセスの状態情報をもう一度取得することができる。 成功した場合には、 waitid() は infop が指す siginfo_t 構造体の以下のフィールドを設定する: si_pid 子プロセスのプロセスID。 si_uid 子プロセスの実ユーザーID (このフィールドは他のほとんどの実装では設定されな い)。 si_signo 常に SIGCHLD が設定される。 si_status _exit(2) (か exit(3)) に指定された子プロセスの終了ステータス、もしくは 子プ ロセスの終了、停止、再開の原因となったシグナルが設定される。 このフィールドを どう解釈するかは、 si_code フィールドを参照して決めることができる。 si_code 以下のいずれかが設定される: CLD_EXITED (子プロセスが _exit(2) を呼び出した); CLD_KILLED (シグナルにより子プロセスが kill された); CLD_DUMPED (シグナルによ り子プロセスが kill され、コアダンプが行われた); CLD_STOPPED (シグナルにより子 プロセスが停止した); CLD_TRAPPED (トレースされていた子プロセスがトラップを受信 した); CLD_CONTINUED (SIGCONT により子プロセスが再開された)。 WNOHANG が options に指定されていて、 waitable 状態の子プロセスがなかった場合には、 waitid() はすぐに 0 を返す。このとき、 infop が指す siginfo_t 構造体の内容は不定である。 この場合を waitable 状態の子プロセスがあった場合と区別するには、 waitid() を呼び出す前に si_pid を 0 にしておき、コールが復帰した後でこのフィールドが 0 以外の値かどうか をチェック すればよい。
返り値
wait(): 成功すると、終了した子プロセスのプロセスID を返す。 エラーの場合 -1 を返す。 waitpid(): 成功すると、状態が変化した子プロセスのプロセスID を返す。 WNOHANG が指定されて いて、 pid で指示された子プロセスが一つ以上存在するが、どの子プロセスでも 状態変化が起こっ ていなかった場合は、 0 を返す。 エラーの場合 -1 を返す。 waitid(): 成功すると 0 を返す。 WNOHANG が指定されていて、 pid で指示された子プロセスで状 態変化が起こっていなかった場合にも 0 を返す。 エラーの場合 -1 を返す。 エラーの場合、これらのシステムコールはいずれも errno に適切な値を 設定する。
エラー
ECHILD (wait() の場合) 呼び出し元プロセスには、wait を行っていない子プロセスはない。 ECHILD (waitpid() か waitid() の場合) pid (waitpid()) か idtype と id (waitid()) で指 定したプロセスが存在しないか、呼び出し元プロセスの子プロセスでない (SIGCHLD の動作 に SIG_IGN を設定した場合には、自分自身の子プロセスでも起こりうる。 スレッドに関し ては「Linux での注意」の節も参照すること)。 EINTR WNOHANG が設定されておらず、禁止 (block) されていないシグナルや SIGCHLD を受信し た。 signal(7) 参照。 EINVAL options 引き数が不正である。
準拠
SVr4, 4.3BSD, POSIX.1-2001.
注意
終了したが、wait されていない子プロセスは「ゾンビ」になる。 後で親プロセスが wait を実行し て子プロセスについての情報を取得できるように、 カーネルはゾンビプロセスについて最小限の情 報 (PID、終了ステータス、 リソース使用状況) を保持する。 ゾンビプロセスは、 wait によって システムから削除されない限り、 カーネルのプロセステーブルの 1 エントリーを消費する。このプ ロセステーブルが 一杯になると、新たにプロセスを作ることができなくなる。 親プロセスが終了す ると、その親プロセスの「ゾンビ」の 子プロセスは (もしあれば) init(1) の養子となる。 init(1) は wait を自動的に実行し、ゾンビを削除する。 POSIX.1-2001 では以下のように規定されている。 SIGCHLD の動作が SIG_IGN に設定されたか、 SIGCHLD に対して SA_NOCLDWAIT フラグが設定された場合 (sigaction(2) 参照)、終了した子プロ セスはゾンビにはならず、 wait() や waitpid() の呼び出しは全ての子プロセスが終了するまで 停止し、 子プロセスが全部終了した後 errno に ECHILD を設定して失敗する。 (もともとの POSIX 標準は SIGCHLD に SIG_IGN を設定した場合の振る舞いを未規定のままにしている。 SIGCHLD のデ フォルトの動作が「無視」であるにもかかわらず、 SIGCHLD の動作として SIG_IGN を明示的に設定 した場合にはゾンビプロセスの子プロセスの扱いが 異なる点に注意すること。) Linux 2.6 はこの仕様に準拠している。 しかし、Linux 2.4 (とそれ以前のバージョン) はそうでは ない: SIGCHLD が無視される状態で wait() または waitpid() が呼び出された場合、 SIGCHLD が 無視されていないかのように振る舞う。 つまり、呼び出しによって次の子プロセスの終了までブ ロックされ、 終了した子プロセスの PID と状態が返される。 Linux での注意 Linux カーネルでは、カーネルによってスケジュールされるスレッドは プロセスと明確に区別でき る構成要素ではない。スレッドは Linux 固有の clone(2) システムコールを使用して生成されるプ ロセスに過ぎない。 移植性のある pthread_create(3) コールのような他のルーチンは clone(2) を使用して実装されている; これらでは waitid() を使うことはできない。 Linux 2.4 より前で は、スレッドは単に特殊なプロセスであったので、 例え同じスレッドグループであっても、 あるス レッドが別のスレッドの子プロセスが終了するのを待つことは出来なかった。 しかし、POSIX では このような機能を規定しており、 Linux 2.4 以降では、あるスレッドが同じスレッドグループの他 のスレッドの 子プロセスが終了するのを待つことができるようになった。 そして将来はこれがデ フォルトの動作になるであろう。 clone(2) を用いて作られた子プロセスには、以下の Linux 固有の options が使用できる。 __WCLONE "clone" な子プロセスだけを待つ。 指定されなかった場合は非 "clone" な子プロセスだけ を待つ ("clone" な子プロセスは、終了時に親プロセスへ全くシグナルを送らないか、 SIGCHLD 以外のシグナルを送る)。 このオプションは __WALL も指定された場合は無視され る。 __WALL (Linux 2.4 以降) "clone" であるかないかに関わらず、 全ての子プロセスを待つ。 __WNOTHREAD (Linux 2.4 以降) 同じスレッドグループの他のスレッドの子プロセスは待たない。 Linux 2.4 より前ではデ フォルトであった。 C ライブラリとカーネル ABI の違い 生の waitid() システムコールは struct rusage * 型の第 5 引数を取る。 この引数が NULL 以外 の場合、 この引数が子プロセスのリソース使用状況を返すのに使用される。 これは wait4(2) と同 じ方法である。 詳細は getrusage(2) を参照。
バグ
POSIX.1-2008 によると、 waitid() を呼び出すアプリケーションは、 infop が siginfo_t 構造体 を指していること (つまり infop が NULL でないポインターであること) を保証しなければならな い。 Linux では、 infop が NULL の場合、 waitid() は成功し、wait している子プロセスのプロ セス ID を返す。 アプリケーションは、この食い違った、非標準で、不必要な機能に依存しないよ うにすべきである。
例
以下のプログラムは、 fork(2) と waitpid() の使用方法の例を示している。 このプログラムで は子プロセスを生成する。 コマンドライン引き数が指定されなかったときは、 子プロセスは pause(2) を使ってその実行を一時停止し、ユーザーがその子プロセスに シグナルを送信できるよ うにする。 コマンドライン引き数が指定された場合は、 子プロセスは直ちに終了し、 コマンドラ インで指定された整数を終了ステータスとして使用する。 親プロセスは、 waitpid() を使って子 プロセスを監視し、 wait のステータス値を上記の W*() マクロを使って解析するという ループを 実行する。 以下のシェルのセッションはこのプログラムの使用例を示したものである。 $ ./a.out & Child PID is 32360 [1] 32359 $ kill -STOP 32360 stopped by signal 19 $ kill -CONT 32360 continued $ kill -TERM 32360 killed by signal 15 [1]+ Done ./a.out $ プログラムのソース #include <sys/wait.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> int main(int argc, char *argv[]) { pid_t cpid, w; int status; cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { /* Code executed by child */ printf("Child PID is %ld\n", (long) getpid()); if (argc == 1) pause(); /* Wait for signals */ _exit(atoi(argv[1])); } else { /* Code executed by parent */ do { w = waitpid(cpid, &status, WUNTRACED | WCONTINUED); if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); } if (WIFEXITED(status)) { printf("exited, status=%d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("killed by signal %d\n", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { printf("stopped by signal %d\n", WSTOPSIG(status)); } else if (WIFCONTINUED(status)) { printf("continued\n"); } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit(EXIT_SUCCESS); } }
関連項目
_exit(2), clone(2), fork(2), kill(2), ptrace(2), sigaction(2), signal(2), wait4(2), pthread_create(3), credentials(7), signal(7)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部である。 プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。