信号集

更新时间:
2024-01-09
下载文档

信号集

在 SylixOS 中,需要一个能表示多个信号的信号集,以便告诉内核不允许递送该信号集中的信号。

信号集操作

不同的信号编号可能超过一个整型量所包含的位数,所以一般而言,不能用整型量来表示一个信号集。POSIX.1 定义了数据类型 sigset_t 来定义相应的信号集,不同的系统 sigset_t 可能有不同的定义方法,因此不应该假设 sigset_t 应该是什么样的类型,SylixOS 定义了下面五个函数来对信号集进行操作:

#include <signal.h>
int  sigemptyset(sigset_t  *psigset);
int  sigfillset(sigset_t  *psigset);
int  sigaddset(sigset_t  *psigset, int  iSigNo);
int  sigdelset(sigset_t  *psigset, int  iSigNo);
int  sigismember(const sigset_t  *psigset, int  iSigNo);

函数 sigemptyset 原型分析:

  • 此函数返回 0。
  • 参数 psigset 是要操作的信号集。

函数 sigfillset 原型分析:

  • 此函数返回 0。
  • 参数 psigset 是要操作的信号集。

函数 sigaddset 原型分析:

  • 此函数成功时返回 0,失败时返回-1 并设置错误号。
  • 参数 psigset 是要添加信号的信号集。
  • 参数 iSigNo 是我们添加到信号集的信号。

函数 sigdelset 原型分析:

  • 此函数成功返回 0,失败返回-1 并设置相应的错误号。
  • 参数 psigset 是要删除信号的信号集。
  • 参数 iSigNo 是要删除的信号。

函数 sigismember 原型分析:

  • 此函数返回 1 代表属于指定的信号集,0 代表不属于指定的信号集,-1 代表错误并设置错误号。
  • 参数 psigset 是要判断的信号集。
  • 参数 iSigNo 是被判断的信号。

sigemptyset 函数初始化一个信号集,清除其中所有的信号;sigfillset 函数初始化一个信号集,使其包含所有信号,所有应用程序在操作信号集之前都要调用一次 sigemptyset 函数或者 sigfillset 函数。sigaddset 函数将指定的信号添加到已有的信号集中,注意,已有的信号集进行了初始化;函数 sigdelset 将指定的信号从已有的信号集中删除;函数 sigismember 判断一个信号是否包含在指定的信号集中。

信号屏蔽字

一个线程的信号屏蔽字(或者称作信号掩码)是指当前屏蔽而不能递送给该进程的信号集。调用 sigprocmask 函数可以检测、更改或同时进行检测和更改信号屏蔽字。

#include <signal.h>
int  sigprocmask(int                iHow, 
                 const sigset_t    *sigset, 
                 sigset_t          *sigsetOld);

函数 sigprocmask 原型分析:

  • 此函数成功时返回 0,失败时返回-1 并设置错误号。

  • 参数 iHow 是信号集操作的命令如下表所示: |宏名|| |---|---| |SIG_BLOCK|新的信号集(sigset)以或的形式添加到当前信号屏蔽字中| |SIG_UNBLOCK|从当前信号屏蔽字中删除新的信号集(sigset)中包含的信号| |SIG_SETMASK|将新的信号集(sigset)赋值给当前信号屏蔽字|

  • 参数 sigset 是新的信号集。

  • 输出参数 sigsetOld 保存先前的信号集。

如果 sigset 为 NULL,则不改变该线程的信号屏蔽字(特殊地,如果此时 sigsetOld 非空,则返回该线程的当前信号屏蔽字), iHow 的值也没有意义;如果 sigsetOld 是 NULL,则不会保存先前的信号集。

在调用 sigprocmask 函数之后如果有任何未决(pending)的、不再屏蔽的信号,在 sigprocmask 返回前,至少将其中之一递送给该进程。

作为早期 BSD 兼容接口,SylixOS 提供了下面一组函数,对信号屏蔽字进行操作。

#include <signal.h>
int  sigmask(int  iSigNo);
int  siggetmask(VOID);
int  sigsetmask(int  iMask);
int  sigblock(int  iBlock);

函数 sigmask 原型分析:

  • 此函数成功返回信号掩码,失败返回 0 并设置错误号。
  • 参数 iSigNo 是信号值。

函数 siggetmask 原型分析:

  • 此函数返回当前线程信号屏蔽字。

函数 sigsetmask 原型分析:

  • 此函数返回设置前的信号屏蔽字。
  • 参数 iMask 是新的信号屏蔽字。

函数 sigblock 原型分析:

  • 此函数返回设置前的信号屏蔽字。
  • 参数 iBlock 是新的需要添加的信号集。

sigmask 函数通过信号值来获取此信号对应的屏蔽位(掩码位),调用 siggetmask 函数可以获得当前线程的信号屏蔽字,调用 sigsetmask 函数可将指定的信号集设置为当前线程的信号屏蔽字,调用 sigblock 函数可将指定的信号集以或的方式添加到当前线程的信号屏蔽字,注意,此函数与 sigsetmask 函数不同的是,此函数不会替代先前的信号屏蔽字,而 sigsetmask 函数将用新的信号集替代当前线程的信号屏蔽字。

sigpending 函数返回当前线程未决的信号集,其中的信号是阻塞不能递送的。

#include <signal.h>
int   sigpending(sigset_t  *sigset);

函数 sigpending 原型分析:

  • 此函数成功时返回 0,失败时返回-1 并设置错误号。
  • 输出参数 sigset 返回未决的信号集。

使用实例

下面实例展示了信号集函数的使用。程序首先将 SIGALRM 信号添加到线程(进程的主线程)信号屏蔽字中,经过 2 秒产生 SIGALRM 信号,之后调用 sigpending 函数获取线程的未决信号集并判断是否包含 SIGALRM 信号,最后恢复之前的信号屏蔽字。

#include <stdio.h>
#include <signal.h>

void int_handler (int  signum)
{
    fprintf(stdout, "signal SIGALRM\n");
    if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
        fprintf(stderr, "Reset SIGALRM error.\n");
    }
}

int main (int argc, char *argv[])
{
    sigset_t newmask, oldmask, pendmask;

    if (signal(SIGALRM, int_handler) == SIG_ERR) {
        fprintf(stderr, "Signal error.\n");
        return  (-1);
    }

    sigemptyset(&newmask);
    sigaddset(&newmask, SIGALRM);
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
        fprintf(stderr, "Sigprocmask error.\n");
        return  (-1);
    }

    alarm(2);
    sleep(5);
    sigpending(&pendmask);
    if (sigismember(&pendmask, SIGALRM) == 1) {
        fprintf(stdout, "Signal SIGALRM pending.\n");
    } else {
        fprintf(stdout, "SIGALRM no pending.\n");
    }

    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
        fprintf(stderr, "Resume mask error.\n");
        return (-1);
    }

    sleep(5);
    return  (0);
}

在 SylixOS Shell 下运行程序,结果如下:

#./SignalSet
Signal SIGALRM pending.
Signal SIGALRM

从运行结果可以看出,SIGALRM 信号被屏蔽了,但是当恢复非屏蔽状态时,SIGALRM 信号处理函数得到了执行,因此说明信号被屏蔽并没有将信号丢弃,当恢复非屏蔽状态时,信号会继续被递送。

文档内容是否对您有所帮助?
有帮助
没帮助