Linux高級調試與優化——信號量機制與應用程序崩潰


背景介紹

  Linux分為內核態和用戶態,用戶態通過系統調用(syscall)進入內核態執行。

  用戶空間的glibc庫將Linux內核系統調用封裝成GNU C Library庫文件(兼容ANSI & POSIX C語言標准),同時提供了其他特性的支持。

  應用程序通常不是直接調用Linux內核的系統調用接口,而是通過glibc庫封裝的接口間接調用Linux內核系統調用。

 

信號量機制

  關於Linux信號量機制的原理,建議閱讀《Unix環境高級編程》第10章,本博客只是簡單介紹其原理。

  信號量是一種軟中斷,用來實現Linux內核和應用程序之間的異步通信。

  每一個信號量由一個4字節整形數據表示。可以通過man 7 signal查看所有信號量描述。其中1~32號信號量是從Unix繼承而來,33~64是Linux內核定義的信號量。

  Linux內核為每個信號量設置了默認處理動作,如Term(終止執行)、Ign(忽略)、Core(終止執行並產生coredump)、Stop(停止運行)和Cont(繼續運行),當應用程序接收到某個信號量時,則按照默認處理動作執行。應用程序也可以通過sigaction()或者signal()函數修改默認的處理動作,比如屏蔽或者忽略某個信號量等。

  應用程序信號量處理函數通常是鏈接glibc中默認的信號量處理函數,也可以自己編寫和指定信號量處理函數。但是需要注意的是,SIGKILL和SIGSTOP信號量不能被捕獲(caught)、屏蔽(blocked)或者忽略(ignored)。

  信號量觸發情況有三種:

  1)Linux內核檢測到應用程序異常,發送特定的信號量給應用程序,應用程序捕獲到信號量后,調用信號量處理函數;

  2)Linux內核因為內部事件而給應用程序發送特定信號,通知應用程序發生了某個事件,如著名的segmentation fault,應用程序捕獲到信號量后,調用信號量處理函數;

  3)Linux內核檢測到外部事件,如Ctrl+C,Ctrl+Z等,發送特定信號給應用程序,應用程序捕獲到信號量后,調用信號量處理函數;

 

信號量列表

Signal Value Action Comment
SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process
SIGINT 2 Term Interrupt from keyboard
SIGQUIT 3 Core Quit from keyboard
SIGILL 4 Core Illegal Instruction
SIGTRAP 5 Core Trace/breakpoint trap
SIGABRT 6 Core Abort signal from abort(3)
SIGIOT 6 Core IOT trap. A synonym for SIGABRT
SIGEMT 7 Term  
SIGFPE 8 Core Floating point exception
SIGKILL 9 Term Kill signal, cannot be caught, blocked or ignored.
SIGBUS 10,7,10 Core Bus error (bad memory access)
SIGSEGV 11 Core Invalid memory reference
SIGPIPE 13 Term Broken pipe: write to pipe with no readers
SIGALRM 14 Term Timer signal from alarm(2)
SIGTERM 15 Term Termination signal
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated
SIGCONT 19,18,25 Cont Continue if stopped
SIGSTOP 17,19,23 Stop Stop process, cannot be caught, blocked or ignored.
SIGTSTP 18,20,24 Stop Stop typed at terminal
SIGTTIN 21,21,26 Stop Terminal input for background process
SIGTTOU 22,22,27 Stop Terminal output for background process
SIGIO 23,29,22 Term I/O now possible (4.2BSD)
SIGPOLL   Term Pollable event (Sys V). Synonym for SIGIO
SIGPROF 27,27,29 Term Profiling timer expired
SIGSYS 12,31,12 Core Bad argument to routine (SVr4)
SIGURG 16,23,21 Ign Urgent condition on socket (4.2BSD)
SIGVTALRM  26,26,28 Term Virtual alarm clock (4.2BSD)
SIGXCPU 24,24,30 Core CPU time limit exceeded (4.2BSD)
SIGXFSZ 25,25,31 Core File size limit exceeded (4.2BSD)
SIGSTKFLT 16 Term Stack fault on coprocessor (unused)
SIGCLD 18 Ign A synonym for SIGCHLD
SIGPWR 29,30,19 Term Power failure (System V)
SIGINFO 29   A synonym for SIGPWR, on an alpha
SIGLOST 29 Term File lock lost (unused), on a sparc
SIGWINCH 28,28,20 Ign Window resize signal (4.3BSD, Sun)
SIGUNUSED 31 Core Synonymous with SIGSYS

 

信號量進階

  關於自定義信號量處理函數、屏蔽指定信號量等操作,參考《System Programing: Signals》

  信號量處理函數實質上是應用程序發生異常時的一種修復或者調試機制,因為信號量處理不是正常的函數調用,因此它會復用父函數的棧,如果信號量處理函數中發生了異常,系統是沒有辦法處理的,因此,信號量處理函數必須是安全可靠的。

  自定義的信號量處理函數不可以做信號量同步(防止死鎖),但是可以通過call fork起gdb調試器或者寫log文件到磁盤。

 

應用程序崩潰

  通常意義上講,main()函數是應用程序的入口。但是實際上,Linux內核執行C程序時(通過exec函數),在調用main函數之前,先調用一個特殊的啟動例程。可執行程序文件(ELF文件)將此啟動例程指定為程序的起始地址。啟動例程從內核取得命令行參數和環境變量值,為調用main函數做好准備。

  有8種方式使進程終止,其中5種為正常終止,他們是

  1) 從main返回(return語句)

  2) 調用exit

  3) 調用_exit或者_Exit

  4) 最后一個線程從其啟動例程返回

  5) 最后一個線程調用pthread_exit

  異常終止有3種方式,他們是

  6) 調用abort()  ----SIGABRT

  7) 接收到一個信號量並終止    ---其他Term/Core類信號量

  8) 最后一個線程對取消請求做出響應

  由此可見,應用程序崩潰必然是因為內部或者外部的原因,導致內核發送信號量或者glibc主動觸發信號量(abort),當應用程序捕獲到信號量之后,進入異常處理流程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM