Linux訊號函數之sigaction系統調用__Oracle

來源:互聯網
上載者:User

目錄

1. sigaction函數詳解 1.1 結構體siginfo_t詳解 1.2 sa_sigaction函數指標中的第3個參數void * 講解

1. sigaction函數詳解

sigaction函數相對於signal函數更加健壯,而且功能也更強大些,其函數原型為:

 #include <signal.h> int sigaction(int signum, const struct sigaction *act,                struct sigaction *oldact);傳回值:成功: 0       失敗:-1 錯誤原因置於errno中


對於參數:
- signum: 指要捕獲的訊號類型,支援linux系統上的64種訊號(除了SIGKILL和SIGSTOP)
- 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_handler __sigaction_handler.sa_handler# define sa_sigaction   __sigaction_handler.sa_sigaction#else    __sighandler_t sa_handler;#endif    __sigset_t sa_mask;    int sa_flags;    void (*sa_restorer) (void);  };


對於結構體struct sigaction中各成員的詳細描述:
- sa_hander: 指定訊號處理函數,此參數和signal()函數中的參數handler相同,此參數主要用來對訊號舊的安裝函數signal()處理形式的支援。
- sa_sigaction: 為新的訊號安裝機制。處理函數被調用的時候,不但可以得到訊號的編號,而且可以獲悉被調用的原因以及產生問題的內容相關的相關資訊。
%%%% 注意:sa_hander和sa_sigaction是互斥的,若執行sa_hander,就無法去執行sa_sigaction;反之亦然 %%%%
- sa_mask: 用來設定進程的訊號掩碼,也就是說在進程原有的訊號掩碼基礎上增加訊號掩碼,以指定哪些訊號不能夠發送給本進程。sa_mask是訊號集sigset_t類型,該類型指定一組訊號。
- sa_restorer: 該成員已經過時,不要使用。
- sa_flags: 用來設定程式收到訊號時的行為。其可選值如下表:

選項 含義
SA_NOCLDSTOP 如果sigaction的sig參數是SIGCHLD,則設定該標誌表示子進程暫停時不產生
SA_NOCLDWAIT 如果sigaction的sig參數是SIGCHLD,則設定該標誌表示子進程結束時不產生殭屍進程
SA_SIGINFO 使用sa_sigaction作為訊號處理函數(而不是sa_handler),它給進程提供更多相關資訊
SA_ONSTACK 調用有sigaltstack函數色或者的可選訊號棧上的訊號處理函數
SA_RESTART 重新調用被該訊號終止的系統調用
SA_NODEFER 當接收到訊號並進入其訊號處理函數時,不屏蔽該訊號。預設情況下,我們期望進程在處理一個訊號時不再接收到同種訊號,否則引起一些競態條件
SA_RESETHAND 訊號處理函數執行完成以後,回複訊號的預設處理方式
SA_INTERRUPT 終端系統調用
重點:SA_SIGINFO 


代碼1:

/************************************************************************* * File Name: sigaction.c * Author:    The answer * Function:  Other         * Mail:      2412799512@qq.com  * Created Time: 2018年04月29日 星期日 05時06分43秒 ************************************************************************/#include <stdio.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#include <string.h>void sig_handler(int signum,siginfo_t *info,void *data){    printf("receive signal [%d]\n",signum);    sleep(5);}int main(int argc,char **argv){    if(argc <2 )    {        fprintf(stderr,"Usage:%s signum.\n",argv[0]);        return -1;    }    struct sigaction act;    int signum ;    signum = atoi(argv[1]);    sigemptyset(&act.sa_mask);    act.sa_sigaction = sig_handler;    act.sa_flags | SA_SIGINFO;    if(sigaction(signum,&act,NULL) < 0)    {        fprintf(stderr,"sigaction err.\n");        return -2;    }    while(1)    {        sleep(2);        puts("wait for the sigal.");    }    return 0;}

