2.6.3 查询子进程终止原因
系统调用waitid的原型如下:
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
参数idtype指定标识符类型,支持以下取值。
(1)P_ALL:表示等待任意子进程,忽略参数id。
(2)P_PID:表示等待进程号为id的子进程。
(3)P_PGID:表示等待进程组标识符是id的任意子进程。
参数options是选项,取值是0或者以下标志的组合。
(1)WEXITED:等待退出的子进程。
(2)WSTOPPED:等待收到信号SIGSTOP并停止执行的子进程。
(3)WCONTINUED:等待收到信号SIGCONT并继续执行的子进程。
(4)WNOHANG:如果没有子进程退出,立即返回。
(5)WNOWAIT:让子进程处于僵尸状态,以后可以再次查询状态信息。
系统调用waitpid的原型是:
pid_t waitpid(pid_t pid, int *wstatus, int options);
系统调用wait4的原型是:
pid_t wait4(pid_t pid, int *wstatus, int options, struct rusage *rusage);
参数pid的取值如下。
(1)大于0,表示等待进程号为pid的子进程。
(2)等于0,表示等待和调用进程属于同一个进程组的任意子进程。
(3)等于-1,表示等待任意子进程。
(4)小于-1,表示等待进程组标识符是pid的绝对值的任意子进程。
参数options是选项,取值是0或者以下标志的组合。
(1)WNOHANG:如果没有子进程退出,立即返回。
(2)WUNTRACED:如果子进程停止执行,但是不被ptrace跟踪,那么立即返回。
(3)WCONTINUED:等待收到信号SIGCONT并继续执行的子进程。
以下选项是Linux私有的,和使用clone创建子进程一起使用。
(1)__WCLONE:只等待克隆的子进程。
(2)__WALL:等待所有子进程。
(3)__WNOTHREAD:不等待相同线程组中其他线程的子进程。
系统调用waitpid、waitid和wait4把主要工作委托给函数do_wait,函数do_wait的执行流程如图2.21所示,遍历当前线程组的每个线程,针对每个线程遍历它的每个子进程,如果是僵尸进程,调用函数eligible_child来判断是不是符合等待条件的子进程,如果符合等待条件,调用函数wait_task_zombie进行处理。
图2.21 函数do wait的执行流程
函数wait_task_zombie的执行流程如下。
(1)如果调用者没有传入标志WEXITED,说明调用者不想等待退出的子进程,那么直接返回。
(2)如果调用者传入标志WNOWAIT,表示调用者想让子进程处于僵尸状态,以后可以再次查询子进程的状态信息,那么只读取进程的状态信息,从线程的成员exit_code读取退出码。
(3)如果调用者没有传入标志WNOWAIT,处理如下。
1)读取进程的状态信息。如果线程组处于正在退出的状态,从线程组的信号结构体的成员group_exit_code读取退出码;如果只是一个线程退出,那么从线程的成员exit_code读取退出码。
2)把状态切换到死亡,释放进程描述符。