天天看點

linux 信号中斷處理

  linux提供的信号機制是一種程序間異步的通信機制,在實作上是一種軟中斷。信号可以導緻一個正在運作的程序被另一個異步程序中斷,轉而處理某一個突發事件。每個信号用一個整型常量宏表示,以SIG開頭,比如SIGCHLD、SIGINT等,它們在系統頭檔案<signal.h>中定義, 也可以通過在shell下鍵入kill –l檢視信号清單, 或者鍵入man 7 signal檢視更詳細的說明。

信号的生成來自核心,讓核心生成信号的請求來自3個地方:

1     使用者:使用者能夠通過輸入CTRL+c、Ctrl+\,或者是終端驅動程式配置設定給信号控制字元的其他任何鍵來請求核心産生信号;

2      核心:當程序執行出錯時,核心會給程序發送一個信号,例如非法段存取(記憶體通路違規)、浮點數溢出等;

3      程序:一個程序可以通過系統調用kill給另一個程序發送信号,一個程序可以通過信号和另外一個程序進行通信。

同步信号和移步信号

    由程序的某個操作産生的信号稱為同步信号(synchronous signals),例如除0;由象使用者擊鍵這樣的程序外部事件産生的信号叫做異步信号。(asynchronous signals)。

程序接收到信号以後,可以有如下3種選擇進行處理:

1, 接收預設處理 :接收預設處理的程序通常會導緻程序本身消亡。例如連接配接到終端的程序,使用者按下CTRL+c,将導緻核心向程序發送一個SIGINT的信号,程序如果不對該信号做特殊的處理,系統将采用預設的方式處理該信号,即終止程序的執行;

2, 忽略信号 :程序可以通過代碼,顯示地忽略某個信号的處理,例如:signal(SIGINT,SIGDEF);但是某些信号是不能被忽略的,

3,捕捉信号并處理:程序可以事先注冊信号處理函數,當接收到信号時,由信号處理函數自動捕捉并且處理信号。

下面詳細介紹:

信号的産生:

1,kill:用法:kill [信号代碼]    程序ID

      注:信号代碼可以省略;我們常用的信号代碼是 -9 ,表示強制終止;

     而kill()函數定義為:

    int kill(_pid_t  _pid , int _sig);

   用法:

   #include <sys/types.h>

     #include <signal.h>

     int kill(pid_t pid, int sig);

     參數:

pid:可能選擇有以下四種

1. pid大于零時,pid是信号欲送往的程序的辨別。

2. pid等于零時,信号将送往所有與調用kill()的那個程序屬同一個使用組的程序。

3. pid等于-1時,信号将送往所有調用程序有權給其發送信号的程序,除了程序1(init)。

4. pid小于-1時,信号将送往以-pid為組辨別的程序。

sig:準備發送的信号代碼,假如其值為零則沒有任何信号送出,但是系統會執行錯誤檢查,通常會利用sig值為零來檢驗某個程序是否仍在執行。

傳回說明:

成功執行時,傳回0。失敗傳回-1,errno被設為以下的某個值

EINVAL:指定的信号碼無效

EPERM;沒有給任何目标程序發送信号的權限

ESRCH:目标程序或程序組不存在

2,alarm()定時

alarm函數可以設定一個計時器,計時器逾時時,産生SIGALRM信号給目前程序。每個程序隻能有一個鬧鐘時鐘。

                          unsigned int alarm(unsigned int seconds);

3,raise()自舉一個信号。函數則允許程序向自身發送信号。

                         int raise(int signo);

                          raise(signo)

                       等價于

                          kill(getpid(),signo);

信号的安裝

    linux主要有兩個函數實作信号的安裝:signal()、sigaction()。其中signal()在可靠信号系統調用的基礎上實作,是庫函數。它隻有兩個參數,不支援信号傳遞資訊,主要是用于前32種非實時信号的安裝;而sigaction()是較新的函數(由兩個系統調用實作:sys_signal以及sys_rt_sigaction),有三個參數,支援信号傳遞資訊,主要用來與 sigqueue()系統調用配合使用,當然,sigaction()同樣支援非實時信号的安裝。sigaction()優于signal()主要展現在支援信号帶有參數。

1、signal()

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

   第一個參數指定信号的值,第二個參數指定針對前面信号值的處理,可以忽略該信号(參數設為SIG_IGN);可以采用系統預設方式處理信号(參數設為SIG_DFL);也可以自己實作處理方式(參數指定一個函數位址)。

    如果signal()調用成功,傳回最後一次為安裝信号signum而調用signal()時的handler值;失敗則傳回SIG_ERR。

2,sigaction()

     int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

    sigaction函數用于改變程序接收到特定信号後的行為。該函數的第一個參數為信号的值(即接受到的信号),可以為除SIGKILL及SIGSTOP外的任何一個特定有效的信号(為這兩個信号定義自己的處理函數,将導緻信号安裝錯誤)。第二個參數是指向結構sigaction的一個執行個體的指針,在結構sigaction 的執行個體中,指定了對特定信号的處理,可以為空,程序會以預設方式對信号處理;第三個參數oldact指向的對象用來儲存原來對相應信号的處理,可指定 oldact為NULL。如果把第二、第三個參數都設為NULL,那麼該函數可用于檢查信号的有效性。第二個參數最為重要,其中包含了對指定信号的處理、信号所傳遞的資訊、信号處理函數執行過程中應屏蔽掉哪些函數等等。

