Linux进程信号——信号的捕捉、保存、处理
文章目录
-
- 信号的基本概念
- 信号保存
-
- block位图
- pending位图
- handler数组
-
信号处理技术
-
- 在时间T处的信号集合操作
- 空信号集合用于表示不存在的数据点
- 完整信号集合涵盖所有可能的状态信息
- 提供动态调整信号元素的功能模块
- 包括添加新元素和删除旧元素的操作模块组
- 实现基于集合论的信号成员资格判定方法
-
基于程序式的信号掩码操作实现模块组
-
捕捉信号
-
信号的基本概念
- 信号接收:系统实际执行的操作
- 信号等待:从产生到接收之前的等待状态
- 信号阻塞:无法被接收的输入信息
- 该系统对该动作进行了忽视
阻塞和忽略的区别
阻塞指的是这个信号不会被递达,也就是不对其进行操作处理
忽略指的是这个信号可以递达,只是处理的动作是忽略
信号保存

在进程的PCB中有如下三个数据结构和信号相关
前两个是位图,后一个是数组
block位图
该位图标识所承载的信号通路状态,在二进制状态下用0或1标记;每个特定的位置对应一个特定的信号。
pending位图
该位图用于记录接收到的信号信息;以二进制形式表示接收到与否的状态;某个位置代表对应的信号;也可称为信号集合;即未处理的情况
handler数组
这个数组由函数指针构成,在内部存储着多个函数指针对象。每个下标对应接收特定编号的信号;当某个处理方法被调用时,则会根据接收的信号选择相应的处理逻辑。
SIG_DFL宏代表这个函数是默认处理函数
SIG_IGN宏代表收到这个信号后,进行忽略这个信号
信号处理

该函数允许手动修改handler数组,并使进程在捕获特定信号时执行相应的处理逻辑。
#include<iostream>
#include<signal.h>
using namespace std;
void func1(int signum)
{
cout<<"进程捕捉到"<<signum<<"号信号,PID为:"<<getpid()<<endl;
}
int main()
{
signal(SIGINT, func1);
while(1)
{
cout<<"进程PID为:"<<getpid()<<endl;
sleep(1);
}
return 0;
}

sigset_t
从本质上看,这种数据结构是一种位图,并且其中包含block位图和pending位图这两种类型的数据结构
对于这个数据结构也有很多操作
sigemptyset
int sigemptyset(sigset_t *set)
这个函数是设置set锁指向相应的信号集,并将其置零以确保其不再拥有任何有效的信号源
sigfillset
int sigfillset(sigset_t *set)
这个函数是初始化全部置一,让其包含所有信号
sigaddset sigdelset
int sigaddset(sigset_t *set. int signo)
这两个是一对,分别对应添加和删除
确保整个信号集处于确定状态之前,在使用sigset_t时必须调用前面的任意一个初始化函数
sigismember
int sigismember(const sigset_t* set, int signo)
这个是用来判断是否有效,有效则返回1,无效返回0
sigprocmask
这个函数可以用于读取或更改阻塞信号集,也成为信号屏蔽字
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
成功返回0,出错返回-1
这里有几种情况
如果当set和oset均不为空指针时,则该函数将原来的屏蔽字复制至oset中,并遵循how参数所规定的规则进行修改
如果set不为空而oset为空,则该函数将直接按照指定的方式执行
如果set为空指针而oset非空,则读取当前进程的信号屏蔽字
假设当前进程的信号屏蔽字是mask,我们期望更改的信号集是set
how的参数和功能如下
- SIG_BLOCK:此时设置信号集表示我们想要加入到当前屏蔽字中的所有信号集合。其原理为通过位运算操作将mask |= set;
- SIG_UNBLOCK:此时设置用于从当前屏蔽字中解除阻塞状态的信号集合。
- SIG_SETMASK:此时代替的方式相当于直接赋值给mask变量。
- SIG_UNBLOCK:此时设置用于从当前屏蔽字中解除阻塞状态的信号集合。
捕捉信号
先说结论再说原理
当进程从内核态转换为用户态时,会自动进行信号的检测和捕捉处理
通常情况下,在代码运行中时操作系统保持着用户态的状态;然而在遇到系统调用请求或发生异常中断的情况下,则会导致操作系统切换至内核态。
由于系统调用与异常处理本质上涉及的是底层代码与函数,在这种情况下仅有内核态环境才能支持其运行,并且在此状态下该进程的优先级显著提升
最基础的是位于CPU内部的一个特定寄存器——CR3寄存器——它用于指示当前CPU所处的状态:数值1代表内核态、数值3则代表用户态。对用户而言是完全看不到的这一功能属性仅由操作系统的管控来保证。
也就是说当程序执行系统调用时会进入内核态
执行完系统调用时会回到用户态
在状态转换的时候,就进行信号的检测和处理
当这时有信号到来的时候,代码会跳转到信号处理的函数
当信号处理函数返回时还会执行特殊的系统调用,再回到内核态
大概流程如下图

