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 <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章