汕尾海湾 发表于 2024-6-15 00:54:57

【Linux】信号(二)

上一章节我们进行了信号产生的讲解。
https://img-blog.csdnimg.cn/direct/8ac2bc1201764a72a8a6ec1e924b7438.png
本节将围绕信号保存展开。


信号保存:

信号的一些概念:



[*]实际执行信号的处理处罚动作称为信号递达(Delivery)
[*]信号从产生到递达之间的状态,称为信号未决(Pending)。
[*]进程可以选择壅闭 (Block )某个信号。
对于递达:也就是我们之前不停在说的处理处罚,仍然是3种处理处罚方法

[*]默认行为 2. 忽略行为 3. 自界说行为
对于未决:是信号产生到递达之间的状态。
对于壅闭:当我们壅闭一个信号,信号一旦产生,永不递达,知道解除壅闭状态。
那么现在我们要进行一个概念的区分。
一个信号如果壅闭和他是否未决有关系吗?
这就像你讨厌一个老师(壅闭),你不会做他布置的作业(递达),但是并不妨碍你将作业记下来(未决)。以是着实是没关系的!
但以上都只是概念
我们要继承深入原理:
我们之前说过发信号实际就是在task_struct中进行pending位图的修改,但除了pending我们还有一个block位图与一张hanler表。
block对应壅闭,pending对应未决,handler对应递达。
https://img-blog.csdnimg.cn/direct/dc6726c8663149ddac275fbbc23f479f.png
既然我们最认识pending,那么就先从pending开始。
我们说过pending是一张位图。
0000 0000 0000 0000 0000 0000 0000 0000
第0个比特位不用,比特位的位置代表信号编号。
比特位的内容代表信号是否收到。
再来看handler表。
提到handler表我们又要把signal函数拿出来https://img-blog.csdnimg.cn/direct/67a7363fdf1448d8af3a10659ea99440.png
handler表的每个元素实际就是https://img-blog.csdnimg.cn/direct/f82a0d8b5a8242e5bdee5beef242ec93.png
这个类型的函数指针。
我们利用signal时,实际上就是在修改handler表,将信号编号直接对应到这个数组的下标
https://img-blog.csdnimg.cn/direct/8f6421ea95ea4022a4642a7dd36cd2ad.png
末了来看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中界说为下:
https://img-blog.csdnimg.cn/direct/015f9ccbb2b34d1aa5437a8df4621b7d.png
我们先本身模拟一个位图便于理解sigset_t。
https://img-blog.csdnimg.cn/direct/6dea0e838274439e80584b52cd26ff98.png
同样,我们不推荐本身操纵位图,因为差别体系位图的结构可能差别,就不能正确的运行,因此,OS也提供了一批函数进行操纵这个类型。
对应的操纵接口:

#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:

https://img-blog.csdnimg.cn/direct/e1029ffa7c144e069ac27ff8bb3942ca.png
参数表明:
   如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指示怎样更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表阐明了how参数的可选值。
https://img-blog.csdnimg.cn/direct/d7b47c35d4a54f299f6e8d6ac36b1eee.png
如果调用sigprocmask解除了对当前若干个未决信号的壅闭,则在sigprocmask返回前,至少将其中一个信号递达。
sigpending:

我们对于pending位图该怎么操纵呢?
实际上我们已经学完了!就是信号发送的5种方式,修改了对应的位图,那么怎么进行获取?
https://img-blog.csdnimg.cn/direct/b1de9ff90fc240c1a235a61d2d08dbf8.png
利用上图函数即可获取。
代码实践:

阶段一:
我们先将获取pending,随后对2号屏蔽,观察征象。
https://img-blog.csdnimg.cn/direct/af4e81cec2a14ee48452a4f57167514a.png
进行kill -2
https://img-blog.csdnimg.cn/direct/cbaa3afc6d2940e6b9f2755c05ec85f3.png
征象:
https://img-blog.csdnimg.cn/direct/15dc53d5e96e42a5971591d621138db8.png
阶段二:
此时我们再尝试规复一下对二号信号。
但要捕获一下,否则解除屏蔽的瞬间就直接进行终止了。
改动后的代码:
https://img-blog.csdnimg.cn/direct/9ff3620181a141219b25a871d7f7a712.png
征象:
https://img-blog.csdnimg.cn/direct/4ae799546d554cd6bb9d0d7b9cf22459.png
现在我们只剩末了一个题目就完成了对信号保存的学习。
当执行完信号后,pending位图也要被清零,那么是在执行handler前清零照旧执行handler后清零?
我们做一个小测试即可。
在handler中进行打印一下pending位图即可
代码:
https://img-blog.csdnimg.cn/direct/44763bdfa7e94054ad2272b762ea4823.png
征象:
https://img-blog.csdnimg.cn/direct/460d59de05bc4053a6ef8307b8b46804.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【Linux】信号(二)