OS——信号

目录

信号是什么

信号的类型

信号的产生

两种方式

发送信号的系统调用

关于定时器

信号的保存和信号处理

理清概念

信号处理的时机

修改block表的系统调用

获取pending位图

修改handler数组

不可屏蔽的信号

core和term


信号是什么

我们都知道,OS中很大一部分是靠中断(不管是硬件中断还是软中断)运行起来的,所以早期操作系统又叫做中断处理程序。
而信号的机制是与中断类似的一种通知机制,分为产生信号(产生中断),保存信号(保存中断),处理信号(中断处理)个步骤。


信号的类型


信号的产生

两种方式

  • 硬件触发**。例如:我们点击键盘的"ctrl + c"会首先触发中断,然后调用中断处理例程,在其内部判断到时这个组合键之后就会给当前的前台进程发送死亡信号,终止前台进程。**
  • 软件触发**。我们可以通过系统调用来发送信号;或者在OS中创建定时任务,由定时任务发送信号;也可以在命令行中输入发送信号的命令(kill);再比如管道写时如果读不具备就会给写的进程发送终止信号****。**

发送信号的系统调用

cpp 复制代码
//给进程号为pid的进程发送sig信号
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);


//调用它的进程给自己发送sig信号
#include <signal.h>
int raise(int sig);

//给本进程发送SIGABRT信号,杀死自己
#include <stdlib.h>
void abort(void);


//在seconds秒之后给调用alarm的进程发送SIGALRM信号,SIGALRM信号的默认处理方式是杀死进程
#include <unistd.h>
unsigned int alarm(unsigned int seconds);//如果在前一个alarm没有起作用前再一次调用它,则重置倒计时并返回上一个闹钟剩余的秒数,alarm(0)意思是取消所设的闹钟。
   

关于定时器

其实每一个定时器就是OS内部的数据结构,所有的定时器被组织成对应的数据结构,OS依靠硬件进行计时,到了过期时间就执行定时器内部绑定的回调方法。而alarm函数就是告诉OS:给我创建一个定时器,这个定时器的任务是给当前进程发送SIGALARM信号。进程收到信号就会执行信号处理函数(默认杀死自己)。


信号的保存和信号处理

理清概念

信号的发送和程序的执行是异步的,因此在我们发送信号给进程后,进程可能正在执行其他指令,而且在一些情况下(比如IO),这种指令是不可以被打断的,所以进程必须有暂时保存信号的能力。话不多说,信号是保存在进程PCB里面的位图中的,信号的处理函数也是保存在PCB中的,除此之外PCB中还有表示屏蔽某信号的位图。如下图:

  • 信号被发送给进程之后,将pending位图相应位置置1,pending位图中就存放着所有进程收到的信号,这就是发送信号的本质。
  • 如果信号没有被处理,pending相应位置就会一直为1。在这次信号被处理之前发送多个信号是无效的。
  • 进程想要阻塞某信号就把block位图相应位置置1。即使阻塞了某信号,进程也会把收到的某信号存放在pending中,一但运行过程中取消阻塞,曾经被阻塞的信号还会被处理。
  • 进程会在合适的时机查看pending表,如果发现某信号对应的位置为1并且block中对应的位置为0,就执行对应的信号处理函数,而这些默认的信号处理函数的函数指针被存放在handler数组中,可以把信号编号当作下标取出对应的函数指针并执行,然后把pending表相应位置置0,表示信号被处理完了。这就是信号处理的本质。
  • 进程PCB在创建之时默认初始化handler数组,所以我们发送的信号都有其对应的默认处理方法,SIG_IGN表示忽略该信号。我们可以使用系统调用来修改某信号对应的信号处理函数,也就是修改handler表,让进程用我们定义的函数来处理相应信号。

术语:某信号在pending中时叫做信号未决,信号被处理叫做信号递达,自定义信号处理函数叫做信号捕捉

信号处理的时机

内核处理完异常或者执行完系统调用后,要返回用户态之前,会处理当前进程的PCB中的pending中的信号,这就是信号处理的时机**。自定义信号的处理流程如下:**

为什么要从内核返回用户才可以执行信号处理函数,内核态权限不是更高吗?

  • 如果信号处理函数中有访问操作系统的代码,那么就可以利用内核态的权限直接对操作系统做任何事,这样很危险,所以要把内核态转回用户态才可以执行函数。

为什么函数执行后不直接返回main函数而是要先返回内核态

  • 无法返回,main函数和signal处理函数无调用关系,无法直接返回,而do_signal()和main函数有调用关系。

如果是非自定义信号的处理函数,会直接在内核态执行,执行结束后直接返回用户态的main函数中。

修改block表的系统调用

获取pending位图

修改handler数组

注:如果我们是自定义信号处理函数的话,在函数内部可能再次陷入系统调用,如果此时再次到来相同的信号就又会调用相同的信号处理函数.....如果一直发送该信号的话就会导致栈溢出,而sa_mask可以设置执行自定义信号处理函数时要屏蔽的信号(比如说屏蔽当前正在处理的信号,就不会调用两次同一个处理函数了),防止上面的情况出现


不可屏蔽的信号

如果所有的信号都是可以屏蔽的,那么一个进程运行起来屏蔽所有信号,他就可以一直运行下去,不会被杀死,因此在OS,一些信号比如9号信号(终止进程)不能被屏蔽(也不能被自定义信号处理函数)


core和term

SIGQUIT和SIGINT的都是进程退出信号但是他们一个是core终止,一个是term终止,前者是异常终止进程,后者是正常终止进程。

如果开启了对应功能,core发生后就会在进程当前工作目录生成core文件,保存错误,gdb可以用这个文件快速定位发生异常的位置。而云服务器一般是关闭core文件生成功能,防止core文件把磁盘打满。

利用core文件的方法如下:

core和进程等待的关系:

父进程等待子进程结束后会获取到子进程的结束信息,这个里面就有一个core标志位。

相关推荐
星马梦缘3 天前
快表、页表地址获取+缓存、主存、硬盘数据获取
算法·操作系统·os·tlb
梁山好汉(Ls_man)9 天前
关于华为鸿蒙系统5A标志的几点看法
华为·鸿蒙·信号·5a
深念Y13 天前
中兴BAV系列机顶盒WiFi天线改造记:从合盖信号差到外壳开孔外置
网络·wifi·天线·信号·diy·数码·机顶盒
艾莉丝努力练剑18 天前
【Linux信号】Linux进程信号
linux·运维·服务器·学习·操作系统·进程·信号
mifengxing22 天前
操作系统(三)
操作系统·多线程·os·进程信息传递
551只玄猫25 天前
【操作系统原理 实验报告6】磁盘调度算法
算法·操作系统·os·实验报告·操作系统原理·磁盘调度算法·磁盘调度
AMoon丶1 个月前
Golang--内存管理
开发语言·后端·算法·缓存·golang·os
HIT_Weston1 个月前
170、【OS】【Nuttx】【ARMV7M】任务跳转(上下文切换)(一)
os·nuttx·armv7m
HIT_Weston1 个月前
171、【OS】【Nuttx】【ARMV7M】任务跳转(上下文切换)(二)
os·nuttx·armv7m