背景:内核刚刚处理完中断和异常.现在它要返回到@current进程了.然而,在返回以前,内核总会习惯性检查一下@current的TIF_SIGPENDING标志,以便确定是否有尚未处理的信号.很不幸,确实有信号正在挂起队列上排队.于是,内核开始启动do_signal()函数…
一. do_signal()函数
遍历@current的挂起信号队列:
1.如果信号的传递方式是SIG_IGN,则忽略这个信号;
2.如果信号的传递方式是SIG_DFL,则根据具体的信号执行相应的默认操作;
3.如果信号有一个处理函数,终止遍历,执行这个信号处理函数;
4.如果信号是0,则检查并处理系统调用的重新执行.
信号处理函数或系统调用的重新执行会返回到内核.紧接着,当内核尝试恢复原程序的执行时,又会陷入do_signal()函数.最终结果是,do_signal()将处理挂起信号队列中的每一个信号.
1.参数
- regs 栈,current在用户态下寄存器的内容存于此处
- oldset 阻塞信号的位掩码数组(已被删除)
2.说明
1. 通常只在CPU返回到用户态时才调用此函数:TIF_SIGPENDING标志的检查总是在内核准备返回到用户态时进行.
2. 反复调用dequeue_signal()直到pending和shared_pending队列为空
3. 调用栈
- do_signal()
在返回到用户态前,处理@current的每一个未阻塞的挂起信号.
- get_signal_to_deliver()
遍历挂起信号队列,自行忽略信号或为信号执行默认操作. - handle_signal()
为执行信号处理程序做准备.
- setup_rt_frame()
复制,修改@current的硬件上下文.
- setup_rt_frame()
- get_signal_to_deliver()
3.复杂性
- 竞争条件,冻结系统,产生内存信息转储,停止/杀死整个线程组
- 中断处理程序调用此函数(可能性?)
- 当current正受到其他进程监控的时候怎么办?
do_notify_parent_cldstop()和schedule() - 待处理的信号是一个被忽略的信号(可能性?)
- 待处理西信号需要被执行缺省操作
- 待处理信号有一个信号处理函数
二.get_signal_to_deliver()函数
这个函数遍历挂起信号队列,处理被显式忽略的信号并并为具体信号执行相应的默认操作.如果遇到信号0(处理系统调用的重新执行)或者遇到注册了信号处理程序的信号,则终止遍历,返回到do_signal()
1.函数的执行过程
- try_to_freeze()
linux冻结系统在信号系统中的钩子函数.linux冻结系统利用信号系统完成自己的功能. - if(signal->flags & SIGNAL_CLD_MASK)
每一个停止的进程在苏醒后都会运行这个检查.在这里,我们检查一下是不是需要通知@current的父进程 - 陷入一个无限循环
- 在循环的开始,检查是不是需要停止整个线程组.
- 从挂起队列上摘下一个信号
- 如果信号是0,则返回0
- 如果信号被显式忽略,continu