Linux 信号保存核心:未决信号集与阻塞信号集详解
进程在收到信号时,并不总是立即处理。如果无法立即响应,内核必须将信号暂存起来。这一机制的核心在于**未决信号集(Pending Set)与阻塞信号集(Blocked Set)**的配合。
一、信号保存相关的常见概念
理解信号流程前,需明确三个关键状态:
- 信号递达 (Delivery):实际执行信号处理动作的阶段。
- 信号未决 (Pending):信号从产生到递达之间的中间状态。
- 信号阻塞 (Block):进程选择暂时屏蔽某个信号。
注意:阻塞信号不同于忽略信号。阻塞发生在信号递达之前,被阻塞的信号会保持在未决状态;而忽略是递达后的一种处理动作。二者阶段不同,效果虽相似但机制迥异。

如图所示,阻塞操作作用于'未决'阶段。一旦某信号被阻塞,即使再次发送,进程也不会进入递达流程,就像没收到一样。
二、信号在内核中的表示
在进程的 PCB(task_struct)中,除了保存信号的位图,还有专门的位图用于管理阻塞状态。内核通过三张表来管理信号生命周期:
- block 表:记录当前被阻塞的信号。
- pending 表:记录当前处于未决状态的信号。
- handler 表:函数指针数组,指向具体的信号处理函数(如 SIG_DFL, SIG_IGN)。
这三张表涵盖了信号从产生到递达的所有行为。我们可以从 Linux 源码中找到对应结构:
struct task_struct {
/* signal handlers */
struct sighand_struct *sighand;
sigset_t blocked;
struct sigpending pending;
}
struct sighand_struct {
atomic_t count;
struct k_sigaction action[_NSIG]; // #define _NSIG 64
spinlock_t siglock;
};
sa_handler;
sa_flags;
(*sa_restorer)();
sa_mask;
};
__user *ka_restorer;
};
;
signal;
}


