linux訊號機制之sigaction結構體淺析,signal 函數,訊號捕捉  

來源:互聯網
上載者:User
訊號安裝函數sigaction(int signum,const struct sigaction *act,struct sigaction *oldact)的第二個參數是一個指向sigaction結構的指標(結構體名稱與函數名一樣,千萬別弄混淆了)。在結構sigaction的執行個體中,指定了對特定訊號的處理,訊號所傳遞的資訊,訊號處理函數執行過程中應屏蔽掉哪些函數等。當然,此指標也可以為NULL,進程會以預設處理訊號。以下就簡單介紹一下sigaction結構以及一般的用法。

        對於核心標頭檔而言,struct sigaction 結構體定義在kernel/include/asm/signal.h,此標頭檔又被kernel/include/linux/signal.h包含。
        對於使用者空間的標頭檔而言,struct sigaction定義在 /usr/include/bits/sigaction.h,此標頭檔又被/usr/include/signal.h包含,所以應用程式中如果用到此結構,只要#include 即可。注意核心中的定義和應用程式中的定義是不一樣的,核心空間的sigaction結構只支援函數類型為 __sighandler_t的訊號處理函數,不能處理訊號傳遞的額外資訊。具體定義如下:

……
/* Type of a signal handler.   */
typedef void (*__sighandler_t)(int);

……
#ifdef __KERNEL__
struct old_sigaction {
          __sighandler_t sa_handler;
         old_sigset_t sa_mask;
         unsigned long sa_flags;
         void (*sa_restorer)(void);
};

struct sigaction {
         __sighandler_t sa_handler;
        unsigned long sa_flags;
        void (*sa_restorer)(void);
        sigset_t sa_mask;   /* mask last for extensibility */
};

struct k_sigaction {
        struct sigaction sa;
};

#else
/* Here we must cater to libcs that poke about in kernel headers.   */

struct sigaction {
          union {
                  __sighandler_t _sa_handler;
                  void (*_sa_sigaction)(int, struct siginfo *, void *);
          } _u;
          sigset_t sa_mask;
          unsigned long sa_flags;
          void (*sa_restorer)(void);
};

#define sa_handler   _u._sa_handler
#define sa_sigaction _u._sa_sigaction

#endif /* __KERNEL__ */

sa_handler的原型是一個參數為int,傳回型別為void的函數指標。參數即為訊號值,所以訊號不能傳遞除訊號值之外的任何資訊;

sa_sigaction的原型是一個帶三個參數,類型分別為int,struct siginfo *,void *,傳回型別為void的函數指標。第一個參數為訊號值;第二個參數是一個指向struct siginfo結構的指標,此結構中包含訊號攜帶的資料值;第三個參數沒有使用。

sa_mask指定在訊號處理常式執行過程中,哪些訊號應當被阻塞。預設當前訊號本身被阻塞。

sa_flags包含了許多標誌位,比較重要的一個是SA_SIGINFO,當設定了該標誌位時,表示訊號附帶的參數可以傳遞到訊號處理函數中。即使sa_sigaction指定訊號處理函數,如果不設定SA_SIGINFO,訊號處理函數同樣不能得到訊號傳遞過來的資料,在訊號處理函數中對這些資訊的訪問都將導致段錯誤。

sa_restorer已淘汰,POSIX不支援它,不應再使用。

        因此,當你的訊號需要接收附加資訊的時候,你必須給sa_sigaction賦訊號處理函數指標,同時還要給sa_flags賦SA_SIGINFO,類似下面的代碼:
     #include
     ……
     void sig_handler_with_arg(int sig,siginfo_t *sig_info,void *unused){……}
    
     int main(int argc,char **argv)
     {
              struct sigaction sig_act;
              ……
              sigemptyset(&sig_act.sa_mask);
              sig_act.sa_sigaction=sig_handler_with_arg;
              sig_act.sa_flags=SA_SIGINFO;
  
               ……
     }
        如果你的應用程式只需要接收訊號,而不需要接收額外資訊,那你需要的設定的是sa_handler,而不是sa_sigaction,你的程式可能類似下面的代碼:
     #include
     ……
     void sig_handler(int sig){……}
    
     int main(int argc,char **argv)
     {
              struct sigaction sig_act;
              ……
              sigemptyset(&sig_act.sa_mask);
              sig_act.sa_handler=sig_handler;
              sig_act.sa_flags=0;
  
               ……
      }

      如果需要更詳細說明,請參閱sigaction的man手冊。

補充:

簡而言之就是:

//自訂退出函數
    sigact.sa_handler = mysighandler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGINT, &sigact, NULL);
    sigaction(SIGTERM, &sigact, NULL);
    sigaction(SIGQUIT, &sigact, NULL);

或者利用signal函數進行訊號捕捉:

void (*signal(int signo, void (*handler)(int)))(int);

當signal到來時,程式運行某函數,函數由你自己指定。

