1. 一、什么是信号
1.信号是很短的消息,可以被发送一个进程或一个进程组,用于进程间的通信
2.消息的内容通常是一个数,这个数用于标识信号
信号的接收方一定是进程,发送方可能是进程,或者内核。
信号只能发送给属于同一session以及同一个用户的进程
3.信号的种类可分为两类
(1)常规信号:编码范围1-31,如果一个常规信号被连续发送多次,会被合并成一次,即只有一个发送到接收进程
(2)实时信号:编码范围32-64,它们必须被排队,以便发送的多个信号都被接收到
(3)常规信号和实时信号,都是用队列来接收的,只是常规信号的接收队列,每个队列中最多只能有一项
(4)可以看出,每个信号对应的信号处理函数相对自己是串行的,不必是可重入的
4.子进程会继承父进程的信号处理方式
2. 二、信号传递的过程
1.信号产生:
更新目标进程的数据结构
2.目标进程对信号的检测与反应
(1)忽略
(2)默认操作
(3)调用相应的信号处理函数
3. 三、信号的挂起、阻塞、忽略、丢弃
1.丢弃:对于常规信号,同种类型的一次存在一个,多余的会被丢弃
2.信号阻塞:某种类型的信号被阻塞后,目标进程不会处理这个信号,直到解除阻塞后再处理(针对信号类型)
3.挂起:已经产生但还没有处理的信号称为挂起信号。对于常规信号,同种类型的挂起信号一次只存在一个(针对某个具体的信号)
4.忽略:目标进程已收到这个信号,并作出回应,回应的方式是不作为任何处理
4. 四、信号产生过程
send_signal()
(1)申请一个挂起信号的数据结构
(2)把数据结构挂入挂起信号队列
(3)修改队列位掩码
(4)如果需要,唤醒进程
5. 五、信号处理的过程
1.在中断机制中,处理器的硬件在每条指令结束进都要检测是否还有中断请求存在
信号机制是纯软件的,不能依靠硬件检测信号,只能在两个特定的时间点检测
2.对信号的检测与响应总发生于系统空间
(1)从系统空间返回到用户空间的前夕
(2)进程在内核睡眠刚被唤醒时,由于信号而提前返回到用户空间
3.进程运行于用户空间时,即使信号到达了也不会作出反应,要等到特定时刻检测到信号才会处理
4.当信号向量为SIG_IGN或SIG_DFL时,对信号的处理都在系统空间完成,无须回到用户空间
当信号向量为用户提供的信号处理程序时,需要用户空间执行,执行完再回到系统空间,然后再回到用户空间
5.执行自定义函数的过程:
do_signal() -----> handle_signal() -----> 信号处理函数
note:
信号处理函数由用户进程定义,包含在用户态代码中,在用户空间运行
handle_signal():运行在内核态
6.关于帧、函数用户、运行空间
(1)帧frame:调用一次子程序时,在栈中保存的一个层次称为一帧,包括子程序的返回地址、子程序的局部变量、调用子程序时的参数
(2)程序与子程序位于同一空间:普通的函数调用
(3)调用者在用户空间,子程序在系统空间:中断处理、异常处理、系统调用
(4)调用者在系统空间,子程序在用户空间:handle_signal()调用信号处理函数
7.从handle_signal()的系统空间 进入 信号处理函数的用户空间 的过程
要从系统空间进入用户空间执行另一段程序,就必须在系统空间准备一个新的帧,而原系统空间的帧也要保存起来
解决方法:把原系统空间帧作为信号处理程序的局部变量,保存在新的帧中
在进入用户空间执行信号处理函数之前,先准备好用户空间堆栈的帧,把原帧复制到新帧中作为局部变量保存起来,回到系统空间后再从那里复制回来
8.从信号处理函数的用户空间 返回到 handle_signal()的系统空间 的过程
用户空间进入系统空间的手段有三种:中断、异常、陷阱,系统调用是陷阱的一种
从信号处理函数返回系统空间使用的方式是系统调用
9.handle_signal() ----- 调用信号处理函数并返回
(1)在用户空间堆栈中为信号处理程序预先创建一个frame,其中包括原系统空间堆栈的frame
(2)在信号处理函数中插入系统调用sigreturn()
(3)将系统空间堆栈中的frame修改为信号处理函数所需的frame
(4)进入用户空间,开始执行信号处理函数
(5)执行信号处理函数
(6)通过系统调用figreturn()返回到系统空间
(7)从用户空间恢复系统堆栈空间的frame
(8)回到用户空间,继续执行用户程序
10.“系统空间->用户空间->系统空间->用户空间”这段过程能不能简化?
答:理论上可以。但是必须保证用户的信号处理程序对“工作现场”(SAVE_ALL所保存的部分)不能更改。
信号处理函数由用户进程定义,包含在用户态代码中,在用户空间运行,不能保证这一点。 为了系统安全,不这么做。
6. 六、为某个信号定义信号处理函数
1.signal(int signr, sigunc *handle);
给信号值是signr的信号安装一个处理函数句柄handle
handle是函数指针
2.自定义的信号处理函数句柄只能使用一次,若要持续使用,在信号处理函数中重置自定义句柄
3.signal()的BUG:在3-(1)的复位和3-(2)的重置之间发生了信号可能会造成信号的丢失。
使用sigaction()能解决信号失去的问题