14_sigaction 函数注册信号处理函数

sigaction函数
   包含头文件<signal.h>
   功能:sigaction函数用于改变进程接收到特定信号后的行为。
   原型:
int  sigaction(int signum,const struct sigaction *act,const struct sigaction *old);
   参数
   该函数的第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一 个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)
   第二个参数是指向结构sigaction的一个实例的指针,在结构 sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理
   第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。
   返回值:函数成功返回0,失败返回-1
    signal(num., handle)

sigaction结构体
   第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
struct sigaction {
    void (*sa_handler)(int);   //信号处理程序 不接受额外数据
    void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序 能接受额外数据,和sigqueue配合使用 
    sigset_t sa_mask; //
    int sa_flags; //影响信号的行为 SA_SIGINFO表示能接受数据
    void (*sa_restorer)(void); //废弃
};
注意1:回调函数句柄sa_handler、sa_sigaction只能任选其一。
注意2:The sigaction structure is defined as something like 思考如何测试?
    struct sigaction {
      void (*sa_handler)(int);
      void (*sa_sigaction)(int, siginfo_t *, void *);
      sigset_t sa_mask;
      int sa_flags;
      void (*sa_restorer)(void);
    }
#if 0
siginfo_t {
           int      si_signo;     /* Signal number */
           int      si_errno;     /* An errno value */
           int      si_code;      /* Signal code */
           int      si_trapno;    /* Trap number that caused
                                     hardware-generated signal
                                     (unused on most architectures) */
           pid_t    si_pid;       /* Sending process ID */
           uid_t    si_uid;       /* Real user ID of sending process */
           int      si_status;    /* Exit value or signal */
           clock_t  si_utime;     /* User time consumed */
           clock_t  si_stime;     /* System time consumed */
           sigval_t si_value;     /* Signal value */   注意
           int      si_int;       /* POSIX.1b signal */  旧时设计
           void    *si_ptr;       /* POSIX.1b signal */
           int      si_overrun;   /* Timer overrun count;
                                     POSIX.1b timers */
           int      si_timerid;   /* Timer ID; POSIX.1b timers */
           void    *si_addr;      /* Memory location which caused fault */
           long     si_band;      /* Band event (was int in
                                     glibc 2.3.2 and earlier) */
           int      si_fd;        /* File descriptor */
           short    si_addr_lsb;  /* Least significant bit of address
                                     (since Linux 2.6.32) */
           void    *si_call_addr; /* Address of system call instruction
                                     (since Linux 3.5) */
           int      si_syscall;   /* Number of attempted system call
                                     (since Linux 3.5) */
           unsigned int si_arch;  /* Architecture of attempted system call
                                     (since Linux 3.5) */
           }
#endif
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

//为某个信号设置捕捉函数
#if 1
//第一个回调函数的使用
void handler(int sig)
{
    if (sig == SIGINT)
    {
        printf("handler recv a sig=%d\n", sig);
    }
}

//第二个回调函数的使用,注意第二个结构体的成员
 void handler2(int num, siginfo_t *info, void * p)
 {
    printf("handler 2 recv sig :%d\n", num);
 }

 void test()
 {
    struct sigaction act;
    act.sa_handler = handler;
    //act.sa_sigaction = handler2;//只能使用其中的一个
    sigaction(SIGINT, &act, NULL);
    for (;;)
    {
        sleep(1);
    }
 }
#endif
/*
信号捕捉特性:
1.  进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。
    当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。
    而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆来指定。而是用sa_mask来指定。
    调用完信号处理函数,再恢复为☆ 
2.  XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
3.  阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
*/

/*
    测试sigaction结构体sa_mask参数的作用:
    验证sa_mask在捕捉函数执行期间的屏蔽作用.
    当执行SIGINT信号处理函数期间,多次收到SIGQUIT信号都将被屏蔽(阻塞)
  SIGINT信号处理函数处理完,立刻解除对SIGQUIT信号的屏蔽,
  由于没有捕捉该信号,将立刻执行该信号的默认动作,程序退出
*/

#if 1
 void handler(int sig)
{
    printf("recv a sig=%d 信号处理函数执行的时候,阻塞sa_mask中的信号\n", sig);
    sleep(8);//模拟处理事件很长
}

 void test()
 {
    struct sigaction act;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);//注意:sa_mask 仅在处理函数被调用期间屏蔽生效,是临时性设置。
    sigaddset(&act.sa_mask, SIGQUIT);//将SIGQUIT加入到信号集sa_mask中,被阻塞(信号处理函数执行的过程中SIGQUIT被阻塞)。

    //注意:SIGQUIT信号最终还会抵达
    /*将SIGQUIT加入信号屏蔽集,这就导致,在调用信号处理函数期间
     *不仅不响应SIGINT信号本身,还不响应SIGQUIT*/
    act.sa_flags = 0;//表使用默认属性

    if(sigaction(SIGINT, &act, NULL) < 0){//注册信号SIGINT捕捉函数
        ERR_EXIT("sigaction error");
    }
    for (;;)
    {
        sleep(1);
    }
 }
/*
    运行结果:
    hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
    ^\Quit (core dumped)
    hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
    ^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    ^\Quit (core dumped)
    hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
    ^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    ^C^\recv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    Quit (core dumped
*/
#endif
/*
    验证在信号处理函数执行期间,该信号多次递送,那么只在处理函数之行结束后,处理一次。
*/
#if 0
 void handler(int sig)
{
    printf("recv a sig=%d 信号处理函数执行的时候,阻塞sa_mask中的信号\n", sig);
    sleep(5);//模拟信号处理函数执行很长时间
    printf("end of handler\n");
}

 void test()
 {
    struct sigaction act, oldact;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);//不屏蔽任何信号
    act.sa_flags = 0;

    if(sigaction(SIGINT, &act, &oldact) < 0){//注册信号SIGINT捕捉函数
        ERR_EXIT("sigaction error");
    }
    while(1);
 }
 /*
     hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
    ^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    ^C^C^Cend of handler
    recv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    end of handler
 */
#endif
/*
    自动屏蔽本信号,调用完毕后屏蔽自动解除
*/
#if 1
 void handler(int sig)
{
    printf("recv a sig=%d 信号处理函数执行的时候,阻塞sa_mask中的信号\n", sig);
    sleep(5);//模拟信号处理函数执行很长时间
    printf("end of handler\n");
}

 void test()
 {
    struct sigaction act, oldact;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);//不屏蔽任何信号
    act.sa_flags = 0;

    if(sigaction(SIGINT, &act, &oldact) < 0){//注册信号SIGINT捕捉函数
        ERR_EXIT("sigaction error");
    }

    //pause();//是调用进程挂起,只有信号处理函数返回了,pause才返回
    sleep(1);//也可以,保证cpu有机会去执行信号处理函数
    if(sigaction(SIGINT, &oldact, NULL) < 0){//注册信号SIGINT捕捉函数
        ERR_EXIT("sigaction error");
    }

    for (;;)
    {
        sleep(1);
    }
 }
 /*
 运行结果
     hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm02_sigaction
    ^Crecv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    ^C^C^C^C^C^C^C^C^Cend of handler
    recv a sig=2 信号处理函数执行的时候,阻塞sa_mask中的信号
    end of handler
    ^C
    hzmct@U-64:/study/linuxtest/day02/02signal$

 */
#endif


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

    return 0;
}

你可能感兴趣的:(linux系统调用)