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.CUOXin.com/nufangrensheng/p/3515035.html)
act結構的sa_flags字段指定對信號進行處理的各個選項。
表10-5 處理每個信號的選項標志(sa_flags)
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/。
新聞熱點
疑難解答