如何异步等待进程终止并找出退出代码?
How to asynchronously wait for process termination and find out the exit code?
pidfd_open
和 poll
的等待工作正常。
我面临的问题,在进程退出后,apparently poll()
API 删除了关于现在已死进程的信息,所以 waitid
P_PIDFD
参数立即失败,提示代码 22“无效参数”
我认为我负担不起为每个 child 进程启动一个线程以在阻塞 waitpid
上休眠,我有多个进程,而另一个句柄不是我需要的进程有效地进行投票。
有什么解决方法吗?
如果重要的话,我只需要在 ARM64 和 ARMv7 CPU 上支持 Linux 5.13.12 和更新的 运行。
内核调用的大致顺序如下:
fork
- 在child中:
setresuid
、setresgid
、execvpe
- 在新的 child 中:
printf
、sleep
、_exit
- 同时在 parent 中:
pidfd_open
、poll
,完成后 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
;)
pidfd_open
和 poll
的等待工作正常。
我面临的问题,在进程退出后,apparently poll()
API 删除了关于现在已死进程的信息,所以 waitid
P_PIDFD
参数立即失败,提示代码 22“无效参数”
我认为我负担不起为每个 child 进程启动一个线程以在阻塞 waitpid
上休眠,我有多个进程,而另一个句柄不是我需要的进程有效地进行投票。
有什么解决方法吗?
如果重要的话,我只需要在 ARM64 和 ARMv7 CPU 上支持 Linux 5.13.12 和更新的 运行。
内核调用的大致顺序如下:
fork
- 在child中:
setresuid
、setresgid
、execvpe
- 在新的 child 中:
printf
、sleep
、_exit
- 同时在 parent 中:
pidfd_open
、poll
,完成后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
;)