信号集及屏蔽信号:

    中斷可以被屏蔽,linux的信号是可以被屏蔽的,即阻塞信号。與信号的忽略操作不同,在這裡系統不傳遞阻塞信号,而忽略信号是系統傳遞信号,隻是不處理。

    linux用信号集來管理阻塞信号,可以設定某個程序阻塞某個集合中的信号。

(1)清空信号集:sigemptyset()

  (2)  完全填充信号集:sigfillset()  設定完成之後,阻塞所有的信号

--------------------

還有很多函數,這裡不一一介紹了。

等待信号

       程序可以因等待信号而暫停目前運作,Pause()函數用來等待除目前程序阻塞信号外的任意信号,而sigsupend()函數用來等待除指定信号外的任意信号

       int   pause(void);

下面給出linux中的常見信号:

此外,對于與終端脫離關系的守護程序,這個信号用于通知它重新讀取配置檔案。

1) SIGHUP

本信号在使用者終端連接配接(正常或非正常)結束時發出, 通常是在終端的控制程序結束時, 通知同一session内的各個作業, 這時它們與控制終端不再關聯。

2) SIGINT

程式終止(interrupt)信号, 在使用者鍵入INTR字元(通常是Ctrl-C)時發出,用于通知前台程序組終止程序。

3) SIGQUIT

和SIGINT類似, 但由QUIT字元(通常是Ctrl-\)來控制. 程序在因收到SIGQUIT退出時會産生core檔案, 在這個意義上類似于一個程式錯誤信号。

4) SIGILL

執行了非法指令. 通常是因為可執行檔案本身出現錯誤, 或者試圖執行資料段. 堆棧溢出時也有可能産生這個信号。

5) SIGTRAP

由斷點指令或其它trap指令産生. 由debugger使用。

6) SIGABRT

調用abort函數生成的信号。

7) SIGBUS

非法位址, 包括記憶體位址對齊(alignment)出錯。比如通路一個四個字長的整數, 但其位址不是4的倍數。它與SIGSEGV的差別在于後者是由于對合法存儲位址的非法通路觸發的(如通路不屬于自己存儲空間或隻讀存儲空間)。

8)SIGFPE

在發生緻命的算術運算錯誤時發出. 不僅包括浮點運算錯誤, 還包括溢出及除數為0等其它所有的算術的錯誤。

9) SIGKILL

用來立即結束程式的運作. 本信号不能被阻塞、處理和忽略。如果管理者發現某個程序終止不了,可嘗試發送這個信号。

10) SIGUSR1

留給使用者使用

11) SIGSEGV

試圖通路未配置設定給自己的記憶體, 或試圖往沒有寫權限的記憶體位址寫資料.

12) SIGUSR2

留給使用者使用

13) SIGPIPE

管道破裂。這個信号通常在程序間通信産生,比如采用FIFO(管道)通信的兩個程序,讀管道沒打開或者意外終止就往管道寫,寫程序會收到SIGPIPE信号。此外用Socket通信的兩個程序,寫程序在寫Socket的時候,讀程序已經終止。

14) SIGALRM

時鐘定時信号, 計算的是實際的時間或時鐘時間. alarm函數使用該信号.

15) SIGTERM

程式結束(terminate)信号, 與SIGKILL不同的是該信号可以被阻塞和處理。通常用來要求程式自己正常退出,shell指令kill預設産生這個信号。如果程序終止不了,我們才會嘗試SIGKILL。

17) SIGCHLD

子程序結束時, 父程序會收到這個信号。

如果父程序沒有處理這個信号,也沒有等待(wait)子程序,子程序雖然終止,但是還會在核心程序表中占有表項,這時的子程序稱為僵屍程序。這種情況我們應該避免(父程序或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子程序,或者父程序先終止,這時子程序的終止自動由init程序來接管)。

1 SIGCONT

讓一個停止(stopped)的程序繼續執行. 本信号不能被阻塞. 可以用一個handler來讓程式在由stopped狀态變為繼續執行時完成特定的工作. 例如, 重新顯示提示符

19) SIGSTOP

停止(stopped)程序的執行. 注意它和terminate以及interrupt的差別:該程序還未結束, 隻是暫停執行. 本信号不能被阻塞, 處理或忽略.

20) SIGTSTP

停止程序的運作, 但該信号可以被處理和忽略. 使用者鍵入SUSP字元時(通常是Ctrl-Z)發出這個信号

21) SIGTTIN

當背景作業要從使用者終端讀資料時, 該作業中的所有程序會收到SIGTTIN信号. 預設時這些程序會停止執行.

22) SIGTTOU

類似于SIGTTIN, 但在寫終端(或修改終端模式)時收到.

23) SIGURG

有"緊急"資料或out-of-band資料到達socket時産生.

24) SIGXCPU

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

25) SIGXFSZ

當程序企圖擴大檔案以至于超過檔案大小資源限制。

26) SIGVTALRM

虛拟時鐘信号. 類似于SIGALRM, 但是計算的是該程序占用的CPU時間.

27) SIGPROF

類似于SIGALRM/SIGVTALRM, 但包括該程序用的CPU時間以及系統調用的時間.

28) SIGWINCH

視窗大小改變時發出.

29) SIGIO

檔案描述符準備就緒, 可以開始進行輸入/輸出操作.

30) SIGPWR

Power failure

31) SIGSYS

非法的系統調用。

(清悠我心:http://hi.baidu.com/%E6%B8%85%E6%82%A0%E6%88%91%E5%BF%83/home)

繼續閱讀