一、什麼是訊號
1.訊號是很短的訊息,可以被發送一個進程或一個進程組,用於進程間的通訊
2.訊息的內容通常是一個數,這個數用於標識訊號
訊號的接收方一定是進程,發送方可能是進程,或者核心。
訊號只能發送給屬於同一session以及同一個使用者的進程
3.訊號的種類可分為兩類
(1)常規訊號:編碼範圍1-31,如果一個常規訊號被連續發送多次,會被合并成一次,即只有一個發送到接收進程
(2)即時訊號:編碼範圍32-64,它們必須被排隊,以便發送的多個訊號都被接收到
(3)常規訊號和即時訊號,都是用隊列來接收的,只是常規訊號的接收隊列,每個隊列中最多隻能有一項
(4)可以看出,每個訊號對應的訊號處理函數相對自己是串列的,不必是可重新進入的
4.子進程會繼承父進程的訊號處理方式
二、訊號傳遞的過程
1.訊號產生:
更新目標進程的資料結構
2.目標進程對訊號的檢測與反應
(1)忽略
(2)預設操作
(3)調用相應的訊號處理函數
三、訊號的掛起、阻塞、忽略、丟棄
1.丟棄:對於常規訊號,同種類型的一次存在一個,多餘的會被丟棄
2.訊號阻塞:某種類型的訊號被阻塞後,目標進程不會處理這個訊號,直到解除阻塞後再處理(針對訊號類型)
3.掛起:已經產生但還沒有處理的訊號稱為掛起訊號。對於常規訊號,同種類型的掛起訊號一次只存在一個(針對某個具體的訊號)
4.忽略:目標進程已收到這個訊號,並作出回應,回應的方式是不作為任何處理
四、訊號產生過程
send_signal()
(1)申請一個掛起訊號的資料結構
(2)把資料結構掛入掛起訊號隊列
(3)修改隊列位元遮罩
(4)如果需要,喚醒進程
五、訊號處理的過程
1.在中斷機制中,處理器的硬體在每條指令結束進都要檢測是否還有插斷要求存在
訊號機制是純軟體的,不能依靠硬體活動訊號,只能在兩個特定的時間點檢測
2.對訊號的檢測與響應總發生於系統空間
(1)從系統空間返回到使用者空間的前夕
(2)進程在核心睡眠剛被喚醒時,由於訊號而提前返回到使用者空間
3.進程運行於使用者空間時,即使訊號到達了也不會作出反應,要等到特定時刻檢測到訊號才會處理
4.當訊號向量為SIG_IGN或SIG_DFL時,對訊號的處理都在系統空間完成,無須回到使用者空間
當訊號向量為使用者提供的訊號處理常式時,需要使用者空間執行,執行完再回到系統空間,然後再回到使用者空間
5.執行自訂函數的過程:
do_signal() -----> handle_signal() -----> 訊號處理函數
note:
訊號處理函數由使用者進程定義,包含在使用者態代碼中,在使用者空間運行
handle_signal():運行在核心態
6.關於幀、函數使用者、Runspace
(1)幀frame:調用一次子程式時,在棧中儲存的一個層次稱為一幀,包括子程式的返回地址、子程式的局部變數、調用子程式時的參數
(2)程式與子程式位於同一空間:普通的函數調用
(3)調用者在使用者空間,子程式在系統空間:中斷處理、異常處理、系統調用
(4)調用者在系統空間,子程式在使用者空間:handle_signal()調用訊號處理函數
7.從handle_signal()的系統空間 進入 訊號處理函數的使用者空間 的過程
要從系統空間進入使用者空間執行另一段程式,就必須在系統空間準備一個新的幀,而原系統空間的幀也要儲存起來
解決方案:把原系統空間幀作為訊號處理常式的局部變數,儲存在新的幀中
在進入使用者空間執行訊號處理函數之前,先準備好使用者空間堆棧的幀,把原幀複製到新幀中作為局部變數儲存起來,回到系統空間後再從那裡複製回來
8.從訊號處理函數的使用者空間 返回到 handle_signal()的系統空間 的過程
使用者空間進入系統空間的手段有三種:中斷、異常、陷阱,系統調用是陷阱的一種
從訊號處理函數返回系統空間使用的方式是系統調用
9.handle_signal() ----- 調用訊號處理函數並返回
(1)在使用者空間堆棧中為訊號處理常式預先建立一個frame,其中包括原系統空間堆棧的frame
(2)在訊號處理函數中插入系統調用sigreturn()
(3)將系統空間堆棧中的frame修改為訊號處理函數所需的frame
(4)進入使用者空間,開始執行訊號處理函數
(5)執行訊號處理函數
(6)通過系統調用figreturn()返回到系統空間
(7)從使用者空間恢複系統堆棧空間的frame
(8)回到使用者空間,繼續執行使用者程式
10.“系統空間->使用者空間->系統空間->使用者空間”這段過程能不能簡化?
答:理論上可以。但是必須保證使用者的訊號處理常式對“工作現場”(SAVE_ALL所儲存的部分)不能更改。
訊號處理函數由使用者進程定義,包含在使用者態代碼中,在使用者空間運行,不能保證這一點。
為了系統安全,不這麼做。
六、為某個訊號定義訊號處理函數
1.signal(int signr, sigunc *handle);
給訊號值是signr的訊號安裝一個處理函數控制代碼handle
handle是函數指標
2.自訂的訊號處理函數控制代碼只能使用一次,若要持續使用,在訊號處理函數中重設自訂控制代碼
3.signal()的BUG:在3-(1)的複位和3-(2)的重設之間發生了訊號可能會造成訊號的丟失。
使用sigaction()能解決訊號失去的問題