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),当应用程序捕获到信号量之后,进入异常处理流程。

posted on 2019-07-28 00:49  者旨於陽  阅读(1629)  评论(0编辑  收藏  举报

导航