Linux进程信号保存/操作系统运行原理
知识补充:
系统调用:pause(); 该函数可以等待发出信号
signal:可以进行信号捕捉
其中,信号捕捉分为三点:
1,默认
2,忽略
3,自定义
默认和忽略系统中给我们提供了具体调用方法:
默认:SIG_DFL
自定义:SIG_IGN
信号相关的其他概念
1,实际执行信号的处理动作称为信号递达
2,信号从产生到递达之间的状态叫做信号未决
3,进程可以选择阻塞某个信号
(信号产生之后会对阻塞的目标信号进行pending,永远不递达,除非我们解除阻塞)
4,被阻塞的信号产生时会一直处于未决状态,直到解除阻塞状态,信号才能执行递达的动作。
5,注意,忽略和阻塞是不同的,只要信号被阻塞就不会被递达,而忽略是递达之后可选的一种处理动作。
进程如何完成进程保存的
在task_struct中维护着三张表,分别叫block,pending,handler
pending
pending表本质就是位图(1-31)
含义:
1,比特位位置代表信号编号。
2,比特位内容 0/1 代表是否收到对应的信号。
pending位图就是当前进程收到的信号列表
handler
handler表本质其实是一个函数指针列表,信号编号-1就是函数指针数组的下标
所以,signal(2,handler)中2就是去找下标,handler就是去修改数组内的内容
这也就是为什么signal改一次之后,后面的内容都会变成自定义内容。
block
block表其实本质也是一张位图,也是维护1-31的内容
含义:
1,比特位位置代表信号编号
2,比特位内容0/1代表是否阻塞,屏蔽特定信号,决定了pending是否可以访问handler表。
我们可以提前屏蔽,屏蔽课收到信号两者毫无关系。
所以,要看某个信号是否要被处理,我们可以横着看:
如果block里值为1,pending值为1,就不递达
如果block里值为零,pending值为0,也不做处理
如果block里值为0,pending值为1,就会对信号进行处理:
信号集操作函数
sigset_t
这是系统封装的pending/block的数据类型,可对其内容进行改变,但是修改内容涉及位图的操作,容易产生失误,所以系统也提供了余其他函数来对sigset_t进行操作:
sigemptyset:可以将位图初始化为全0
sigfillset:可以将位初始化为全1
sigaddset:可以将signum信号添加到set中
sigdelset:可以将特定信号删除
sigismember:可以判断signum信号是否在set里
sigprocmask
该函数可以读或者该进程信号的屏蔽字:
其中,how代表用什么方式进行修改,系统提供了三种函数来供我们使用:
其中第三个参数是可以拷贝一份老的数据出来做备份的。
sigpending
sigpending的参数属于输出型参数,可以获取pending信号集
代码演示
接下来将用代码的方式来混用上面的函数,以便大家理解:
1,对2号信号进行屏蔽
2,如何获取pending表
3,如何解除屏蔽?
可以使用之前备份的oblock来进行备份:
代码如下:
可以看到,当我们解除了二号信号屏蔽,系统就会执行二号信号,二号信号默认行为是退出,如何我们没对信号进行捕捉,所以进程就会退出。
信号捕捉
在主函数因为中断,异常或系统调用将进入内核处理,处理完后可以递送的信号,字给到信号处理,如果信号处理为忽略或者默认就回到主流程,如果是自定义就会调用用户自定义函数,如何在进到内核流程中被中断的地方继续执行。
os运行状态
1,用户态---我自己写的代码
2,内核态---执行os代码
所以信号捕捉流程:
os是怎么运行的
1,硬件中断
在图中左侧有各种各样的外设,当他们的内容准备就绪时,就会通知中断控制器,通知cpu,cpu知道中断之后会回来获取中断号,如何去os根据中断号在中断向量表中找对应的方法并执行,当执行完毕之后会恢复现场并持续刚刚的工作。
2,时钟中断
此中断会一直推进os的调度,在当代设备中,有一个时钟源会一直给os发送时钟中断,而这个时钟源现在在cpu中,如果在外设的话就太慢了,而时钟源发送的频率称为主频,主频越高代表cpu利用效率越高,调用os的次数就越多,cpu也越贵。
此时我们知道,os是基于中断向量表工作的,cpu中时钟源会不断地推进os的运行
os这样就可以之间躺平,要什么就去向量表拿。
3,软件中断
除了上面说的硬件中断,还有软件中断,cpu用和汇编可以让cpu内部促发中断逻辑
4,什么是时间片?
就是时钟中断时固定的发过来:1纳秒
task_struct
{
int count = 1000;
count--;
if(count == 0);---
}
时间片本质就是一个计数器,当count==0时,就进行进程切换。
内核页表
一个进程中除了有用户页表,也有一个内核页表:
在每一个进程中,用户页表每个进程互不影响,相互独立,但是在所有进程中,内核页表整个系统就只有一个,所以无论进程怎么调用调度,都能找到同一个os。