Linux下signaction系统调用

本文详细介绍了在Unix系统中如何使用signal和sigaction系统调用来设置信号处理函数,包括信号处理函数的设置、信号掩码的作用及如何使用SA_RESTART等信号标志。通过代码示例展示了信号处理的过程。

1.signal系统调用

要为一个信号设置处理函数,可以使用signal系统调用:

#include<signal.h>
_sighandler_t signal(int sig, _sighandler_t _handler)

sig参数指出要捕获的信号类型。_handler参数是_sighandler_t类型的函数指针,用于指定信号sig的处理函数。signal函数成功时返回一个函数指针,该函数指针的类型也是_sighandler_t类型。这个返回值是前一次调用signal函数时传入的函数指针,或者是信号sig对应的默认处理函数指针SIG_DEF(如果是第一次调用signal的话)。

signal系统调用出错时返回SIG_ERR,并设置errno。

2.sigaction系统调用

设置信号处理函数更加健壮的接口是如下系统调用:

#include<signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)

sig参数指出要捕获的信号类型,act参数指定新的信号处理方式,oact参数则输出信号先前的处理方式(如果不为NULL的话)。act和oact都是sigaction结构体类型的指针,sigaction结构体描述了信号处理细节,其定义如下:

struct sigaction
{

#ifdef __USE_POSIX199309
    union
    {
        _sighandler_t sa_handler;
        void (*sa_sigaction)(int, siginfo_t*, void *);

    }_sigaction_handler;

#define sa_hander    __sigaction_handler.sa_handler
#define sa_sigaction    __sigaction_handler.sa_sigaction
#else
    _sigaction_handler sa_handler;
#endif

    _sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
};

该结构体中的sa_handler成员指定信号处理函数。sa_mask成员设置进程的信号掩码(确切地说是在原有进程的信号掩码基础上增加信号掩码),以指定哪些信号不能发送给本进程。sa_mask是信号集sigset_t(_sigset_t的同义词)类型,该类型指定一组信号。sa_flags成员用于设置程序收到信号时的行为:

  1. SA_RESTART用在为某个信号设置信号处理函数时,给该信号设置的一个标记。一般情况下 ,进程正在执行某个系统调用,那么在该系统调用返回前信号是不会被递送的。但慢速系统调用除外,如读写终端、网络、磁盘,以及wait和pause。这些系 统调用都会返回-1,errno置为EINTR当系统调用被中断时,我们可以选择使用循环再次调用,或者设置重新启动该系统调用 (SA_RESTART)。一旦给信号设置了SA_RESTART标记,那么当执行某个阻塞系统调用时,收到该信号时,进程不会返回,而是重新执行该系统调用。
  2. SA_NOCLDSTOP:如果参数signum为SIGCHLD,当子进程被中断时,并不通知父进程。

  3.  SA_NOCLDWATI:当信号为SIGCHLD,时可避免子进程僵死。

  4.  SA_NODEFER:当信号处理函数正在进行时,不堵塞对于信号处理函数自身信号功能。

  5.  SA_NOMASK:同SA_NODEFER,在处理此信号前允许信号再次递送,相当于中断嵌套。

  6.  SA_ONESHOT:当用户注册的信号处理函数被执行过一次后,该信号的处理函数被设为系统默认的处理函数。

  7.  SA_RESETHAND:同SA_ONESHOT

  8.  SA_RESTART:是本来不能重新于运行的系统调用自动重新运行。

  9.  SA_SIGINFO:如果设置了该标志,则信号处理函数由三参数的sa_sigaction指定而不是sa_handler指定。

3.关于信号掩码字段

sa_mask声明一个信号集,在调用信号捕捉函数之前,该信号集会增加到进程的信号掩码中。新的信号掩码会自动包含正在处理的信号(sa_flags未指定SA_NODEFER和SA_NOMASK)掩码集中。当从信号函数返回时,进程掩码会恢复原来的值。因此当处理一个给定信号时,如果这种信号再次发生,那么它会阻塞直到本次信号处理结束为止。若这种信号发生了多次,则对于不可靠信号,他只会阻塞一次,即本次信号处理结束以后会再处理一次(相当于丢失了信号),对于可靠信号(实时信号),则会被阻塞多次,即信号不会丢失,信号发生了多少次就会调用处理函数多少次。

可以通过下面这段代码示例来进行实验(注意SIGALRM是不可靠信号):

#include<signal.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>


void sig_handler(int sig)
{
        sleep(5);
        printf("call signal handler.\n");
//      alarm(1);       
}

void addsig(int sig)
{
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sig_handler;
        sa.sa_flags |= SA_RESTART;
        sigfillset(&sa.sa_mask);
        assert(sigaction(sig, &sa, NULL) != -1);
}

int main(int argc, char *argv[])
{
        addsig(SIGALRM);

        alarm(3);
//      sleep(5);
        alarm(5);
        alarm(6);
//      sleep(2);
//      alarm(3);
        printf("go on\n");
//      sleep(30);
        while(1){}

        return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值