一,信号,信号集
1. 信号相关的概念
信号递达:实际执行信号的处理动作
信号未决:从信号产生到信号递达之间的状态
信号阻塞:如果一个信号被阻塞,那它在产生时处于未决状态,不会被递达,只有解除该信号后,才被递达。
注意:信号的阻塞,是还未执行处理动作,而信号的忽略是正在处理信号,但信号的处理动作是忽略。这两者是不同的。
2. 信号在内核中的表示
我们之前一直说操作系统向进程发送了一个信号,但操作系统是如何发送的,见下图:
上图应该横向来看,每一行表示一种信号。上图表明,在每个进程的PCB中都有一个有关信号的指针,该指针指向一张表,该表中有三部分内容:
block位图:表示每种信号是否被阻塞,0表示没有被阻塞,1表示被阻塞。
pending位图:表示每种信号的未决状态,1表示该信号已经已经产生,但还未递达。0表示信号没有产生,或者产生后已经递达了,此时该标志位也变为0。
handler表:实际是一函数指针数组,数组每个元素对应处理该信号的函数指针。如果是SIG_DEL表示自行默认处理动作,如果是SIG_IGN表示忽略该信号,如果是用户自定义处理动作,则保存的是自定义函数的指针,该自定义函数位于用户空间中。
因此,操作系统向进程发送信号是指将该表中的pending位图中的该信号对应状态位由0变为1。如果该信号的block标志位为1,表明该信号被阻塞,所以不会被递达,只有解除阻塞后才会递达。用户可以通过修改handler表中该信号对应的函数指针。当接收到该信号时,来执行自定义处理动作,这就叫信号的捕捉。
常规信号在递达前产生多次时,只会被记一下,而实时信号可以将其全部放入一个队列中。这里只讨论常规信号。
二, 信号集及相关操作函数
上面我们已经了解了操作系统是如何发送信号的。当我们使用触发或采取二中信号产生的条件时,操作系统会将pending表中对应的比特位由0变为1来产生信号。也就是说pending表是由操作系统来修改的。如果我们想阻塞某种信号,就必须人为的对block表中的比特位进行修改,以及想知道pending表和block表中的相关内容,这些又如何做到呢?
1. 信号集sigset_t
我们要查看或修改block表,首先要知道它是如何存储的,即它是什么类型的。从上图中可以看到,pending表和block表的结构很相似,都是一个比特位表示一种信号的未决或阻塞状态。所以,所有信号的未决状态信息和阻塞状态信息,可以用同一种类型来存储,这个类型就叫做信号集sigset_t。阻塞信号集也叫作信号屏蔽字。
2. 信号集操作函数
知道了block表和pending表的存储类型,便可以对其查询和修改了。sigset_t类型内部是如何存储这些比特位的,这些我们是不必关心的。如果是一个整型变量,可以直接对其赋值进行修改。而sigset_t类型的变量必须通过调用以下函数来实现:
注意:对sigset_t类型的变量进行查看或修改只能通过调用以下函数,而直接printf打印该类型的变量是没有意义的</