信号在最早的Unix系统中即被引入,用于在用户态进程间通信。内核也用信号通甜味晕程系统所发生的事件。
信号的作用
信号(signal)是很短的消息,可以被发送到一个进程或一组进程。发送给进程的唯一信息通常是一个数,以此来标识信号。在标准信号中,对参数、消息或者其他相随的信息没有给予关注。
使用信号的两个主要目的是:
- 让进程知道已经发生了一个特定的事件。
- 强迫进程执行它自己代码中的信号处理程序。
基于80x86的Linux 2.6所处理的前31个信号[即:SIGHUP(1)- SIGSYS(31)]为常规信号(regular signal)。POSIX标准还引入了一类新的信号,叫做实时信号(real-time signal)[即:SIGRTMIN(34)- SIGRTMAX(64)];实时信号与常规信号不同,它们必须排队以便发送的多个信号能被接收到;常规信号并不排队:如果一个常规信号被送多次,那么,只有其中一个发送到接收进程。Linux内核并不使用实时信号,它是通过几个特定的系统调用完全实现了POSIX标准。
内核区分信号传递的两个不同阶段:
- 信号产生 内核更新目标进程的数据结构以表示一个新信号已发送
- 信号传递 内核强迫目标进程通过以下方式对信号做出反应:或改变目标进程的执行状态,或开始执行一个特定的信号处理程序,或两者都是。
信号是可消费资源:一旦它们已传递出去,进程描述符中有关这个信号的所有信息都被取消。
已经产生但还没有传递的信号称为挂起信号(pending signal)。一个进程中仅存在一个给定类型信号挂起,进程中的同种类型的其他信号不被排队,只被简单地丢弃。但是实时信号同种类型的挂起信号可以有好几个。
信号可以保留不可预知的挂起时间。必须考虑下列因素:
- 信号通常只被当前正运行的进程传递(即由current进程传递)。
- 给定类型的信号可以由进程选择性地阻塞(blocked)。这种情况下,在取消阻塞前进程将不接收这个信号。
- 当进程执行一个信号处理程序的函数时,通常“屏蔽”相应的信号,即自动阻塞这个信号直到处理程序结束。因此,所处理的信号的另一次出现不能中断信号处理程序,所以信号处理函数不必是可重入的。
- 记住每个进程阻塞哪些信号
- 当从内核态切换到用户态时,对任何一个进程都要检查是否有一个信号已到达。这几乎在每个定时中断都发生(大约每毫秒发生一次)。
- 确定是否可以忽略信号。这发生下列所有的条件都满足时:
— 目标进程没有被另一个进程跟踪(进程描述符中ptrace字段的PT_PTRACED标志等于0)。
— 信号没有被目标进程阻塞。
— 信号被目标进程忽略(或者因为进程已显式地忽略了信号,或者因为进程没有改变信号的缺省操作县城这个缺省操作就是“忽略”)。 - 处理这样的信号,即信号可能在进程运行期间的任一时刻请求把进程切换到一个信号处理函数,并在这个函灵敏返回以后恢复原来执行的上下文。