該程式會每隔2秒鐘列印一次:wait for the sigal. 此時若linux終端按下按鍵組合:ctrl+c,則會調用使用者自訂的函數列印:^Creceive signal [2] 然後繼續每隔2秒鐘列印一次wait for the sigal. 若在終端按下按鍵組合:ctrl + \,則程式退出並終止。

2018-05-06 補充:

上面在講解結構體sigaction時提到過該結構體成員sa_flags用來說明並指定該sigaction函數中安裝資訊的函數是舊的signal還是最新的。若為sa_sigaction新的訊號函數,則:sa_flags | SA_SIGINFO;(“|”或—>位元運算);若想要使用舊的sa_handle,則指定sa_flags = 0;便可。
代碼2:

/************************************************************************* * File Name: sigaction.c * Author:    The answer * Function:  Other         * Mail:      2412799512@qq.com  * Created Time: 2018年05月06日 星期日 14時48分03秒 ************************************************************************/#include <stdio.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#include <string.h>void sig_handler(int signum,siginfo_t *info,void *data){    printf("receive signal [%d]\n",signum);    sleep(5);}void oldSig_handler(int signo){    printf("oldSig_handler receive signal [%d]\n",signo);    sleep(2);}int main(int argc,char **argv){    if(argc <2 )    {        fprintf(stderr,"Usage:%s signum.\n",argv[0]);        return -1;    }    struct sigaction act;    int signum ;    signum = atoi(argv[1]);    sigemptyset(&act.sa_mask);    act.sa_handler = oldSig_handler;  //將oldSig_handler函數地址賦給sa_hanlder函數指標    act.sa_flags = 0; //指定sa_flags = 0;    if(sigaction(signum,&act,NULL) < 0)    {        fprintf(stderr,"sigaction err.\n");        return -2;    }    while(1)    {        sleep(2);        puts("wait for the sigal.");    }    return 0;}

該程式實現的功能和”代碼1”實現的功能相同。見“代碼1”中詳細描述。
1.1 結構體siginfo_t詳解

前面說過sigaction是sigal函數的加強版。因此sigaction函數肯定會有sigal函數沒有的功能,雖然“代碼1”中用了sa_sigaction新函數,但是我只使用了第一個參數,訊號的編號(若只是用這一個參數,和直接使用sigal沒有任何區別)。

man sigaction可以看到sgaction機構體中的成員sa_sigaction是一個函數指標,該函數指標指向的函數中公有3個參數,如下:
void (sa_sigaction)(int, siginfo_t , void *);

其中siginfo_t是一個結構體,其定義如下:

