execve を使用して他のプロセスを生成するプログラムがあります。
s32 ret = execve( argv[0], argv.data(), (char* const*) req.posixEnv() );
その後、ループの後半で、waitpid を呼び出して、プロセスがいつ終了するかを監視します。
while( 1 )
{
readOutputFromChildProcess( pid );
int status;
s32 retPid = waitpid( pid, &status, WNOHANG );
if ( retPid < 0 )
{
if ( errno == ECHILD )
{
// I don't expect to ever get this error - but I do. why?
printf( "Process gone before previous wait. Return status lost.\n" );
assert(0);
} else {
// other real errors handled here.
handleError();
break;
}
}
if ( retPid == 0 )
{
waitSomeTime();
continue;
}
processValidResults( status );
break;
}
コードを大幅に簡素化しました。私の理解では、プロセスを生成すると、呼び出し元が「waitpid」を呼び出してゼロより大きい戻り値と有効な戻りステータスを取得するまで、プロセス テーブル エントリが残ります。
しかし、場合によっては、プロセスが勝手に終了し、waitpid を呼び出すと -1 が返され、ECHILD エラーが発生することがあります。
ECHILD は、waitpid を呼び出した時点で、その ID を持つプロセスがプロセス テーブルに存在しなかったことを意味します。したがって、私のpidが無効であったか、慎重に確認しましたが、有効です。
または - このプロセスが終了した後に既に waitpid が呼び出されています - この場合、このプロセスからリターン コードを取得できません。
プログラムはマルチスレッドです。また、waitpid の呼び出しが早すぎないことも確認しました。数回の「待機」後に発生します。
waitpid を呼び出さずにプロセス テーブル エントリをクリーンアップする他の方法はありますか? 必ずリターン コードを取得するにはどうすればよいですか?
@明示的に SIGCHLD を無視する:
わかりましたので、明示的に無視すると waitpid() が失敗することを理解しています。明示的に無視するわけではありませんが、次のように別の場所でクラッシュをトラップするようにいくつかのシグナル ハンドラーを設定しています。
void kxHandleCrashes()
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = abortHandler;
sigemptyset( &sa.sa_mask );
sigaction( SIGABRT, &sa, NULL );
sigaction( SIGSEGV, &sa, NULL );
sigaction( SIGBUS, &sa, NULL );
sigaction( SIGILL, &sa, NULL );
sigaction( SIGFPE, &sa, NULL );
sigaction( SIGPIPE, &sa, NULL );
// Should I add aline like this:
// sigaction( SIGCHLD, &sa, NULL );
}