信号集
我们需要一种数据类型去描绘多种信号,这种数据类型被称为信号集。我们将使用sigprocmask函数告知内核不允许哪类信号发生。就像之前说的那样种类众多的信号超出了整型能表示的位数,所以一般来说我们不使用整型中的一位来描述信号。POSIX.1定义的数据类型是sigset_t来包含信号集并且用下面五种函数来操纵信号集。
|
sigemptyset函数初始化信号集,让其不包含任何信号。sigfillset初始化信号集包含所有信号。所有的应用程序必须在使用信号集之前为每个信号集调用sigemptyset或sigfillset函数一次,because we cannot assume that the C initialization for external and static variables (0) corresponds to the implementaion of signal sets on a given system。(不知道C initialization是什么东西,大概意思应该是“不能保证你所使用的系统中的每个信号都包含在该信号集内”)
一旦我们初始化了信号集,我们能在该集中添加和删除指定的信号。sigaddset函数添加单一的信号到已经存在的集中,而sigdelset从集中移除单一的信号。这几个函数都需要一个信号集参数,我们通过传送一个信号集地址作为这个参数。
实现
如果所用实现中没有几个信号,信号数少于整型位数,信号集的实现可以使用整型变量的每一位表示一个信号。本节剩下的部分假定实现的系统有31个信号并且整型变量是32位。sigemptyset函数将整型归零,sigfillset函数可以将整型的每位置1。这两个函数在<signal.h>头文件中用宏实现:
#define sigemptyset(ptr) (*(ptr) = 0)
#define sigfillset(ptr) (*(ptr) = ~(sigset_t)0, 0)
|
注意:函数必须返回0,并设置每一位都是1,所以我们使用逗号操作符,它返回逗号后面的表达式值。(so we use C’s comma operator, which returns the value after the comma as the value of the expression.)
使用这个实现,sigaddset打开信号的某一位,sigdelset关闭信号的某一位;sigisnumber测试某一位。因为没有信号是数字0,所以我们从信号数上减1来获得相应的比特位,用函数来操纵该“数”。下面显示了这几个函数的实现:
Figure 10.12. An implementation of sigaddset, sigdelset, and sigismember#include <signal.h>
#include <errno.h>
/* <signal.h> usually defines NSIG to include signal number 0 */
#define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG)
int
sigaddset(sigset_t *set, int signo)
{
if (SIGBAD(signo)) { errno = EINVAL; return(-1); }
*set |= 1 << (signo - 1); /* turn bit on */
return(0);
}
int
sigdelset(sigset_t *set, int signo)
{
if (SIGBAD(signo)) { errno = EINVAL; return(-1); }
*set &= ~(1 << (signo - 1)); /* turn bit off */
return(0);
}
int
sigismember(const sigset_t *set, int signo)
{
if (SIGBAD(signo)) { errno = EINVAL; return(-1); }
return((*set & (1 << (signo - 1))) != 0);
}
|
我们可以试图实现这三个函数做为一个一行长的宏在<signal.h>头文件中实现,但是POSIX.1需要我们去检查信号数参数的有效性,并且如果该信号数无效的话设置errno。相比函数实现,用宏实现这个功能更困难。