Linux系统,信号提供了一种处理异步事件的方法。很多重要的程序都需要处理信号。本文略作梳理,更详细的知识可以参考APUE。
一、基本概念
- 信号是软件中断,信号相对于进程控制流程来说是异步的
- kill -l命令可以查看系统定义的信号列表,每一个信号都有一个编号(不为0)和名称
- 信号在用户程序不注册处理函数时,有默认的处理动作,比如:终止进程、coredump
二、产生信号
- 用户终端按键触发信号发送到前台进程,比如: Ctrl-C产生SIGINT中断信号,Ctrl-\产生SIGQUIT信号
- 硬件异常产生信号,如:除0产生SIGFPE信号,非法内存访问产生SIGSEGV信号
- 发送kill命令
- 另一个进程调用kill函数发送信号
- 内核检测到某种软件条件发生,比如:timer超时产生SIGALRM信号,向已关闭的管道写数据产生SIGPIPE信号
三、阻塞信号
- 信号在内核中的表示
- pending: 信号是否处于未决状态,信号产生内核处理中断完成后,对应的信号pending被设置为1。如果block标记为0,则可以递送,否则需等待解除阻塞后递送
- block: 是(1)/否(0) 阻塞产生的信号递送。阻塞时,信号多次产生的话,常规信号仅计一次(标记pending为1),实时信号排队处理
- 信号集操作函数
- sigemptyset、sigfillset:初始化信号集 (前者将信号集中的所有bit位置0,后者则置1)
- sigaddset, sigdelset: 操作信号集添加或删除某信号 (对应的信号bit位置1或0)
- sigismember: 检查信号是否在信号集是否有效
- sigprocmask: 操作信号屏蔽字(即设置信号的block标记,如果为1则阻塞递送)
- sigpending: 获取进程的未决信号集(信号的pending为1)
- sigsuspend: 挂起当前进程,直到捕捉到一个信号
四、信号捕捉
- 捕捉后处理
- 忽略SIG_IGN
- 不忽略
- 执行系统默认SIG_DFL
- 用户程序注册handler处理
- 注册信号处理函数的方式
- signal: 使用sigaction函数替代
- sigaction
- 信号处理函数指针有两种,只能二选一 (sa_flags是否被标记SA_SIGINFO区分)
- 如果用户程序注册信号处理函数,则信号递送后,表示捕捉信号成功,过程举例
- 用户程序注册了SIGINT信号的处理函数sighandler
- 程序执行时任意时刻,收到SIGINT信号发生中断切换到内核态
- 中断处理完毕,内核在返回用户态之前,发现SIGINT信号处于未决状态且未被阻塞递送,则返回用户态后执行信号处理函数sighandler
- 信号处理函数sighandler执行完毕后,自动执行特殊的系统调用sigreturn再次进入内核态
- 内核态检查没有新的信号可以递送,则返回用户态执行正常的业务流程