OS——信号

张开发
2026/4/18 8:31:59 15 分钟阅读

分享文章

OS——信号
目录信号是什么信号的类型信号的产生两种方式发送信号的系统调用关于定时器信号的保存和信号处理理清概念信号处理的时机修改block表的系统调用获取pending位图修改handler数组不可屏蔽的信号core和term信号是什么我们都知道OS中很大一部分是靠中断不管是硬件中断还是软中断运行起来的所以早期操作系统又叫做中断处理程序。而信号的机制是与中断类似的一种通知机制分为产生信号产生中断保存信号保存中断处理信号中断处理个步骤。信号的类型信号的产生两种方式硬件触发。例如我们点击键盘的“ctrl c”会首先触发中断然后调用中断处理例程在其内部判断到时这个组合键之后就会给当前的前台进程发送死亡信号终止前台进程。软件触发。我们可以通过系统调用来发送信号或者在OS中创建定时任务由定时任务发送信号也可以在命令行中输入发送信号的命令kill再比如管道写时如果读不具备就会给写的进程发送终止信号。发送信号的系统调用//给进程号为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没有起作用前再一次调用它则重置倒计时并返回上一个闹钟剩余的秒数alarm0意思是取消所设的闹钟。关于定时器其实每一个定时器就是OS内部的数据结构所有的定时器被组织成对应的数据结构OS依靠硬件进行计时到了过期时间就执行定时器内部绑定的回调方法。而alarm函数就是告诉OS给我创建一个定时器这个定时器的任务是给当前进程发送SIGALARM信号。进程收到信号就会执行信号处理函数默认杀死自己。信号的保存和信号处理理清概念信号的发送和程序的执行是异步的因此在我们发送信号给进程后进程可能正在执行其他指令而且在一些情况下比如IO这种指令是不可以被打断的所以进程必须有暂时保存信号的能力。话不多说信号是保存在进程PCB里面的位图中的信号的处理函数也是保存在PCB中的除此之外PCB中还有表示屏蔽某信号的位图。如下图信号被发送给进程之后将pending位图相应位置置1pending位图中就存放着所有进程收到的信号这就是发送信号的本质。如果信号没有被处理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和termSIGQUIT和SIGINT的都是进程退出信号但是他们一个是core终止一个是term终止前者是异常终止进程后者是正常终止进程。如果开启了对应功能core发生后就会在进程当前工作目录生成core文件保存错误gdb可以用这个文件快速定位发生异常的位置。而云服务器一般是关闭core文件生成功能防止core文件把磁盘打满。利用core文件的方法如下core和进程等待的关系父进程等待子进程结束后会获取到子进程的结束信息这个里面就有一个core标志位。

更多文章