如何异步等待进程终止并找出退出代码?

How to asynchronously wait for process termination and find out the exit code?

pidfd_openpoll 的等待工作正常。

我面临的问题,在进程退出后,apparently poll() API 删除了关于现在已死进程的信息,所以 waitid P_PIDFD 参数立即失败,提示代码 22“无效参数”

我认为我负担不起为每个 child 进程启动一个线程以在阻塞 waitpid 上休眠,我有多个进程,而另一个句柄不是我需要的进程有效地进行投票。

有什么解决方法吗?

如果重要的话,我只需要在 ARM64 和 ARMv7 CPU 上支持 Linux 5.13.12 和更新的 运行。

内核调用的大致顺序如下:

  1. fork
  2. 在child中:setresuidsetresgidexecvpe
  3. 在新的 child 中:printfsleep_exit
  4. 同时在 parent 中:pidfd_openpoll,完成后 waitid 第一个参数 P_PIDFD

预期结果:waitid 应该给我 child 的退出代码。

实际结果:它什么也不做,将 errno 设置为 EINVAL

您可以使用单个收割线程,在 waitpid(-1, &status, 0) 上循环。每当它获取子进程时,它都会在当前子进程集中查找它,处理可能的通知(信号量或回调),并存储退出状态。

有一种值得注意的情况需要特别考虑:子进程可能会在父进程的 fork() returns 之前退出。这意味着收割者有可能在执行 fork() 的代码设法在任何数据结构中注册子进程 ID 之前看到子进程退出。因此,reaper 和 fork() 注册函数都必须准备好在数据存储中查找或创建记录以跟踪子进程;包括调用回调或发布信号量。它一点也不复杂,但是除非你习惯于用异步的方式思考,否则很容易错过这些极端情况。

因为 wait(...)/waitpid(-1,...) returns 当没有子进程等待时立即执行(-1 和 errno 设置为 ECHILD ),当没有子进程等待时,reaper 线程可能应该等待条件变量,注册子进程 ID 的代码会在该条件变量上发出信号,以最大限度地减少无子进程情况下的资源使用。 (此外,请记住尽量减少收割线程堆栈大小,因为默认情况下它过大(大约 8 MiB)并且浪费资源。我经常使用 2*PTHREAD_STACK_MIN,我自己。)

关键有一点。来自 man waitid:

Applications shall specify at least one of the flags WEXITED, WSTOPPED, or WCONTINUED to be OR'ed in with the options argument.

I was passing was WNOHANG

你想通过 WNOHAND | WEXITED ;)