深入理解计算机系统--信号
深入理解计算机系统--信号
2012-07-19 22:38:52| 分类: Linux | 标签:linux 信号 计算机系统 |字号大中小订阅
信号
信号其实是一种高级的软件形式的异常。我们已经知道了硬件和软件是如何合作以提供基本的低层异常机制的,我们也知道了操作系统是如何利用异常来支持一种称为进程上下文切换的异常控制流形式。在本篇文章里,继续研究一种更高层次的软件形式的异常,称为unix信号,它允许进程中断其他进程。
信号就是一条小消息,它通知进程系统中发生了一种类型的事件。Linux系统上支持30多种信号,我简单介绍几个常用的信号。
序号 | 名称 | 默认行为 | 相应事件 |
1 | SIGHUP | 终止 | 终端线挂断 |
2 | SIGINT | 终止 | 来自键盘的中断 |
3 | SIGABRT | 终止 | 来自abort函数的终止 |
4 | SIGCHLD | 忽略 | 一个子进程停止或者终止 |
5 | SIGALRM | 终止 | alarm函数的信号 |
6 | SIGBUS | 终止 | 总线错误 |
每个信号类型都对应于某个系统事件。低层的硬件异常是由内核异常处理程序处理的,正常情况下是对用户进程而言是不可见的。那么信号提供了一种机制,可以通知用户进程发生了哪些异常。比如如果一个进程试图除以0,那么内核就会发送给他一个SIGFPE信号。如果一个进程进行非法存储器的引用,内核就发送给它一个SIGSEGV信号。
发送信号
是指内核通过更新目的进程上下文中的某个状态,发送给目的进程一个信号。发送信号的原因可能有两个:1)内核检测到了一个系统事件,比如是除以0,或者是子进程终止等。2)一个进程用kill函数,显示的要求内核发送给目的进程一个信号。一个进程也可以给自己本身发送新号。
接受信号
当目的进程被内核强迫以某种方式对信号的发送做出反应时,目的进程就接受了信号。进程也可以忽略该信号,终止或者通过执行一个信号处理函数去处理信号。
一个只发出却没有被接受的信号叫做待处理信号pending signal。在任何时刻,一种类型至多只会有一个待处理信号。如果一个进程有一个类型为k的待处理信号,那么接下来发送到这个进程的类型为k的信号都不会排队等待,而是简单的被丢弃。
一个待处理信号最多只能被接受一次。内核为每个进程在pengding位向量中维护着待处理信号的集合,而在blocked位向量中维护着被阻塞的信号集合。只要传送了一个类型为k的信号,内核就会设置pending位向量中的第k位,而只要接收了一个类型为k的信号,内核就会清除pending位向量中的第k位。
信号处理问题
对于只捕获一个信号并终止的程序来说,信号处理是非常简单的。然而,当一个程序要捕获多个信号的时候,一些细微的问题就产生了。
-
待处理信号被阻塞。Unix信号处理程序通常会阻塞当前处理程序正在处理的类型的信号。比如一个进程捕获了信号SIGINT,并且该进程正在运行SIGINT信号的信号处理函数,这时又一个SIGINT信号传送到这个进程,此时这个SIGINT将变成待处理的,但是不会被接受,指导处理程序返回。
-
待处理信号不会排队等待。任意类型至多只有一个待处理信号。因此,如果有两个类型为k的信号传送到一个目的进程,而由于目的进程当前正在执行信号k 的处理程序,所以信号k是阻塞的,那么第二个信号就被简单的丢弃,它不会排队等待。关键思想是只存在一个待处理的信号仅仅表明至少已经有一个信号到达了。
-
系统调用可以被中断。像read,write这样的系统调用潜在地会阻塞进程一段较长的时间,成为慢速系统调用。在这些系统中,当处理程序捕获到一个信号的时候,被中断的慢速系统调用在信号处理程序返回时不再继续,而是立即返回给用户一个错误条件,并将error设置成为EINTTR。