linux中的訊號處理機制 [一]
訊號排隊對於每乙個目標程序,核心會用乙個位圖(bitmap)來記錄訊號的處理狀態。如果乙個訊號還未被目標程序處理,那麼它就是掛起/未決(pending)的狀態。核心在向目標程序遞送訊號時,會檢視程序對應的bitmap中,該訊號對應的bit是否有掛起的訊號。
如果當前有掛起的訊號,按照unix傳統的做法,核心將直接丟棄這一訊號,其結果當然就是該訊號不能被目標程序正確接收。這樣的訊號存在丟失的風險,因而被稱為「不可靠訊號」。
而後出現的各種unix衍生版本對此做出了一些改進,以linux的實現為例,核心會為每個程序維護一組佇列(queue),有掛起訊號時,就將新來的訊號排隊(enqueue)。只要掛起的訊號個數沒有超過核心設定的上限,理論上就不會丟失,這樣的訊號被稱為「可靠訊號」。
在**實現中,bitmap用sigset_t表示,而佇列就是乙個雙向鍊錶,煉表頭結點包含在程序對應的task_struct中。
struct
看起來不可靠訊號和可靠訊號只是unix/linux中處理訊號的兩種機制,跟訊號本身無關,為什麼把訊號劃分為不可靠訊號和可靠訊號呢?
因為早期的訊號都是按不排隊的方式實現的,它們的訊號值在1到31之間,為了保持前向相容性,linux對[1, 31]之間的訊號還是保持了原來的處理方式,只有對[sigrtmin, sigrtmax]之間的訊號才採用排隊的處理方式,因此[1, 31]之間的就是不可靠訊號,[sigrtmin, sigrtmax]之間的就是可靠訊號。
這裡出現了乙個"rt",它代表real time,這是**於posix對可靠訊號機制的標準化定義。在posix標準中,可靠訊號被稱為realtime signal,與之相對的不可靠訊號則被稱為regular signal。作為一種標準,posix只對可靠訊號機制應具有的功能和對外介面做了定義,並沒有對實現的具體方式作出要求。
你就算用sigqueue()函式去傳送不可靠訊號,它還是不會排隊,還是不可靠,生來注定,不可逆轉。你也不能怪sigqueue這個名字取的有歧義,人家本來就是為了配合會排隊的可靠訊號而生的,只不過為了相容性,也可以用來傳送不可靠訊號罷了。
這個過程類似於中斷虛擬化中的「中斷採集」。
訊號遞送訊號是軟體範疇中乙個類似於硬體中斷的概念,但它不能像硬體中斷那樣直接打斷程式的執行,目標程序對訊號的處理只會發生在該程序被重新排程執行,也就是從核心態切換到使用者態的時候。由於使用者態和核心態的切換是很頻繁的,因而訊號通常能很快地得到目標程序的響應,看起來就跟中斷的效果一樣。
在核心將cpu的控制權交還給使用者程序之前,核心會檢視程序對應的的tif_sigpending標誌位,以判斷即將執行的這個程序有無pending的訊號需要處理。每次程序對應的bitmap和pending佇列發生變化時,tif_sigpending標誌位都會被重新計算,這樣在發生切換的時候,核心就可以快速做出判斷。
如果目標程序沒有設定對訊號的「忽略」或者「遮蔽」,那麼它就將執行對應的訊號處理函式。這個過程類似於中斷虛擬化中的「中斷注入」。
當pending的訊號不止乙個的時候,核心會呼叫do_signal()-->get_signal()迴圈地進行訊號遞送,其中由異常產生的"synchronous"訊號將會被優先遞送。
bool
對於同為"synchronous"或者同為非"synchronous"的pending訊號,則按照訊號值在bitmap中從小到大的順序,依次遞送給目標程序執行。如果被程序響應的訊號是不可靠訊號,核心將把這個訊號從程序對應的bitmap中移除;如果是可靠訊號,核心還會把該訊號從程序對應的pending佇列中移除。
核心將訊號遞送給程序後,程序會根據需要做出不同的接收處理,其詳細過程將在下文中介紹。
Linux訊號處理機制(二) 阻塞訊號
訊號在核心中一般有三種狀態 1 訊號遞達 delivery 實際執行訊號的處理動作稱為訊號遞達 2 訊號未決 pending 訊號從產生到遞達之間的狀態 3 訊號阻塞 block 被阻塞的訊號產生時將保持在未決狀態,直到程序解除對此訊號的阻塞,才執行遞達的動作 注意 阻塞與忽略是不同的,只要訊號被阻...
Linux訊號處理機制
程式錯誤 除零,非法記憶體訪問 外部訊號 終端ctrl c產生sgint訊號,定時器到期產生sigalrm 顯式請求 kill函式允許程序傳送任何訊號給其他程序或程序組。目前linux支援64種訊號。訊號分為非實時訊號 不可靠訊號 和實時訊號 可靠訊號 兩種型別,對應於 linux 的訊號值為 1 ...
LINUX訊號處理機制的原理
訊號處理機制的原理 核心給乙個程序傳送軟中斷訊號的方法,是在程序所在的程序表項的訊號域設定對應於該訊號的位。這裡要補充的是,如果訊號傳送給乙個正在睡眠的程序,那麼要 看該程序進入睡眠的優先順序,如果程序睡眠在可被中斷的優先順序上,則喚醒程序 否則僅設定程序表中訊號域相應的位,而不喚醒程序。這一點比較...