1. 程式人生 > >跟結束程序相關的那些訊號

跟結束程序相關的那些訊號

前言

專案中在使用kube-keepalived-vip時遇到了keepalived相關的Bug, 原本計劃測試最新版的keepalived看是否存在同樣的問題. 在將keepalived升級到當前最新版本v2.0.7之後發現每次執行kubectl delete pod <kube-keepalived-vip pod>都會出現segfault的核心錯誤, 且較大概率會連帶出現keepalived的殭屍程序, 但對比發現通過手動執行kill -9結束keepalived程序卻沒有這個問題. 翻了一下runc的程式碼發現kubectl delete實際上(預設情況)是通過發給程序一個SIGTERM的訊號讓其退出, 這就是為什麼手動執行kill -9

沒有出現同樣的問題. 這裡索性整理了一下與結束程序相關的訊號的區別和聯絡.

訊號

  • 什麼是訊號
  • 訊號是軟體中斷, 很多比較重要的應用程式都需要處理訊號. 訊號提供了一種處理非同步事件的方法. 例如, 終端用於鍵入中斷健, 會通過訊號機制停止一個程式, 或及早終止管道中的下一個程式.
  • UNIX系統的早期版本就已經提供訊號機制, 但是這些系統(V7)所提供的訊號模型並不可靠. 訊號可能丟失, 並且在執行臨界區程式碼時, 程序很難關閉所選擇的訊號. 4.3BSD和SVR3對訊號模型都做了修改, 增加了可靠訊號機制. 但是Berkeley和AT&T所做的更改之間並不相容. 幸運的是, POSIX.1對可靠訊號例程進行了標準化.
  • 檢視訊號列表
  • 在Linux系統當中可直接通過kill命令加-l引數列出所有的訊號, 主要依據標頭檔案/usr/include/linux/signal.h.
  • 可以看到所有的訊號都包含一個正整數序號(序號0有特殊用途)和一個以SIG開頭的簡稱
[[email protected] ~]# kill -l
 1) SIGHUP  2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT 7) SIGBUS   8) SIGFPE   9) SIGKILL  10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
[
[email protected]
~]#

結束程序相關的訊號

通過kill -l可以看到作業系統總共提供了64種訊號, 這裡只列舉了與結束程序相關的幾種訊號, 分別是訊號序號為1、2、3、9、15的SIGHUP、SIGINT、SIGKILL、SIGTERM

  • SIGHUP

    • 如果終端介面檢測到一個連線斷開, 則將此訊號送給與該終端相關的控制程序. (與之相關的命令為nohup)
    • 如果終端會話首程序終止, 也產生此訊號. 在這種情況下, 此訊號送給前臺程序組中的每一個程序.
    • 通常用此訊號通知守護程序再次讀取它們的配置檔案. 選用SIGHUP的理由是, 守護程序不會有控制終端, 通常絕不會接收到這種訊號.
    • 這也是kube-keepalived-vip當中reload keepalived.conf的方式
kill -1 <pid>
  • SIGINT

    • 使用者按下中斷健(一般採用DELETE或Ctrl+C)時, 終端驅動程式產生此訊號併發送至前臺程序組中的每一個程序.
    • 當一個程序組在執行時失控, 特別是當程序正在螢幕上產生大量不需要的輸出時, 常用此訊號終止.
kill -2 <pid>
  • SIGQUIT

    • 當用戶在終端上按退出鍵(一般採用Ctrl +  ), 中斷驅動程式產生此訊號, 併發送給前臺程序組中的所有程序.
    • 此訊號不僅終止前臺程序組(如SIGINT), 同時將產生一個core檔案(關於如何檢視core檔案, 見另一片博文《如何檢視core檔案》).
    • 設計的初衷為以較溫和地方式退出程式, 讓程式在退出前可以清理一些臨時檔案或者做別的處理, 但建議最好不好清理臨時檔案, 方便gdb配合core檔案進行Debug.
kill -3 <pid>
  • SIGKILL

    • 強制立即結束程序, 相較於其他訊號, SIGKILL訊號不能夠被程序捕獲, 也不能夠被忽略, 因此總是能夠結束程序(如果不行, 那一定是作業系統的Bug).
    • 不能夠阻塞該訊號
    • 使用該訊號一定要想清楚後果
kill -9 <pid>
  • SIGTERM

    • kill命令預設傳送的終止訊號.
    • 該訊號可由應用程式捕獲, 故使用SIGTERM也讓程式有機會在退出之前做好清理工作, 從而優雅地終止.
kill -15 <pid>

結束語

很多時候很多莫名其妙的問題或者Bug都是因為我們對一些細節的不理解或者掌握的不夠透徹, 就比如結束一個程序就有這麼多種方式, 你是否每一種方式都能夠說清楚呢? 基礎是否夯實正是從日常工作的小事積累和體現出來.

參考

  1. https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
  2. 《Unix環境高階程式設計》
  3. Linux man page