一,sigaction()
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
sigaction函數用於改變進程接收到特定訊號後的行為。該函數的第一個參數為訊號的值,可以為除SIGKILL及SIGSTOP外的任何一個特定有效訊號(為這兩個訊號定義自己的處理函數,將導致訊號安裝錯誤)。第二個參數是指向結構sigaction的一個執行個體的指標,在結構sigaction的執行個體中,指定了對特定訊號的處理,可以為空白,進程會以預設方式對訊號處理;第三個參數oldact指向的對象用來儲存原來對相應訊號的處理,可指定oldact為NULL。如果把第二、第三個參數都設為NULL,那麼該函數可用於檢查訊號的有效性。
第二個參數最為重要,其中包含了對指定訊號的處理、訊號所傳遞的資訊、訊號處理函數執行過程中應屏蔽掉哪些函數等等。
sigaction結構定義如下:
(*_sa_sigaction)(, siginfo *, * (*sa_restorer)(
其中,sa_restorer,已淘汰,POSIX不支援它,不應再被使用。
1、聯合資料結構中的兩個元素_sa_handler以及*_sa_sigaction指定訊號關聯函數,即使用者指定的訊號處理函數。除了可以是使用者自訂的處理函數外,還可以為SIG_DFL(採用預設的處理方式),也可以為SIG_IGN(忽略訊號)。
2、由_sa_handler指定的處理函數只有一個參數,即訊號值,所以訊號不能傳遞除訊號值之外的任何資訊;由_sa_sigaction是指定的訊號處理函數帶有三個參數,是為即時訊號而設的(當然同樣支援非即時訊號),它指定一個3參數訊號處理函數。第一個參數為訊號值,第三個參數沒有使用(posix沒有規範使用該參數的標準),第二個參數是指向siginfo_t結構的指標,結構中包含訊號攜帶的資料值,參數所指向的結構如下:
typedef si_signo; si_errno; si_code;pid_t si_pid;pid_t si_uid; si_status;clock_t si_utime;clock_t si_stime; **
siginfo_t結構中的聯合資料成員確保該結構適應所有的訊號,比如對於即時訊號來說,則實際採用下面的結構形式:
typedef
結構的第四個域同樣為一個聯合資料結構:
*
採用聯合資料結構,說明siginfo_t結構中的si_value要麼持有一個4位元組的整數值,要麼持有一個指標,這就構成了與訊號相關的資料。在訊號的處理函數中,包含這樣的訊號相關資料指標,但沒有規定具體如何對這些資料進行操作,操作方法應該由程式開發人員根據具體任務事先約定。
sigval結構體:系統調用sigqueue發送訊號時,sigqueue的第三個參數就是sigval聯合資料結構,當調用sigqueue時,該資料結構中的資料就將拷貝到訊號處理函數的第二個參數中。這樣,在發送訊號同時,就可以讓訊號傳遞一些附加資訊。訊號可以傳遞資訊對程式開發是非常有意義的。
siginfo_t.si_value與sigqueue(pid_t pid, int sig, const union sigval val)第三個參數關聯即:
所以通過siginfo_t.si_value可以獲得sigqueue(pid_t pid, int sig, const union sigval val)第三個參數傳遞過來的資料。
如:siginfo_t.si_value.sival_int或siginfo_t.si_value.
訊號參數的傳遞過程可圖示如下:
3、sa_mask指定在訊號處理常式執行過程中,哪些訊號應當被阻塞。預設情況下當前訊號本身被阻塞,防止訊號的嵌套發送,除非指定SA_NODEFER或者SA_NOMASK標誌位,處理常式執行完後,被阻塞的訊號開始執行。
註:請注意sa_mask指定的訊號阻塞的前提條件,是在由sigaction()安裝訊號的處理函數執行過程中由sa_mask指定的訊號才被阻塞。
4、sa_flags中包含了許多標誌位,包括剛剛提到的SA_NODEFER及SA_NOMASK標誌位。另一個比較重要的標誌位是SA_SIGINFO,當設定了該標誌位時,表示訊號附帶的參數可以被傳遞到訊號處理函數中,因此,應該為sigaction結構中的sa_sigaction指定處理函數,而不應該為sa_handler指定訊號處理函數,否則,設定該標誌變得毫無意義。即使為sa_sigaction指定了訊號處理函數,如果不設定SA_SIGINFO,訊號處理函數同樣不能得到訊號傳遞過來的資料,在訊號處理函數中對這些資訊的訪問都將導致段錯誤(Segmentation fault)。
註:很多文獻在闡述該標誌位時都認為,如果設定了該標誌位,就必須定義三參數訊號處理函數。實際不是這樣的,驗證方法很簡單:自己實現一個單一參數訊號處理函數,並在程式中設定該標誌位,可以察看程式的運行結果。實際上,可以把該標誌位看成訊號是否傳遞參數的開關,如果設定該位,則傳遞參數;否則,不傳遞參數。
二,sigqueue()
之前學過kill,raise,alarm,abort等功能稍簡單的訊號發送函數,現在我們學習一種新的功能比較強大的訊號發送函數sigqueue.
#include <sys/types.h>
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval val)
調用成功返回 0;否則,返回 -1。
sigqueue()是比較新的發送訊號系統調用,主要是針對即時訊號提出的(當然也支援前32種),支援訊號帶有參數,與函數sigaction()配合使用。
sigqueue的第一個參數是指定接收訊號的進程ID,第二個參數確定即將發送的訊號,第三個參數是一個聯合資料結構union sigval,指定了訊號傳遞的參數,即通常所說的4位元組值。
typedef union sigval {
int sival_int;
void *sival_ptr;
}sigval_t;
sigqueue()比kill()傳遞了更多的附加資訊,但sigqueue()只能向一個進程發送訊號,而不能發送訊號給一個進程組。如果signo=0,將會執行錯誤檢查,但實際上不發送任何訊號,0值訊號可用於檢查pid的有效性以及當前進程是否有許可權向目標進程發送訊號。
在調用sigqueue時,sigval_t指定的資訊會拷貝到對應sig 註冊的3參數訊號處理函數的siginfo_t結構中,這樣訊號處理函數就可以處理這些資訊了。由於sigqueue系統調用支援發送帶參數訊號,所以比kill()系統調用的功能要靈活和強大得多。
三,sigqueue與sigaction應用執行個體
執行個體一:利用sigaction安裝SIGINT訊號
#include <unistd.h><sys/stat.h><sys/wait.h><sys/types.h><fcntl.h><stdlib.h><stdio.h><errno.h><.h><signal.h> ERR_EXIT(m) \ ( handler( main( argc, *=&= (sigaction(SIGINT, &act, NULL) < handler(
結果:
<sys/stat.h><sys/wait.h><sys/types.h><fcntl.h><stdlib.h><stdio.h><errno.h><.h><signal.h> ERR_EXIT(m) \ ( handler( main( argc, * =&= (sigaction(sig, &act, &oldact) < handler(
結果:
<sys/stat.h><sys/wait.h><sys/types.h><fcntl.h><stdlib.h><stdio.h><errno.h><.h><signal.h> ERR_EXIT(m) \ ( handler( main( argc, *=&&= (sigaction(SIGINT, &act, NULL) < =&= (sigaction(SIGQUIT, &act2, NULL) < handler((sig == (sig ==
結果:
<unistd.h><signal.h><stdlib.h> sighandler( signo, siginfo_t *info, * main(=&= SA_SIGINFO; (sigaction(SIGINT,&act,NULL) == -= (sigqueue(getpid(),SIGINT,mysigval) == - sighandler( signo, siginfo_t *info, * printf(,info->,info->
結果:
<unistd.h><signal.h><stdlib.h> sighandler( signo, siginfo_t *info, * main(=&= SA_SIGINFO; (sigaction(SIGINT,&act,NULL) == - sighandler( signo, siginfo_t *info, * printf(,info->,info->
發送端:
#include <stdio.h><unistd.h><signal.h><stdlib.h> main( argc, **(argc != ,argv[= atoi(argv[= (sigqueue(pid,SIGINT,mysigval) == -
結果:
由圖可知接收成功