WAIT
Section: Linux Programmer's Manual (2)
Updated: 2007-07-26
Index
JM Home Page
roff page
名前
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 向けの機能検査マクロの要件
(feature_test_macros(7)
参照):
waitid():
_SVID_SOURCE || _XOPEN_SOURCE
説明
これらのシステムコールはいずれも、呼び出し元プロセスの子プロセスの
状態変化を待ち、状態が変化したその子プロセスの情報を取得するのに
使用される。
状態変化とは以下のいずれかである:
子プロセスの終了、シグナルによる子プロセスの停止、
シグナルによる子プロセスの再開。
子プロセスが終了した場合は、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 専用オプションについては後述する)
WUNTRACED
と
WCONTINUED
の両オプションが有効となるのは、
SIGCHLD
シグナルに対して
SA_NOCLDSTOP
フラグが設定されていない場合だけである
(sigaction(2)
を参照)。
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_STOPPED
(シグナルにより子プロセスが停止した);
CLD_CONTINUED
(SIGCONT
により子プロセスが再開された)。
WNOHANG
が
options
に指定されていて、
waitable 状態の子プロセスがなかった場合には、
waitid()
はすぐに 0 を返す。このとき、
infop
が指す
siginfo_t
構造体の内容は不定である。
この場合を waitable 状態の子プロセスがあった場合と区別するには、
waitid()
を呼び出す前に
si_pid
を 0 にしておき、コールが復帰した後でこのフィールドが 0 以外の値かどうか
をチェックすればよい。
返り値
wait():
成功すると、終了した子プロセスのプロセスID を返す。
エラーの場合 -1 を返す。
waitpid():
成功すると、状態が変化した子プロセスのプロセスID を返す。
エラーの場合 -1 を返す。
WNOHANG
が指定されていて、
pid
で指示された子プロセスで状態変化が起こっていなかった場合は、
0 を返す。
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
を受信した。
- EINVAL
-
options
引き数が不正である。
準拠
SVr4, 4.3BSD, POSIX.1-2001.
注意
終了したが、wait されていない子プロセスは「ゾンビ」になる。
後で親プロセスが wait を実行して子プロセスについての情報を取得できるように、
カーネルはゾンビプロセスについて最小限の情報 (PID、終了ステータス、
リソース使用状況) を保持する。
ゾンビプロセスは、 wait によってシステムから削除されない限り、
カーネルのプロセステーブルの 1 エントリを消費する。このプロセステーブルが
一杯になると、新たにプロセスを作ることができなくなる。
親プロセスが終了すると、その親プロセスの「ゾンビ」の
子プロセスは (もしあれば)
init(8)
の養子となる。
init(8)
は wait を自動的に実行し、ゾンビを削除する。
POSIX.1-2001 では以下のように規定されている。
SIGCHLD
の動作が
SIG_IGN
に設定されたか、
SIGCHLD
に対して
SA_NOCLDWAIT
フラグが設定された場合
(sigaction(2)
参照)、終了した子プロセスはゾンビにはならず、
wait()
や
waitpid()
の呼び出しは全ての子プロセスが終了するまで停止し、
子プロセスが全部終了した後
errno
に
ECHILD
を設定して失敗する。
(もともとの POSIX 標準は
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 より前ではデフォルトであった。
例
以下のプログラムは、
fork(2)
と
waitpid(2)
の使用方法の例を示している。
このプログラムでは子プロセスを生成する。
コマンドライン引き数が指定されなかったときは、
子プロセスは
pause(2)
を使ってその実行を一時停止し、ユーザがその子プロセスに
シグナルを送信できるようにする。
コマンドライン引き数が指定された場合は、
子プロセスは直ちに終了し、
コマンドラインで指定された整数を終了ステータスとして使用する。
親プロセスは、
waitpid(2)
を使って子プロセスを監視し、
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)
Index
- 名前
-
- 書式
-
- 説明
-
- wait() と waitpid()
-
- waitid()
-
- 返り値
-
- エラー
-
- 準拠
-
- 注意
-
- Linux での注意
-
- 例
-
- 関連項目
-
This document was created by
man2html,
using the manual pages.
Time: 04:32:11 GMT, November 19, 2007