可靠的信号术语和语义
我们需要定义一些术语用于我们讨论信号。首先,当某个引发信号的事件发生时,信号是为一个进程产生(generation)的(或发送到一个进程)。这个事件可能是一个硬件异常(如:除数为0)、一个软件条件(如:alarm计时间超时)、一个终端产生的信号或调用了kill函数。当产生了信号时,内核通常在进程表中设置一些形式的标记。
当一个信号已经设置了动作,我们说这个信号已经交付(delivery)给了进程。在一个信号产生后和交付之间的这段时间被称作准备(pending)。
进程有阻塞(blocking)信号交付的选项。如果一个信号被阻塞并且该信号的动作要么是默认要么是捕获,那么这个信号为进程保留了准备时间,直到要么(a)解除该信号的阻塞或(b)改变信号的动作为忽略。系统决定当信号交付时被阻塞的信号要作些什么,而不是当信号被产生时。这允许进程在信号被交付前改变它的动作。sigpending函数可以被进程调用,用于决定哪些信号被阻塞和准备。
如果一个被阻塞的信号在解除阻塞之前产生了不止一次,那么会发生什么?POSIX.1允许系统交付信号一次或多次。如果系统交付信号超过一次,我们说信号被排队。多数UNIX系统,并不排队信号,除非它们支持实时扩展到POSIX.1。而多数UNIX内核交付信号一次。
SVR2的手册宣称当进程正在执行SIGCLD信号处理函数的同时,这时产生的SIGCLD信号会被排队。虽然这在概念层上是真实的,但是在实际的实现上有所不同。信号会被内核重新生成(就像在APUE 10.7节描述的那样)。在SVR3中,当进程正在执行SIGCLD的信号处理函数的同时产生的SIGCLD信号会被忽略。在SVR4中,并没有提及当进程正在执行SIGCLD的信号处理函数的同时产生SIGCLD信号会发生什么。
SVR4的sigaction(2)函数在AT&T中的手册里声明,SA_SIGINFO标记引发的信号是可靠队列。不过这是错误的。显然,这个功能只是部分地被实现在内核中,但并没有在SVR4中开启。奇怪的是,SVID并没有宣称相同的可靠队列。
如果有不止一个信号做好了交付到进程的准备,会发生什么?POSIX.1没有特别的顺序来安排信号如何交付到进程。POSIX.1只是建议,和当前进程状态有关联的信号优先于其它信号。(SIGSEGV就是这类信号)
每个进程都有一个信号掩码,它定义了一组当前交付到相关进程中被阻塞的信号。我们可以认为这个掩码就像是为每个可能的信号安排了一个比特位。如果该位是on,那把这个信号会被阻塞。进程可以检查并改变当前信号掩码,只要使用sigprocmask函数就可以。
因为信号的数量大大的超出了整型变量的位数,所以POSIX.1定义了一个数据类型,被叫做sigset_t,它持有一个信号集。信号掩码被存储在其中的一个信号集中。在APUE的10.11节,会描述5个操作信号集的函数。