信號之sigaction函數


sigaction函數的功能是檢查或修改與指定信號相關聯的處理動作(或同時執行這兩種操作)。

#include <signal.h>
int sigaction( int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
返回值:若成功則返回0,若出錯則返回-1

其中,參數signo是要檢測或修改其具體動作的信號編號。若act指針非空,則要修改其動作。如果oact指針非空,則系統經由oact指針返回該信號的上一個動作。此函數使用下列結構:

struct sigaction {
    void    (*sa_handler)(int);    /* addr of signal handler, or SIG_IGN, or SIG_DFL */
    sigset_t    sa_mask;           /* additional signals to block */
    int    sa_flags;               /* signal options */

    /* alternate handler */
    void    (*sa_sigaction)(int, siginfo_t *, void *);
};

當更改信號動作時,如果sa_handler字段包含一個信號捕捉函數的地址(與常量SIG_IGN或SIG_DFL相對),則sa_mask字段說明了一個信號集,在調用該信號捕捉函數之前,這一信號集要加到進程的信號屏蔽字中。僅當從信號捕捉函數返回時再將進程的信號屏蔽字復位為原先值。這樣,在調用信號處理程序時就能阻塞某些信號。在信號處理程序被調用時,操作系統建立的新信號屏蔽字包括正被遞送的信號。因此保證了在處理一個給定的信號時,如果這種信號再次發生,那么它會被阻塞到對前一個信號的處理結束為止。

一旦對給定的信號設置了一個動作,那么在調用sigaction顯式地改變它之前,該設置就一直有效。(早期版本並非如此,而是:在進程每次接到信號對其進行處理時,隨即將該信號動作復位為默認值。見http://www.cnblogs.com/nufangrensheng/p/3515035.html

act結構的sa_flags字段指定對信號進行處理的各個選項。

                                                        表10-5 處理每個信號的選項標志(sa_flags)

2012082515302617

sa_sigaction字段是一個替代的信號處理程序,當在sigaction結構中使用了SA_SIGINFO標志時,使用該信號處理程序。對於sa_sigaction字段和sa_handler字段這兩者,其實現可能使用同一存儲區,所以應用程序只能一次使用這兩個字段中的一個。

通常,按下列方式調用信號處理程序:

void handler(int signo);

但是,如果設置了SA_SIGINFO標志,那么按下列方式調用信號處理程序:

void handler(int signo, siginfo_t *info, void *context);

siginfo_t結構包含了信號產生原因的有關信息。該結構的大致樣式如下所示:

struct siginfo {
    int      si_signo;        /* signal number */
    int      si_errno;        /* if nonzero, errno value from <errno.h> */
    int      si_code;         /* additional info (depends on signal) */
    pid_t    si_pid;          /* sending process ID */
    uid_t    si_uid;          /* sending process real user ID */
    void    *si_addr;         /* address that caused the fault */
    int      si_status;       /* exit value or signal number */
    long     si_band;         /* band number for SIGPOLL */
    /* possibly other fields also */
};

 

各種信號的si_code值(包括上面的相關數據結構和標志選項),可通過man sigaction命令進行查看。

若信號是SIGCHLD,則將設置si_pid、si_status和si_uid字段。

若信號是SIGILL或SIGSEGV,則si_addr包含造成故障的根源地址,盡管該地址可能並不准確。

若信號是SIGPOLL,那么si_band字段將包含STREAMS消息的優先級(priority band),該消息產生POLL_IN、POLL_OUT或POLL_MSG事件。

si_errno字段包含錯誤編號,它對應於引發信號產生的條件,並由實現定義。

信號處理程序的context參數是無類型指針,它可被強制轉換為ucntext_t結構類型,用於標識信號傳遞時進程的上下文。

 

 實例:signal函數

現在用sigaction實現signal函數。很多平台都是這樣做的。

程序清單10-12 用sigaction實現signal函數

#include "apue.h"

/* Reliable version of signal(), using POSIX sigaction(). */
Sigfunc *
signal(int signo, Sigfunc *func)
{
    struct sigaction    act, oact;
    
    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if(signo == SIGALRM)
    {
#ifdef    SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;
#endif
    }
    else
    {
#ifdef    SA_RESTART
        act.sa_flags |= SA_RESTART;
#endif
    }
    if(sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

注意,必須用sigemptyset函數初始化act結構的sa_mask成員。不能保證:act.sa_mask = 0;會做同樣的事情。

對除SIGALRM以外的所有信號,我們都有嘗試設置SA_RESTART標志,於是被這些信號中斷的系統調用都能自動重啟動。不希望重啟動由SIGALRM信號中斷的系統調用的原因是:我們希望對I/O操作可以設置時間限制。

實例:signal_intr函數

程序清單10-13是signal函數的另一種版本,它力圖阻止任何被中斷的系統調用重啟動。

程序清單10-13 signal_intr函數

#include "apue.h"

Sigfunc *
signal_intr(int signo, Sigfunc *func)
{
    struct sigaction     act, oact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef    SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    if(sigaction(signo, &act, &oact) < 0)
        return(SIG_ERR);
    return(oact.sa_handler);
}

 

如果系統定義了SA_INTERRUPT標志,那么為了提高可移植性,我們在sa_flags中增加該標志,這樣也就阻止了被中斷的系統調用重啟動。

 

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關於本書可參考:http://www.apuebook.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM