信號種類
信號分為可靠信號與不可靠信號,可靠信號又稱為實時信號,非可靠信號又稱為非實時信號。
不可靠信號
信號代碼從1到32是不可靠信號,不可靠信號主要有以下問題:
(1)每次信號處理完之后,就會恢復成默認處理,這可能是調用者不希望看到的
(2)存在信號丟失的問題
現在的Linux對信號機制進行了改進,因此,不可靠信號主要是指信號丟失。
可靠信號
信號代碼從SIGRTMIN到SIGRTMAX之間的信號是可靠信號。可靠信號不存在丟失,由sigqueue發送,可靠信號支持排隊。
可靠信號注冊機制
內核每收到一個可靠信號都會去注冊這個信號,在信號的未決信號鏈中分配sigqueue結構,因此,不會存在信號丟失的問題。
不可靠信號的注冊機制
而對于不可靠的信號,如果內核已經注冊了這個信號,那么便不會再去注冊,對于進程來說,便不會知道本次信號的發生。
可靠信號與不可靠信號與發送函數沒有關系,取決于信號代碼,前面的32種信號就是不可靠信號,而后面的32種信號就是可靠信號。
信號響應的方式
(1)采用系統默認處理SIG_DFL,執行缺省操作
(2)捕捉信號處理,即用戶自定義的信號處理函數來處理
(3)忽略信號SIG_IGN ,但有兩種信號不能被忽略SIGKILL,SIGSTOP
信號的生命周期與處理過程分析
1. 信號的生命周期
信號產生->信號注冊->信號在進程中注銷->信號處理函數執行完畢
(1)信號的產生是指觸發信號的事件的發生
(2)信號注冊
指的是在目標進程中注冊,該目標進程中有未決信號的信息:
struct sigpending pending:
struct sigpending {
????????struct sigqueue *head, **tail;
????????sigset_t signal;
};
struct sigqueue {
????????struct sigqueue *next;
????????siginfo_t info;
}
其中 sigqueue結構組成的鏈稱之為未決信號鏈,sigset_t稱之為未決信號集。
*head,**tail分別指向未決信號鏈的頭部與尾部。
siginfo_t info是信號所攜帶的信息。
信號注冊的過程就是將信號值加入到未決信號集siginfo_t中,將信號所攜帶的信息加入到未決信號鏈的某一個sigqueue中去。
因此,對于可靠的信號,可能存在多個未決信號的sigqueue結構,對于每次信號到來都會注冊。
而不可靠信號只注冊一次,只有一個sigqueue結構。
只要信號在進程的未決信號集中,表明進程已經知道這些信號了,還沒來得及處理,或者是這些信號被阻塞。
(3)信號在目標進程中注銷
在進程的執行過程中,每次從系統調用或中斷返回用戶空間的時候,都會檢查是否有信號沒有被處理。如果這些信號沒有被阻塞,那么就調用相應的信號處理函數來處理這些信號。
在調用信號處理函數之前,進程會把信號在未決信號鏈中的sigqueue結構卸掉。是否從未決信號集中把信號刪除掉,對于實時信號與非實時信號是不相同的。
非實時信號:由于非實時信號在未決信號鏈中只有一個sigqueue結構,因此將它刪除的同時將信號從未決信號集中刪除。
實時信號:由于實時信號在未決信號鏈中可能有多個sigqueue結構,如果只有一個,也將信號從未決信號集中刪除掉。如果有多個那么不從未決信號集中刪除信號,注銷完畢。
(4)信號處理函數執行完畢
執行處理函數,本次信號在進程中響應完畢。
信號處理函數的過程:
(1)注冊信號處理函數
信號的處理是由內核來代理的,首先程序通過sigal或sigaction函數為每個信號注冊處理函數,而內核中維護一張信號向量表,對應信號處理機制。這樣,在信號在進程中注銷完畢之后,會調用相應的處理函數進行處理。
(2)信號的檢測與響應時機
在系統調用或中斷返回用戶態的前夕,內核會檢查未決信號集,進行相應的信號處理。
(3)處理過程:
程序運行在用戶態時->進程由于系統調用或中斷進入內核->轉向用戶態執行信號處理函數->信號處理函數完畢后進入內核->返回用戶態繼續執行程序
首先程序執行在用戶態,在進程陷入內核并從內核返回的前夕,會去檢查有沒有信號沒有被處理,如果有且沒有被阻塞就會調用相應的信號處理程序去處理。首先,內核在用戶棧上創建一個層,該層中將返回地址設置成信號處理函數的地址,這樣,從內核返回用戶態時,就會執行這個信號處理函數。當信號處理函數執行完,會再次進入內核,主要是檢測有沒有信號沒有處理,以及恢復原先程序中斷執行點,恢復內核棧等工作,這樣,當從內核返回后便返回到原先程序執行的地方了。
信號處理函數的過程大概是這樣了。