附帶各種訊號定義:

在終端使用kill -l 命令可以顯示所有的訊號。
$kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN
35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4
39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6
59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX

其中前面31個訊號為不可靠訊號(非即時的,可能會出現訊號的丟失),後面的訊號為可靠訊號(即時的real_time,對訊號
排隊,不會丟失)。

1) SIGHUP (掛起) 當運行進程的使用者登出時通知該進程,使進程終止

2) SIGINT (中斷) 當使用者按下時,通知前台進程組終止進程

3) SIGQUIT (退出) 使用者按下或時通知進程,使進程終止

4) SIGILL (非法指令) 執行了非法指令,如可執行檔本身出現錯誤、試圖執行資料區段、堆疊溢位

5) SIGTRAP 由斷點指令或其它trap指令產生. 由debugger使用

6) SIGABRT (異常中止) 調用abort函數產生的訊號

7) SIGBUS 非法地址, 包括記憶體位址對齊(alignment)出錯. eg: 訪問一個四個字長的整數, 但其地址不是4的倍數.

8) SIGFPE (算術異常) 發生致命算術運算錯誤,包括浮點運算錯誤、溢出及除數為0.

9) SIGKILL (確認殺死) 當使用者通過kill -9命令向進程發送訊號時,可靠的終止進程

10) SIGUSR1 使用者使用

11) SIGSEGV (段越界) 當進程嘗試訪問不屬於自己的記憶體空間導致記憶體錯誤時,終止進程

12) SIGUSR2 使用者使用

13) SIGPIPE 寫至無讀進程的管道, 或者Socket通訊SOCT_STREAM的讀進程已經終止,而再寫入。

14) SIGALRM (逾時) alarm函數使用該訊號,時鐘定時器逾時響應

15) SIGTERM (非強制中斷) 使用不帶參數的kill命令時終止進程

17) SIGCHLD (子進程結束) 當子進程終止時通知父進程

18) SIGCONT (暫停進程繼續) 讓一個停止(stopped)的進程繼續執行. 本訊號不能被阻塞.

19) SIGSTOP (停止) 作業控制訊號,暫停停止(stopped)進程的執行. 本訊號不能被阻塞, 處理或忽略.

20) SIGTSTP (暫停/停止) 互動式停止訊號, Ctrl-Z 發出這個訊號

21) SIGTTIN 當後台作業要從使用者終端讀資料時, 終端驅動程式產生SIGTTIN訊號

22) SIGTTOU 當後台作業要往使用者終端寫資料時, 終端驅動程式產生SIGTTOU訊號

23) SIGURG 有"緊急"資料或網路上帶外資料到達socket時產生.

24) SIGXCPU 超過CPU時間資源限制. 這個限制可以由getrlimit/setrlimit來讀取/改變。

25) SIGXFSZ 當進程企圖擴大檔案以至於超過檔案大小資源限制。

26) SIGVTALRM 虛擬時鐘訊號. 類似於SIGALRM, 但是計算的是該進程佔用的CPU時間.

27) SIGPROF (梗概時間逾時) setitimer(2)函數設定的梗概統計間隔計時器(profiling interval timer)

28) SIGWINCH 視窗大小改變時發出.

29) SIGIO(非同步I/O) 檔案描述符準備就緒, 可以開始進行輸入/輸出操作.

30) SIGPWR 電源失效/重啟動

31) SIGSYS 非法的系統調用。

在以上列出的訊號中,
程式不可捕獲、阻塞或忽略的訊號有:SIGKILL,SIGSTOP
不能恢複至預設動作的訊號有:SIGILL,SIGTRAP
預設會導致進程流產的訊號有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
預設會導致進程退出的訊號有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
預設會導致進程停止的訊號有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
預設進程忽略的訊號有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH

此外,SIGIO在SVR4是退出,在4.3BSD中是忽略;SIGCONT在進程掛起時是繼續,否則是忽略,不能被阻塞。

在Unix/Linux中signal函數是比較複雜的一個,其定義原型如下:
void (*signal(int signo,void (*func)(int))) (int)
這個函數中,最外層的函數體
void (* XXX )(int)表明是一個指標,指向一個函數XXX的指標,XXX所代表的函數需要一個int型的參數,返回void
signal(int signo, void(*func)(int))是signal函數的主體.
需要兩個參數int型的signo以及一個指向函數的函數.
void (*func)(int).
正是由於其複雜性,在[Plauger 1992]用typedef來對其進行簡化
typedef void Sigfuc(int);//這裡可以看成一個傳回值 .
再對signal函數進行簡化就是這樣的了
Sigfunc *signal(int,Sigfuc *);

在signal.h標頭檔中還有以下幾個定義
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1

原文 章中對signal函數的解釋不是很清楚,對signal函數,參看http://narmy.cn/linux/read.php/90.htm

轉自:http://blog.csdn.net/lanmanck/archive/2009/09/19/4568911.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.