sigsuspend相当于原子系列的sigprocmask、pause、sigprocmask?

k0z*_*tis 5 c signals exception signal-handling multiple-processes

我正在阅读教科书关于 Linux x86-64 系统的信号/ECF 的章节(CS:APP,第 3 版,第 8 章,第 781 页),并发现了以下内容:

sigsuspend 函数暂时用 mask 替换当前的阻塞集,然后挂起进程,直到收到一个信号,该信号的操作是运行处理程序或终止进程。如果操作是终止,则进程将终止,而不从 sigsuspend 返回。如果操作是运行处理程序,则 sigsuspend 在处理程序返回后返回,将阻塞集恢复到调用 sigsuspend 时的状态。

sigsuspend 函数相当于以下函数的原子(不可中断)版本:

1       sigprocmask(SIG_BLOCK, &mask, &prev);
2       pause();
3       sigprocmask(SIG_SETMASK, &prev, NULL);
Run Code Online (Sandbox Code Playgroud)

据我了解,sigprocmask(SIG_BLOCK, &mask, &prev)应该导致阻塞集与掩码进行“或”运算,即将掩码中的信号添加到阻塞集中已有的信号中。但代码正上方的文本(以及我查找的 sigsuspend 的手册页)表示 sigsuspend“暂时用掩码替换当前的阻塞集”。对我来说,这听起来更像是sigprocmask(SIG_SETMASK, &mask, &prev),阻塞集设置为等于掩码中的信号。

那么为什么sigsuspend(&mask)等价于上面的代码(第 1-3 行)而不是下面的代码(第 4-6 行)呢?我对 signal.h 函数的直觉和/或理解哪里出了问题?

4       sigprocmask(SIG_SETMASK, &mask, &prev);
5       pause();
6       sigprocmask(SIG_SETMASK, &prev, NULL);
Run Code Online (Sandbox Code Playgroud)

如果我不清楚,让我问一个具体的问题(它可能会更好地解释我的直觉)。假设当前的阻塞集编码 SIGCHLD,而 sigset_t 掩码编码 SIGINT。我打电话sigsuspend(&mask)。无论哪种代码解释是正确的(第 1-3 行或第 4-6 行),在调用 sigsuspend 之后传递的 SIGINT 信号都将被阻止/不会唤醒进程。但是,如果在调用 sigsuspend 之后立即传递 SIGCHLD 信号怎么办?进程会唤醒/接收信号吗?我的直觉表明第 1-3 行会阻止 SIGCHLD,而第 4-6 行则不会,因此显然第 1-3 行和第 4-6 行并不等效。但我的直觉还表明,sigsuspend 不应该阻止 SIGCHLD,因为它不在掩码中,因此第 4-6 行是正确的,如果在这种情况下第 4-6 行相当于 sigsuspend,则 sigsuspend 不能相当于第 1 行- 3. 我的直觉/理解哪里出了问题?

Mar*_*eld 4

关于技术书籍(尤其是教科书)的问题是,您应该始终了解是否有可用的勘误表

该书勘误表的链接显示:

第8章:异常控制 流
…… 781. 在第二段的描述中,第 1 行应为: 2015 年 10 月 28 日发布。戴夫·奥哈拉伦

sigsuspend
sigprocmask(SIG_SETMASK, &mask, &prev);