2026/10/11 17:46:01
网站建设
项目流程
Linux进程信号——捕捉、操作系统运行机制与实战
四、捕捉信号
4.1 信号捕捉的流程
如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。
处理过程举例:
- 用户程序注册了SIGQUIT信号的处理函数sighandler
- 当前正在执行main函数,这时发生中断或异常切换到内核态
- 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达
- 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程
- sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态
- 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了
示意图:
用户态 ----+--------+--------+--------+---- | | | | | | | | 内核态 ----+--------+--------+--------+---- 检查pending表
4.2 sigaction
#include<signal.h>intsigaction(intsigno,conststructsigaction*act,structsigaction*oact);
- sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回-1
- signo是指定信号的编号
- 若act指针非空,则根据act修改该信号的处理动作
- 若oact指针非空,则通过oact传出该信号原来的处理动作
- act和oact指向sigaction结构体
sigaction结构体:
structsigaction{void(*sa_handler)(int);void(*sa_sigaction)(int,siginfo_t*,void*);sigset_tsa_mask;intsa_flags;void(*sa_restorer)(void);};
- 将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号
- 赋值为常数SIG_DFL表示执行系统默认动作
- 赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函数
- 该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号
- 显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用
注意:
- 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么它会被阻塞到当前处理结束为止
- 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字
- sa_flags字段包含一些选项,本章的代码都把sa_flags设为0
- sa_sigaction是实时信号的处理函数,本章不详细解释这两个字段
4.3 穿插话题——操作系统是怎么运行的
4.3.1 硬件中断
- 中断向量表就是操作系统的一部分,启动就加载到内存中了
- 通过外部硬件中断,操作系统就不需要对外设进行任何周期性的检测或者轮询
- 由外部设备触发的,中断系统运行流程,叫做硬件中断
// Linux内核0.11源码voidtrap_init(void){inti;set_trap_gate(0,÷_error);// 设置除操作出错的中断向量值。以下雷同。set_trap_gate(1,&debug);set