信号集

信号集

我们需要一种数据类型去描绘多种信号,这种数据类型被称为信号集。我们将使用sigprocmask函数告知内核不允许哪类信号发生。就像之前说的那样种类众多的信号超出了整型能表示的位数,所以一般来说我们不使用整型中的一位来描述信号。POSIX.1定义的数据类型是sigset_t来包含信号集并且用下面五种函数来操纵信号集。

#include <signal.h>

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signo);

int sigdelset(sigset_t *set, int signo);

All four return: 0 if OK, 1 on error

int sigismember(const sigset_t *set, int signo);

Returns: 1 if true, 0 if false, 1 on error

sigemptyset函数初始化信号集,让其不包含任何信号。sigfillset初始化信号集包含所有信号。所有的应用程序必须在使用信号集之前为每个信号集调用sigemptysetsigfillset函数一次,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。相比函数实现,用宏实现这个功能更困难。

发表评论