8.5.4 阻塞和解除阻塞信号

8.5.4 阻塞和解除阻塞信号

Linux 提供阻塞信号的隐式和显式的机制:

  • 隐式阻塞机制。 内核默认阻塞任何当前处理程序正在处理信号类型的待处理的信号。例如,图 8-31 中,假设程序捕获了信号 s,当前正在运行处理程序 S。如果发送给该进程另一个信号 s,那么直到处理程序 S 返回,s 会变成待处理而没有被接收。
  • 显式阻塞机制。 应用程序可以使用 sigprocmask 函数和它的辅助函数,明确地阻塞和解除阻塞选定的信号。
#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);

返回: 如果成功则为 0,若出错则为 -1。

int sigismember(const sigset_t *set, int signum);

返回:signumset 的成员则为 1,如果不是则为 0,若出错则为 -1。

sigprocmask 函数改变当前阻塞的信号集合(8.5.1 节中描述的 blocked 位向量)。具体的行为依赖于 how 的值:

  • SIG_BLOCK:把 set 中的信号添加到 blocked 中(blocked = blocked | set)。
  • SIG_UNBLOCK:从 blocked 中删除 set 中的信号(blocked = blocked & ~set)。
  • SIG_SETMASKblocked = set

如果 oldset 非空,那么 blocked 位向量之前的值保存在 oldset 中。

使用下述函数对 set 信号集合进行操作:sigemptyset 初始化 set 为空集合。sigfillset 函数把每个信号都添加到 set 中。sigaddset 函数把 signum 添加到 setsigdelsetset 中删除 signum,如果 signumset 的成员,那么 sigismember 返回 1,否则返回 0。

例如,图 8-32 展示了如何用 sigprocmask 来临时阻塞接收 SIGINT 信号。

sigset_t mask, prev_mask;

Sigemptyset(&mask);
Sigaddset(&mask, SIGINT);

/* Block SIGINT and save previous blocked set */
Sigprocmask(SIG_BLOCK, &mask, &prev_mask);
...
/* Code region that will not be interrupted by SIGINT */
...
/* Restore previous blocked set, unblocking SIGINT */
Sigprocmask(SIG_SETMASK, &prev_mask, NULL);

图 8-32 临时阻塞接收一个信号