【Linux】信号(二)

上一章节我们进行了信号产生的讲解。

本节将围绕信号保存展开,并会将处理部分开一个头。

目录

信号保存:

信号的一些概念:

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号。

对于递达:也就是我们之前一直在说的处理,仍然是3种处理方法

  1. 默认行为 2. 忽略行为 3. 自定义行为

对于未决:是信号产生到递达之间的状态。

对于阻塞:当我们阻塞一个信号,信号一旦产生,永不递达,知道解除阻塞状态。

那么现在我们要进行一个概念的区分。

一个信号如果阻塞和他是否未决有关系吗?

这就像你讨厌一个老师(阻塞),你不会做他布置的作业(递达),但是并不妨碍你将作业记下来(未决)。所以其实是没关系的!

但以上都只是概念

我们要继续深入原理:

我们之前说过发信号实际就是在task_struct中进行pending位图的修改,但除了pending我们还有一个block位图与一张hanler表。

block对应阻塞,pending对应未决,handler对应递达。


既然我们最熟悉pending,那么就先从pending开始。

我们说过pending是一张位图。

0000 0000 0000 0000 0000 0000 0000 0000

第0个比特位不用,比特位的位置代表信号编号。

比特位的内容代表信号是否收到。


再来看handler表。

提到handler表我们又要把signal函数拿出来

handler表的每个元素实际就是

这个类型的函数指针。

我们使用signal时,实际上就是在修改handler表,将信号编号直接对应到这个数组的下标


最后来看block位图。

和pending是非常类似的。

0000 0000 0000 0000 0000 0000 0000 0000

比特位的位置:代表信号编号

比特位的内容:当前信号是否阻塞


所以只要有两个位图+一张表 就能让进程识别信号。

最后在补充两个概念。

  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
  • 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

关于信号保存的接口:

在说到接口前我们还需要铺垫一个linux提供的一个类型sigset_t。

sigset_t的解释:

从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。

因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的"有效"或"无效"状态,在阻塞信号集中"有效"和"无效"的含义是该信号是否被阻塞,而在未决信号集中"有效"和"无效"的含义是该信号是否处于未决状态。

等了解了sigset_t将详细介绍信号集的各种操作。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的"屏蔽"应该理解为阻塞而不是忽略。

linux中定义为下:

我们先自己模拟一个位图便于理解sigset_t。

同样,我们不推荐自己操作位图,因为不同系统位图的结构可能不同,就不能正确的运行,因此,OS也提供了一批函数进行操作这个类型。

对应的操作接口:

cpp 复制代码
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。

函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。

注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。

这四个函数都是成功返回0,出错返回-1。sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种 信号,若包含则返回1,不包含则返回0,出错返回-1.

我们现在知道了信号位图和对应的操作,那么怎么获得block与pending??

因为task_struct是属于内核的,所以只有OS可以进行获取与修改,所以OS就要提供对应的系统调用供我们使用。


我们先来看block的操作函数

sigprocmask:

参数解释:

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

sigpending:

我们对于pending位图该怎么操作呢?

实际上我们已经学完了!就是信号发送的5种方式,修改了对应的位图,那么怎么进行获取?

使用上图函数即可获取。

代码实践:

阶段一:


我们先将获取pending,随后对2号屏蔽,观察现象。

进行kill -2

现象:


阶段二:

此时我们再尝试恢复一下对二号信号。

但要捕捉一下,否则解除屏蔽的瞬间就直接进行终止了。

改动后的代码:

现象:

持续更新...

相关推荐
A小辣椒2 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux