Provided by: manpages-ja-dev_0.5.0.0.20180315+dfsg-1_all ![bug](/img/bug.png)
![bug](/img/bug.png)
名前
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/ に書かれている。