参考书籍 The Design and Implementation of the FreeBSD Operating System by Marshall Kirk McKusick, George V. Neville-Neil, and Robert N.M. Watson. 2nd edition, Chapter 4, Process Management – 4.7 Signals.
信号最初是用来为特殊事件建立的模型,比如一个用户要强制结束一个逃逸程序。当时的设计并没有把信号作为一种进程之间通信的机制,因此并没有多少人关心他的可靠性。在早期的系统中,如果一个信号被捕获,其对应的处理是重置为默认的操作。
当前FreeBSD中的信号系统是建立在一个虚拟机模型(virtual machine model)之上的。在该模型中,系统调用被视作与硬件指令是相同类型的操作。信号是该模型中与硬件陷阱和中断相对应的机制。只不过信号是软件实现的。信号处理程序与陷阱/中断处理程序具有相同的机制。类似于硬件中可以屏蔽中断来保证数据访问的一致性,软件实现的信号也可以被屏蔽。最后,同中断处理类似,有些信号处理程序要求复杂的运行时栈环境,特定的信号处理可以有选择的借助应用在用户空间提供的运行栈。
硬件机器 | 软件虚拟机 |
---|---|
指令集 | 系统调用集 |
可重启指令 | 可重启的系统调用 |
中断/陷阱 | 信号 |
中断/陷阱处理程序 | 信号处理程序 |
中断屏蔽 | 信号屏蔽 |
中断栈 | 信号栈 |
Table: 硬件系统操作与软件虚拟机系统操作的对比。
信号处理是按照每个进程为单位进行的。如果一个进程没有制定如何处理一个信号,则对该信号采取默认处理程序。默认处理程序可以是:
- 忽略
- 终止(terminating) 进程中所有线程
- 在生成core file后终止(terminating) 进程中的所有线程
- 强制退出(stopping) 进程中的所有线程
- 恢复进程中的所有线程
一个应用程序可以通过sigaction系统调用来指定某个信号的处理程序,这些程序包括:
- 采取默认操作
- 忽略
- 使用指定信号处理程序(signal handler)
信号处理程序(signal handler)是一个系统调用可以调用的用户态程序。一般称信号处理程序捕获一个信号。SIGSTOP 和 SIGKILL 两个信号是无法屏蔽,忽略,或者捕获的。这样的限制保证了这两个信号可以用于stop或kill逃逸程序。
当系统检测到事件发生时,系统可以发送信号通知进程。这样的事件包括硬件事件,如非法指令,和软件事件,如终端发送的终止请求。一个进程可以通过kill系统调用给另一个进程发送信号。一个发送信号的进程仅仅能发送给具有相同有效用户标识(effective user identifier)的其他进程发送信号,即一个用户的进程无法发送信号给另一个用户的进程,除非该用户是超级用户。唯一的一个特例是continue信号 SIGCONT。该信号可以发送给当前发送者进程的所有子进程。保留这样一个特例的原因是允许用户在用键盘停止setuid程序后能够重启该程序。
系统调用sigprocmask可供每个线程用来屏蔽信号的传送(delivery)。如果一个线程的信号被屏蔽,该信号被存储在该线程的等待信号队列(pending signals)中,该队列中的信号不会被处理,除非信号被解屏蔽。sigprocmask可以修改线程的等待信号队列。它可以向队列中增加新的屏蔽信号,删除已屏蔽信号,或者替换屏蔽信号。
Although the delivery of the SIGCONT signal to the signal handler of a process may be masked, the actions of resuming that stopped process is not masked.
另外两个信号相关的系统调用是sigsuspend 和 sigaltstack。sigsuspend 允许当前进程主动放弃CPU,直到该进程收到信号为止。类似于**sleep()**方法。sigaltstack 允许当前进程指定一个用于信号处理的运行栈。默认情况下,操作系统会用进程正常使用的运行栈处理信号。在一些程序中,这个默认栈是不可行的。比如,如果一个程序有较多的线程,每一个都有自己的运行栈,那么在每一个运行栈中预留信号处理的栈空间会导致浪费。这时让所有线程都使用同一个足够大的运行栈处理信号,会提高内存使用效率。
最后一个信号相关的系统调用是sigreturn。sigreturn等同于用户态的load-process-context操作。用户程序通过该系统调用传送给内核一个指针。指针指向一个存储着线程的上下文运行环境的内存块。在用户的信号处理程序完成后,sigreturn使用该内存块恢复线程的正常运行。