sigaction函數(shù)的功能是檢查或修改與指定信號(hào)相關(guān)聯(lián)的處理動(dòng)作(或同時(shí)執(zhí)行這兩種操作)。
#include <signal.h>int sigaction( int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);返回值:若成功則返回0,若出錯(cuò)則返回-1
其中,參數(shù)signo是要檢測(cè)或修改其具體動(dòng)作的信號(hào)編號(hào)。若act指針非空,則要修改其動(dòng)作。如果oact指針非空,則系統(tǒng)經(jīng)由oact指針返回該信號(hào)的上一個(gè)動(dòng)作。此函數(shù)使用下列結(jié)構(gòu):
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 *);};
當(dāng)更改信號(hào)動(dòng)作時(shí),如果sa_handler字段包含一個(gè)信號(hào)捕捉函數(shù)的地址(與常量SIG_IGN或SIG_DFL相對(duì)),則sa_mask字段說明了一個(gè)信號(hào)集,在調(diào)用該信號(hào)捕捉函數(shù)之前,這一信號(hào)集要加到進(jìn)程的信號(hào)屏蔽字中。僅當(dāng)從信號(hào)捕捉函數(shù)返回時(shí)再將進(jìn)程的信號(hào)屏蔽字復(fù)位為原先值。這樣,在調(diào)用信號(hào)處理程序時(shí)就能阻塞某些信號(hào)。在信號(hào)處理程序被調(diào)用時(shí),操作系統(tǒng)建立的新信號(hào)屏蔽字包括正被遞送的信號(hào)。因此保證了在處理一個(gè)給定的信號(hào)時(shí),如果這種信號(hào)再次發(fā)生,那么它會(huì)被阻塞到對(duì)前一個(gè)信號(hào)的處理結(jié)束為止。
一旦對(duì)給定的信號(hào)設(shè)置了一個(gè)動(dòng)作,那么在調(diào)用sigaction顯式地改變它之前,該設(shè)置就一直有效。(早期版本并非如此,而是:在進(jìn)程每次接到信號(hào)對(duì)其進(jìn)行處理時(shí),隨即將該信號(hào)動(dòng)作復(fù)位為默認(rèn)值。見http://www.CUOXin.com/nufangrensheng/p/3515035.html)
act結(jié)構(gòu)的sa_flags字段指定對(duì)信號(hào)進(jìn)行處理的各個(gè)選項(xiàng)。
表10-5 處理每個(gè)信號(hào)的選項(xiàng)標(biāo)志(sa_flags)
sa_sigaction字段是一個(gè)替代的信號(hào)處理程序,當(dāng)在sigaction結(jié)構(gòu)中使用了SA_SIGINFO標(biāo)志時(shí),使用該信號(hào)處理程序。對(duì)于sa_sigaction字段和sa_handler字段這兩者,其實(shí)現(xiàn)可能使用同一存儲(chǔ)區(qū),所以應(yīng)用程序只能一次使用這兩個(gè)字段中的一個(gè)。
通常,按下列方式調(diào)用信號(hào)處理程序:
void handler(int signo);
但是,如果設(shè)置了SA_SIGINFO標(biāo)志,那么按下列方式調(diào)用信號(hào)處理程序:
void handler(int signo, siginfo_t *info, void *context);
siginfo_t結(jié)構(gòu)包含了信號(hào)產(chǎn)生原因的有關(guān)信息。該結(jié)構(gòu)的大致樣式如下所示:
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 */};
各種信號(hào)的si_code值(包括上面的相關(guān)數(shù)據(jù)結(jié)構(gòu)和標(biāo)志選項(xiàng)),可通過man sigaction命令進(jìn)行查看。
若信號(hào)是SIGCHLD,則將設(shè)置si_pid、si_status和si_uid字段。
若信號(hào)是SIGILL或SIGSEGV,則si_addr包含造成故障的根源地址,盡管該地址可能并不準(zhǔn)確。
若信號(hào)是SIGPOLL,那么si_band字段將包含STREAMS消息的優(yōu)先級(jí)(priority band),該消息產(chǎn)生POLL_IN、POLL_OUT或POLL_MSG事件。
si_errno字段包含錯(cuò)誤編號(hào),它對(duì)應(yīng)于引發(fā)信號(hào)產(chǎn)生的條件,并由實(shí)現(xiàn)定義。
信號(hào)處理程序的context參數(shù)是無類型指針,它可被強(qiáng)制轉(zhuǎn)換為ucntext_t結(jié)構(gòu)類型,用于標(biāo)識(shí)信號(hào)傳遞時(shí)進(jìn)程的上下文。
實(shí)例:signal函數(shù)
現(xiàn)在用sigaction實(shí)現(xiàn)signal函數(shù)。很多平臺(tái)都是這樣做的。
程序清單10-12 用sigaction實(shí)現(xiàn)signal函數(shù)
#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函數(shù)初始化act結(jié)構(gòu)的sa_mask成員。不能保證:act.sa_mask = 0;會(huì)做同樣的事情。
對(duì)除SIGALRM以外的所有信號(hào),我們都有嘗試設(shè)置SA_RESTART標(biāo)志,于是被這些信號(hào)中斷的系統(tǒng)調(diào)用都能自動(dòng)重啟動(dòng)。不希望重啟動(dòng)由SIGALRM信號(hào)中斷的系統(tǒng)調(diào)用的原因是:我們希望對(duì)I/O操作可以設(shè)置時(shí)間限制。
實(shí)例:signal_intr函數(shù)
程序清單10-13是signal函數(shù)的另一種版本,它力圖阻止任何被中斷的系統(tǒng)調(diào)用重啟動(dòng)。
程序清單10-13 signal_intr函數(shù)
#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);}
如果系統(tǒng)定義了SA_INTERRUPT標(biāo)志,那么為了提高可移植性,我們?cè)趕a_flags中增加該標(biāo)志,這樣也就阻止了被中斷的系統(tǒng)調(diào)用重啟動(dòng)。
本篇博文內(nèi)容摘自《UNIX環(huán)境高級(jí)編程》(第二版),僅作個(gè)人學(xué)習(xí)記錄所用。關(guān)于本書可參考:http://www.apuebook.com/。
新聞熱點(diǎn)
疑難解答
圖片精選