typedef struct  {    int si_signo;       /* 訊號  */    int si_errno;       /* 錯誤值,見<error.h>中*/    int si_code;        /* 訊號代碼  *//*************** union聯合體類型  ******************/    union      {    int _pad[__SI_PAD_SIZE];     /* kill().  */    struct      {        __pid_t si_pid; /* 發送進程的ID.  */        __uid_t si_uid; /* 發送過程的真實ID.  */      } _kill;    /* POSIX.1b timers.  */    struct      {        int si_tid;     /* 定時器ID.  */        int si_overrun; /* 超額計數.  */        sigval_t si_sigval; /* 訊號值.  */      } _timer;    /* POSIX.1b signals.  */    struct      {        __pid_t si_pid; /*  發送進程的ID.  */        __uid_t si_uid; /* 發送過程的真實ID.  */        sigval_t si_sigval; /* 訊號值  */      } _rt;    /* SIGCHLD.  */    struct      {        __pid_t si_pid; /* 發送進程的ID.  */        __uid_t si_uid; /* 發送過程的真實ID.  */        int si_status;  /* 退出值或訊號.  */        __sigchld_clock_t si_utime;  /* 使用者時間消耗.  */        __sigchld_clock_t si_stime;  /* 系統時間消耗.  */      } _sigchld;    /* SIGILL, SIGFPE, SIGSEGV, SIGBUS.  */    struct      {        void *si_addr;  /* 斷層斷陷/記憶體引用.  */        short int si_addr_lsb;  /* 報告地址的有效LSB.  */      } _sigfault;    /* SIGPOLL.  */    struct      {        long int si_band;   /* SIGPOLL訊號中的band事件. */        int si_fd;   /* 檔案描述符. */      } _sigpoll;    /* SIGSYS.  */    struct      {        void *_call_addr;   /* 使用者調用  */        int _syscall;   /* 觸發系統本機號碼.  */        unsigned int _arch; /* AUDIT_ARCH_的系統調用.  */      } _sigsys;     } _sifields;   // %%%% union範圍 %%%%    /******************************************/  } siginfo_t __SI_ALIGNMENT;

該siginfo_t結構體中內嵌了一個聯合體(又名“共用體”),而該聯合體中嵌套了多個結構體strcut類型。該聯合體union的範圍為:
union { union成員類別 }_sifields,除了這個union聯合體外,該siginfo_t結構體中主要有3個結構體成員:

int si_signo;       /* 訊號  */int si_errno;       /* 錯誤值,見<error.h>中*/int si_code;        /* 訊號代碼 ;si_code是一個值(不是位元遮罩),說明為什麼發送這個訊號 */


si_signo、si_errno和si_code為所有訊號定義。(si_errno通常在Linux上不使用。)結構的其餘部分可能是一個聯合,因此,應該唯讀取對給定訊號有意義的欄位。 1.2 sa_sigaction函數指標中的第3個參數void * 講解

sa_sigaction函數是函數指標,所指向的函數為3個參數,前面已經講解了該形參中的前面2個參數的含義。下面具體講解第3個參數。sa_sigaction指向函數的具體形式:
void
handler(int sig, siginfo_t *info, void *ucontext)
{

}

這是一個指向ucontext_t結構體的指標,轉換為void *類型。該欄位指向的結構包含了訊號上下文。在使用者空間堆棧上儲存的資訊。具體可以去參考:sigreturn(2). 更進一步的資訊在 getcontext(3). 可以看到ucontext_t結構體定義。 但是通常都沒有用到第3個參數 ;

代碼3中用到了sa_sigaction中的第2個參數:並列印了其發送訊號的進程id與真實id。

/************************************************************************* * File Name: sigaction.c * Author:    The answer * Function:  Other         * Mail:      2412799512@qq.com  * Created Time: 2018年04月29日 星期日 05時06分43秒 ************************************************************************/#include <stdio.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>#include <sys/stat.h>#include <stdlib.h>#include <string.h>void sig_handler(int signum,siginfo_t *info,void *data){    printf("main  pid: [%d]\n",getpid());    printf("receive signal [%d]\n",signum);    printf("Signal number [%d]\n",info->si_signo);    printf("Signal code [%d]\n",info->si_code);    printf("Sigal errno [%d]\n",info->si_errno);    printf("Sending process ID [%d]\n",info->si_pid);    printf("Real user ID of sending process [%d]\n",info->si_uid);    printf("SI_USER [%d]\n",SI_USER);    sleep(5);}void oldSig_handler(int signo){    printf("oldSig_handler receive signal [%d]\n",signo);    sleep(2);}int main(int argc,char **argv){    if(argc <2 )    {        fprintf(stderr,"Usage:%s signum.\n",argv[0]);        return -1;    }    struct sigaction act;    int signum ;    signum = atoi(argv[1]);    sigemptyset(&act.sa_mask);    act.sa_sigaction = sig_handler;    act.sa_flags | SA_SIGINFO;    if(sigaction(signum,&act,NULL) < 0)    {        fprintf(stderr,"sigaction err.\n");        return -2;    }    while(1)    {        sleep(2);        puts("wait for the sigal.");    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.