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

  • 相关阅读:
    清除浮动的几种方法
    call() 、 apply() 、bind()方法的作用和区别!
    关于如何通过json更改背景图片
    js验证码实现
    解决python3 UnicodeDecodeError: 'gbk' codec can't decode byte
    Rest接口测试,巧用firebug插件
    PHP中字符串的连接和换行
    PHP内置函数file_put_content(),将数据写入文件,使用FILE_APPEND 参数进行内容追加
    PHP的三种输出方式
    PHP中的include、include_once、require、require_once
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/11257472.html
Copyright © 2020-2023  润新知