Linux中訊號相關的一個結構體struct sigaction主要在sigaction訊號安裝和sigqueue訊號發送時會用到
該結構位於/usr/include/bits/sigaction.h
在裡面可以找到該結構的描述
/* Structure describing the action to be taken when a signal arrives. */
struct sigaction
{
/* Signal handler. */
#ifdef __USE_POSIX199309
union
{
/* Used if SA_SIGINFO is not set. */
__sighandler_t sa_handler;
/* Used if SA_SIGINFO is set. */
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
/* Additional set of signals to be blocked. */
__sigset_t sa_mask;
/* Special flags. */
int sa_flags;
/* Restore handler. */
void (*sa_restorer) (void);
};
在網上查了一些書料這個結構大概是這樣的
其中,sa_restorer,已淘汰,POSIX不支援它,不應再被使用。
1、聯合資料結構中的兩個元素_sa_handler以及*_sa_sigaction指定訊號關聯函數,即使用者指定的訊號處理函數。除了可以是使用者自訂的處理函數外,還可以為SIG_DFL(採用預設的處理方式),也可以為SIG_IGN(忽略訊號)。
2、由_sa_handler指定的處理函數只有一個參數,即訊號值,所以訊號不能傳遞除訊號值之外的任何資訊;由_sa_sigaction是指定的訊號處理函數帶有三個參數,是為即時訊號而設的(當然同樣支援非即時訊號),它指定一個3參數訊號處理函數。第一個參數為訊號值,第三個參數沒有使用(posix沒有規範使用該參數的標準),第二個參數是指向siginfo_t結構的指標,結構中包含訊號攜帶的資料值,參數所指向的結構如下:
在/usr/include/bits/siginfo.h中是這樣定義的
是不是太複雜了,在網上有一個簡潔版我搬過來用一下
siginfo_t {
int si_signo; /*訊號值,對所有訊號有意義*/
int si_errno; /* errno值,對所有訊號有意義*/
int si_code; /*訊號產生的原因,對所有訊號有意義*/
union{ /*聯合資料結構,不同成員適應不同訊號*/
//確保分配足夠大的儲存空間
int _pad[SI_PAD_SIZE];
//對SIGKILL有意義的結構
struct{
...
}...
... ...
... ...
//對SIGILL, SIGFPE, SIGSEGV, SIGBUS有意義的結構
struct{
...
}...
... ...
}
}
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
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)。
註:很多文獻在闡述該標誌位時都認為,如果設定了該標誌位,就必須定義三參數訊號處理函數。實際不是這樣的,驗證方法很簡單:自己實現一個單一參數訊號處理函數,並在程式中設定該標誌位,可以察看程式的運行結果。實際上,可以把該標誌位看成訊號是否傳遞參數的開關,如果設定該位,則傳遞參數;否則,不傳遞參數。
結構說的也差不多了,其實在我看到這些東西的時候給弄暈了好幾回,簡單的說幾句就是
如果要在某訊號產生時觸發某些動作我們就可以安裝訊號
signal用於安裝不可靠訊號 linux現在是用sigaction實現的
sigaction用於安裝可靠訊號當然他也可以安裝不可靠訊號並且可以附帶更多的資訊
signal安裝訊號時只需傳入2個參數一個是訊號的值 一個是訊號發生時觸發的函數,該函數接受一個整數
sigaction安裝時有3個參數第一個參數是訊號的值,第二個是sigaction結構這個結構說明了訊號發生時調用的函數和其它的一些資訊,主要的成員是sa_handler指定的觸發函數只帶一個參數即訊號的值這和signal調用沒什麼區別,sa_sigaction指定的觸發函數帶有3個參數第一個參數是訊號的值,第二個參數是包函附加資訊的結構siginfo,第三個參數為空白如果要傳遞附加資訊給觸發函數那麼必須將傳給sigaction的第二個參數sigaction結構的sa_flag設為SA_SIGINFO
上面說了那麼多結構體和複雜的很的siginfo,其實siginfo我們在實際應用中並不需要去初始化他或者做什麼,只是在訊號觸發時我們可以從這個結構體中提取一些資訊。
sigaction函數原型:int sigaction(int signo,const struct sigaction *restrict act,struct sigaction *restrict oact);
//第一個參數為訊號編號,第二個是sigaction結構體,第三個一般為NULL。
樣本:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
static void sig_usr(int signum)
{
if(signum == SIGUSR1)
{
printf("SIGUSR1 received\n");
}
else if(signum == SIGUSR2)
{
printf("SIGUSR2 received\n");
}
else
{
printf("signal %d received\n", signum);
}
}
int main(void)
{
char buf[512];
int n;
struct sigaction sa_usr;
sa_usr.sa_flags = 0;
sa_usr.sa_handler = sig_usr; //訊號處理函數
sigaction(SIGUSR1, &sa_usr, NULL);
sigaction(SIGUSR2, &sa_usr, NULL);
printf("My PID is %d\n", getpid());
while(1)
{
if((n = read(STDIN_FILENO, buf, 511)) == -1)
{
if(errno == EINTR)
{
printf("read is interrupted by signal\n");
}
}
else
{
buf[n] = '\0';
printf("%d bytes read: %s\n", n, buf);
}
}
return 0;
}