操作系统折腾记(三)

wait

https://www.ibm.com/docs/en/ztpf/2020?topic=apis-waitwait-status-information-from-child-process

1
2
#include <sys/wait.h>
int wait(int *stat_loc);

等待任一子进程退出,如果正常获取到了子进程的退出信息(存入 stat_loc 指向的地址),返回该子进程的 pid;否则立即返回 -1 并设置 errno(据实践,不会更改 *stat_loc 原本的值,「立即返回」应该就是这个意思)。

注意,wait 的返回值只说明了它本身有没有被正常地执行,并不能说明子进程是怎样退出的。无论子进程是怎么挂掉的,只要 wait 成功地搞到了子进程挂掉的信息(stat_loc),就返回 pid (>0);什么时候搞不到呢,一是调用 wait 的进程本来就没有子进程,二是 wait 被信号中断了。

那么子进程有哪些退出状态呢?CSAPP 中说到,进程会因为三种原因终止:

  1. 收到一个信号
  2. 从主程序返回
  3. 调用 exit 函数:有一个 exit code,如 exit(0)exit(-1)

那我们怎么知道子进程是因为什么原因而退出的呢?看 stat_loc 呗!怎么个看法呢?见下文 WIFEXITED & WEXITSTATUS 一节。

waitpid

https://www.ibm.com/docs/en/ztpf/2020?topic=apis-waitpidobtain-status-information-from-child-process

1
2
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_loc, int options);

类似于 wait,但功能更强大了。首先,pid 参数有以下两种选择:

  • pid>0:等待集合就是 ID 为 pid 的子进程
  • pid=-1:等待集合是所有 子进程

其次,options 选项提供了 waitpid 行为的选择:

  • 默认为 0,则 waitpid挂起调用它的进程,直到等待集合中的某一个子进程终止;当然,如果本来就有终止的子进程,那么就立即返回了
  • WNOHANG:如果等待集合中没有已经终止的子进程,就立即返回而不挂起等待
  • ……

WIFEXITED & WEXITSTATUS

https://www.ibm.com/docs/en/ztpf/2020?topic=zca-wifexitedquery-status-see-if-child-process-ended-normally

https://www.ibm.com/docs/en/ztpf/2020?topic=apis-wexitstatusobtain-exit-status-child-process

https://www.ibm.com/docs/en/ztpf/2020?topic=zca-wifsignaledquery-status-see-if-child-process-ended-abnormally

https://www.ibm.com/docs/en/ztpf/2020?topic=zca-wtermsig-determine-which-signal-caused-child-process-exit#cpp_wtermsig

https://blog.csdn.net/duyuguihua/article/details/38986197

https://blog.csdn.net/y396397735/article/details/53769865

https://stackoverflow.com/questions/47441871/why-should-we-check-wifexited-after-wait-in-order-to-kill-child-processes-in-lin

1
2
3
4
5
6
#include <sys/wait.h>
int WIFEXITED(int status);
int WEXITSTATUS(int status);
int WIFSIGNALED(int status);
int WTERMSIG(int status);
// The status field that was filled in by the wait or waitpid function.

我们知道,父进程调用 wait 或者 waitpid 时需要传入一个 &status,意即获取子进程的退出状态。大多数情况下,我们并不关心子进程怎么挂掉的,所以经常这么写:wait(NULL) 或者 wait(0)

但有的时候我们就是想看看 statusstatus 能指出子进程是怎样退出的、如果是 exit 的话返回值是啥、如果是被信号结束的话是被谁结束的……这些信息被编码进了一个 int 的二进制位中。但是每次找某个二进制位也太麻烦了吧,所以为了方便,人们定义了一套,用来解析 status 的信息:

  • WIFEXITED(status)

    如果子进程是调用 exit 退出的,返回 TRUE,接下来我们需要用 WEXITSTATUS 获取子进程的 exit code;否则返回 FALSE。

  • WEXITSTATUS(status)

    返回子进程的 exit code,当然前提是 WIFEXITED(status) 是 TRUE,否则返回值没有任何意义。

  • WIFSIGNALED(status)

    如果子进程是因为信号而退出的,返回 TRUE,接下来我们需要用 WTERMSIG 获取究竟是什么信号让它退出的;否则返回 FALSE。

  • WTERMSIG(status)

    返回让子进程退出的信号对应的数值(什么信号对应什么数值在 sys/signal.h 中有定义),前提是 WIFSIGNALED(status) 是 TRUE,否则返回值没有任何意义。

  • ……

(注:C 语言没有 bool 类型,也没有 truefalse,上文中的 TRUE 泛指非零值,FALSE 指 0 值)


操作系统折腾记(三)
https://xyfjason.github.io/blog-main/2021/12/10/操作系统折腾记(三)/
作者
xyfJASON
发布于
2021年12月10日
许可协议