程序在發送 SIGKILL 信號時會做什麼?
當我用來
killall -9 name
殺死一個程序時,狀態變成了殭屍。幾分鐘後,它真的停了下來。那麼,在那幾分鐘內發生了什麼?
該程序實際上從未收到 SIGKILL 信號,因為 SIGKILL 完全由作業系統/核心處理。
當發送特定程序的 SIGKILL 時,核心的調度程序會立即停止為該程序提供更多 CPU 時間來執行使用者空間程式碼。如果在調度程序做出此決定時,程序有任何執行緒在其他 CPU/核心上執行使用者空間程式碼,則這些執行緒也將停止。(在單核系統中,這過去要簡單得多:如果系統中唯一的 CPU 核心正在執行調度程序,那麼根據定義,它不會同時執行程序!)
如果程序/執行緒在 SIGKILL 時正在執行核心程式碼(例如係統呼叫,或與記憶體映射文件關聯的 I/O 操作),它會變得有點棘手:只有一些系統呼叫是可中斷的,所以核心在內部將程序標記為處於特殊的“死亡”狀態,直到系統呼叫或 I/O 操作得到解決。解決這些問題的 CPU 時間將照常安排。可中斷的系統呼叫或 I/O 操作將檢查呼叫它們的程序是否在任何合適的停止點死亡,並在這種情況下提前退出。不間斷的操作將執行完成,並在返回使用者空間程式碼之前檢查“死亡”狀態。
一旦解決了任何程序內核心常式,程序狀態就會從“死亡”變為“死”,並且核心開始清理它,類似於程序正常退出時。清理完成後,將分配一個大於 128 的結果程式碼(表示該程序已被信號殺死;有關混亂的詳細資訊,請參見此答案),並且該程序將轉換為“殭屍”狀態. 被殺死程序的父程序將收到一個 SIGCHLD 信號通知。
結果,程序本身永遠不會有機會實際處理它收到的 SIGKILL 資訊。
當程序處於“殭屍”狀態時,意味著該程序已經死亡,但其父程序尚未通過使用
wait(2)
系統呼叫讀取死程序的退出程式碼來確認這一點。基本上,殭屍程序消耗的唯一資源是程序表中的一個槽,該槽保存它的 PID、退出程式碼和程序在其死亡時的一些其他“重要統計資訊”。如果父程序在其子程序之前死亡,則孤立的子程序會自動被 PID #1 採用,它有一個特殊的職責是繼續呼叫
wait(2)
,這樣任何孤立的程序就不會像殭屍一樣留下來。如果殭屍程序需要幾分鐘才能清除,則表明殭屍的父程序正在掙扎或沒有正常工作。
在類 Unix 作業系統中出現殭屍問題時,有一個半開玩笑的描述:“你不能為殭屍本身做任何事情,因為它們已經死了。相反,殺死邪惡的殭屍大師! ” (即麻煩殭屍的父程序)