我有一个使用 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 );
}