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),当应用程序捕获到信号量之后,进入异常处理流程。
Linux高级调试与优化——信号量机制与应用程序崩溃的更多相关文章
- Linux高级调试与优化——gdb调试命令
番外 2019年7月26日至27日,公司邀请<软件调试>和<格蠹汇编——软件调试案例集锦>两本书的作者张银奎老师进行<Linux高级调试与优化>培训,有幸聆听张老师 ...
- Linux高级调试与优化——内存泄漏实战分析
最近在整理Linux调试方面的文档,正好碰到了一个内存泄漏踩栈的问题,借此机会记录一下分析过程. 首先,发现问题之后,赶紧看一下产生coredump文件没有,果不其然,产生了coredump,果断上g ...
- Linux高级调试与优化——ptrace
ptrace (process trace) #include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_ ...
- Linux高级调试与优化——内存管理
1.物理地址和虚拟地址 Linux采用页表机制管理内存,32位系统中页大小一般为4KB,物理内存被划分为连续的页,每一个页都有一个唯一的页号. 为了程序的的可移植性,进程往往需要运行在flat mem ...
- Linux高级调试与优化——用户态堆
内存问题是软件世界的住房问题 嵌入式Linux系统中,物理内存资源通常比较紧张,而不同的进程可能不停地分配和释放不同大小的内存,因此需要一套高效的内存管理机制. 内存管理可以分为三个层次,自底向上分别 ...
- Linux高级调试与优化——同时抓取coredump和maps文件
Linux内核源码 Documentation/sysctl/kernel.txt core_pattern: core_pattern: core_pattern is used to specif ...
- Linux高级调试与优化——进程管理和调度
进程管理 进程和文件是Linux操作系统的两个最基本的抽象. 进程是处于执行期的程序,进程不仅仅局限于一段可执行程序代码,通常还包含其他资源,如打开的文件.挂起的信号.内核内部数据.处理器状态.进程地 ...
- Linux高级调试与优化——Address Sanitizer
Address Sanitizer ASAN最早可以追溯到 LLVM 的 sanitizers项目(https://github.com/google/sanitizers),这个项目包含了Addre ...
- 09、高级编程之基于排序机制的wordcount程序
package sparkcore.java; import java.util.Arrays; import java.util.Iterator; import org.apache.spark. ...
随机推荐
- java String int转换的不同方法
参考了网上某篇日志的内容,现摘录如下: String转int: 最常见:int i = Integer.parseInt("123"); 罕见:Integer i= Integer ...
- mydql 设置充许远程链接
1 本机作为服务器时,其他机器连接不上? 1)看一下防火墙是否打开了. 2)在cmd中设置权限. 第一种:(进入数据库的情况下) 1.d:\mysql\bin\>mysql -h localho ...
- 可持久化BCJ
BZOJ3674:可持久化并查集加强版 n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出 ...
- Tableau Dashboard
Dashboard仪表盘,用来展示多个图表,并展示之间的联动,分析数据.
- 【HDU4003】Find Metal Mineral
题目大意:给定一棵 N 个节点的有根树,边有边权,在根结点处有 K 个人,这些人会遍历树上的所有边,求如何遍历才能使得所有人走过路径的边权和最小. 题解: 引理:对于一棵子树来说,若存在 M>0 ...
- 使用XML的方式实现账户的CRUD
1 需求和技术要求 1.1 需求 实现账户的CRUD. 1.2 技术要求 使用Spring的IOC实现对象的管理. 使用QueryRunner作为持久层的解决方案. 使用C3p0作为数据源. 2 环境 ...
- ZROI 19.08.03 分治与离线
经典问题,给一张图,支持加边/删边/询问两点连通性. 离线统计边权(删除时间),lct维护最大生成树即可. 也可以按时间分治,维护一个可回退并查集即可. 主定理 很好用,但是记不住. 有一种简明的替代 ...
- Puppet利用Nginx多端口实现负载均衡
随着公司应用需求的增加,需要不断的扩展,服务器数量也随之增加,当服务器数量不断增加,我们会发现一台puppetmaster压力大,解析缓慢,而且时不时出现"time out"之类的 ...
- CentOS源码编译安装MySQL 5.5.15
CentOS源码编译安装MySQL 5.5.15 文章目录 [隐藏] 安装编译工具 下载源码 安装cmake和bison 编译安装MySQL 一些相关设置 安装编译工具 yum install g ...
- python连接 MySQ 数据库
python 是目前比较流行的语言,所以学习一下 首先需要 安装MySQL-python驱动 下载地址:http://dev.mysql.com/downloads/connector/python/ ...