目录
- 0.前言预备
- 1.系统定义的信号列表
- 2.核心转储 -- Core Dump
- 1.信号基础
- 1.信号概念
- 2.信号处理方式概览
- 3.理解信号如何被保存
- 4.信号发送的本质
- 2.如何产生信号?
- 1.终端按键产生信号
- 2.系统调用接口
- 1.kill()
- 2.raise()
- 3.abort()
- 4.如何理解?
- 3.由软件条件产生信号
- 4.硬件异常产生信号
- 5.总结
0.前言预备
1.系统定义的信号列表
-
**[1, 31]:**普通信号
-
**[34, 64]:**实时信号
-
这些信号在什么条件下产生,默认的处理动作是什么,可以通过 man 7 signal 查看
2.核心转储 – Core Dump
- 当一个进程要异常终止时,可以选择把当前进程在内存中的相关核心数据转存到磁盘上,文件名通常是core,这叫做Core Dump
- 进程异常终止通常是因为有Bug,事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug(事后调试)
- 使用:core -file core.pid
- 默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全
- 一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存在PCB中)
- 在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件
- ulimit -a
- ulimit -c
- 当前bash会话有效
1.信号基础
1.信号概念
- 信号是进程之间事件异步通知的一种方式,属于软中断
- 本质是一种通知机制
- 理解信号思路:
- 进程要处理信号,必须具备信号"识别"能力(看到 + 处理动作)
- 进程为什么能够"识别"信号?
- 程序员通过代码提前设置好的
- 信号产生是随机的,进程可能正在忙自己的事情
- 信号可能后续被处理,不一定是立即处理
- 信号会临时的记录下对应的信号,方便后续进行处理
- 何时处理?
- 合适的时候
- 何时处理?
- 一般而言,信号的产生相对于进程而言是异步的
2.信号处理方式概览
- 执行该信号的默认处理动作
- 忽略此信号
- 自定义动作(捕捉信号)
- 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数
- 信号捕捉初识
- **功能:**捕获特定的信号,执行自定的方法
- 原型:
sighandler_t signal(int signum, sighandler_t handler);
- 参数:
- **signum:**要捕获的信号
- **handler:**函数指针,要执行的自定方法
- 返回值:
- 不在乎
- 注意:
- signal函数,仅仅是修改进程对特性信号的后续处理动作,不是直接调用对应的处理动作
- 如果后续没有任何SIGNAL信号产生,handler永远不会被调用
3.理解信号如何被保存
- 需要解决两个问题 --> 什么信号?是否产生?
- 进程PCB内部保存了**信号位图**字段
- 第几个比特位表示什么信号
- 01表示是否产生信号
4.信号发送的本质
- 信号位图在task_struct --> task_struct内核数据结构 --> OS掌控
- 信号发送的本质:OS向目标进程写信号,OS直接修改PCB中的指定的位图结构,完成"发送"信号的过程
2.如何产生信号?
1.终端按键产生信号
- 键盘的工作方式是通过中断方式进行的
- 便可以**识别组合键,**如Ctrl + c
- OS解释组合键 --> 查找进程列表 --> 找到前台运行的进程 --> OS写入对应的信号到进程内部的位图结构中
2.系统调用接口
1.kill()
- **功能:**给指定的进程发送指定的信号
- 原型:
int kill(pid_t pid, int sig);
2.raise()
- **功能:**给当前进程发送指定的信号 --> 自己给自己发信号
- 原型:
int raise(int sig);
3.abort()
- **功能:通常用来终止进程,发送SIGABRT(6)**信号
- 原型:
void abort(void);
4.如何理解?
- 用户调用系统接口 --> 执行OS对应的系统调用代码 --> OS提取参数,或者设置特定的数值 --> OS****向目标进程写信号 --> 修改对应进程的信号标记位 --> 进程后续会处理信号 --> 执行对应的处理动作
3.由软件条件产生信号
- 如:管道读端不光不读,而且还关闭了,写端一直在写,会发生什么问题?
- 写没有意义,OS会自动终止对应的写端进程,通过发送信号(SIGPIPE)的方式
- 如:alarm() && SIGALRM
- 功能:
- 设定一个闹钟,告诉内核在seconds秒之后给当前进程发SIGALRM信号,该信号的默认处理动作是终止当前进程
- 闹钟一旦触发,就自动移除了
- 功能:
- 原型:
unsigned int alarm(unsigned int seconds);
- 返回值:
- 0
- 以前设定的闹钟时间还余下的秒数
- 如何理解?
- OS先识别到某种软件条件触发或不满足某条件 --> OS构建信号,发送给指定的进程
4.硬件异常产生信号
- 硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号
- 例如:当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程
- 例如:当前进程访问了非法内存地址,,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程
- 由此看出,在C/C++中,除零,内存越界等异常,在系统层面上,是被当成信号处理的
5.总结
- 所有的信号,有他的来源,但最终全部都是被OS识别,解释,并发送的