web-dev-qa-db-ja.com

waitpidシステムコールが子プロセスでのみ使用できるのはなぜですか?

マニュアルページwait(2)には、指定したプロセスが呼び出しプロセスの子でない場合、waitpidシステムコールがECHILDエラーを返すと記載されています。どうしてこれなの?子以外のプロセスで待機すると、何らかのセキュリティ問題が発生しますか?非子プロセスでの待機の実装が困難または不可能である技術的な理由はありますか?

6
Tanner Swett

waitpidの仕組みが原因です。 POSIXシステムでは、子プロセスの1つが停止すると、シグナル(SIGCHLD)が親プロセスに配信されます。高レベルでは、指定されたプロセス(またはプロセスの1つ)にSIGCHLDシグナルが配信されるまで、waitpidが実行していることはすべてブロックされます。 SIGCHLDシグナルはプロセスに配信されないため、任意のプロセスを待つことはできません。

13
godlygeek

godlygeekの答えはシステムがどのように機能するかを理解するのに役立ちますが、必然的に続く後続の質問は次のとおりです。

プロセスがなくなったかどうかを判断するにはどうすればよいですか?

別のプロセスグループまたはセッションのプロセスを待機する正しい方法は、kill()を使用することです。明らかに、それは直感的ではない答えです。 SIGCHILDシグナルはプロセスに渡されず、ステータスコードも取得できないため、waitファミリーの関数を使用することはできません。ただし、kill()は、送信するシグナルに0を渡すことにより、特定のプロセスが終了したことを通知できます。これは、シグナルをプロセスに送信できるかどうかを確認するだけです。 kill()の戻り値は複雑ですが、次のように要約できます。値0はプロセスが生きていてプロセスからのシグナルを受け入れることを意味し、値-1およびerrno EPERMはプロセスが生きていますが、プロセスからのシグナルを受け入れていません。

1秒に1回チェックして任意のプロセスがなくなったかどうかを確認するサンプルCコード:

_int res = kill(pid, 0);
while (res == 0 || (res < 0 && errno == EPERM))
{
    sleep(1);

    res = kill(pid, 0);
}
_

同様に、killコマンドを試すことができます。

_kill -0 <pid>
_

それはpidと0をkill()に渡します。一部のシェルにはkillが組み込まれているため、新しいプロセスを開始するよりもはるかに効率的です(例:ps)。

4
CubicleSoft