Linux信号:信号的保存

目录

一、信号在内核中的表示

 二、sigset_t

2.1sigset_t的概念和意义

2.2信号集操作数

三、信号集操作数的使用

3.1sigprocmask

3.2sigpending

3.3sigemptyset

四、代码演示


一、信号在内核中的表示

实际执行信号的处理动作称为信号 递达(Delivery)
信号从产生到递达之间的状态,称为信号 未决(Pending)
进程可以选择 阻塞 (Block ) 某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
信号在内核中的表示示意图
每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中
如上图所示:
SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。
如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。

 二、sigset_t

2.1sigset_t的概念和意义

Linux中,常用的信号有31个,内核中则存在一个类似于位图的方式来对该进程的block,peding进行表示,由于不存在0号信号,所以信号就从1号位置开始到31,如果该位置上为1则表示该信号当前存在,为0则表示不存在。

从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。下一节将详细介绍信号集的各种操作。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。
而为了方便统一管理,和安全性考虑,Linux中就设置了一种sigset_t的类型专门用于表示信号集。

2.2信号集操作数

sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的。
而常用的系统调用接口有如下几个:
#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在该信号集中添加或删除某种有效信号。

三、信号集操作数的使用

3.1sigprocmask

调用函数 sigprocmask 可以读取或更改进程的信号屏蔽字 ( 阻塞信号集)。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
返回值:若成功则为0,若出错则为-1
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

3.2sigpending

#include <signal.h>sigset_t pendig;
int n=sigpending(&pending);
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0则n=0,出错则返回-1则n=-1。

3.3sigemptyset

清空sigset_t类型内部的数据。

sigset_t pending;
sigemptyset(&pending);
考虑到各个平台的不同,这种方式可以很好解决在栈上生成随机值的情况

四、代码演示

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>
#include <sys/wait.h>void PrintSig(sigset_t &pending)
{std::cout << "Pending bitmap: ";for (int signo = 31; signo > 0; signo--){if (sigismember(&pending, signo))//判断该信号是否在信号集中{std::cout << "1";}else{std::cout << "0";}}std::cout << std::endl;
}void handler(int signo)
{sigset_t pending;sigemptyset(&pending);int n = sigpending(&pending); // 正在处理2号信号assert(n == 0);// 3. 打印pending位图中的收到的信号std::cout << "递达中...: ";PrintSig(pending); // 0: 递达之前,pending 2号已经被清0. 1: pending 2号被清0一定是递达之后std::cout << signo << " 号信号被递达处理..." << std::endl;
}int main()
{// 对2号信号进行自定义捕捉 --- 不让进程因为2号信号而终止signal(2, handler);// 1. 屏蔽2号信号sigset_t block, oblock;sigemptyset(&block);sigemptyset(&oblock);sigaddset(&block, 2); // SIGINT --- 根本就没有设置进当前进程的PCB block位图中// 0. for test: 如果我屏蔽了所有信号呢???// for(int signo = 1; signo <= 31; signo++) // 9, 19号信号无法被屏蔽, 18号信号会被做特殊处理//     sigaddset(&block, signo); // SIGINT --- 根本就没有设置进当前进程的PCB block位图中// 1.1 开始屏蔽2号信号,其实就是设置进入内核中int n = sigprocmask(SIG_SETMASK, &block, &oblock);assert(n == 0);// (void)n; // 骗过编译器,不要告警,因为我们后面用了n,不光光是定义std::cout << "block 2 signal success" << std::endl;std::cout << "pid: " << getpid() << std::endl;int cnt = 0;while (true){// 2. 获取进程的pending位图sigset_t pending;sigemptyset(&pending);n = sigpending(&pending);assert(n == 0);// 3. 打印pending位图中的收到的信号PrintSig(pending);cnt++;// 4. 解除对2号信号的屏蔽if (cnt == 20){std::cout << "解除对2号信号的屏蔽" << std::endl;n = sigprocmask(SIG_UNBLOCK, &block, &oblock); // 2号信号会被立即递达, 默认处理是终止进程assert(n == 0);}// 我还想看到pending 2号信号 1->0 : 递达二号信号!sleep(1);}return 0;
}

通过以上代码所演示的现象我们也可以验证两个结论:

1、递达信号的时候一定会把对应的pending位图清0。

2、先清0,再递达。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/14553.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql数据库——DML操作

目录 添加数据&#xff08;INSERT&#xff09; 修改数据&#xff08;UPDATE&#xff09; 删除数据&#xff08;DELETE&#xff09; 添加数据&#xff1a; &#xff08;1). 给指定字段添加数据 &#xff08;2). 给全部字段添加数据 &#xff08;3). 批量添加数据 修改数据: 案例…

【STM32】HAL库点灯

【STM32】HAL库点灯 一、探究目标二、探究原理2.1 ST开发库2.1.1 直接配置寄存器2.1.2 标准外设库2.1.3 HAL库2.2 HAL开发2.2.1 环境配置2.2.2 时钟配置2.2.3 GPIO配置2.2.4 工程创建2.2.5 KEIL代码![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bf1c95d5c6724a6a…

NextGen Mirth Connect XStream反序列化远程代码执行漏洞(CVE-2023-43208)

0x01 产品简介 NextGen Mirth Connect是是美国NextGen公司的一个医疗集成引擎,主要用于医疗领域的系统集成和数据交换,支持多种协议和标准。 0x02 漏洞概述 NextGen Mirth Connect 4.4.1之前版本存在远程代码执行漏洞,未经身份认证的攻击者可利用该漏洞远程执行代码。 0…

混合组网VS传统网络:智能硬件混合组网优劣势浅要解析

智能硬件混合组网是一种利用多种通信技术相结合的方法&#xff0c;以实现更灵活、更可靠的网络连接。通过蓝牙、Wi-Fi、LoRa、4G相互之间的不同通讯方式&#xff0c;根据应用场景的不同以及现场实际环境&#xff0c;优选最佳物联网混合组网方案&#xff0c;以达到部署最便捷性价…

一张SSL证书如何同时保护多个域名及其子域名?

在互联网时代&#xff0c;数据安全和隐私保护变得至关重要&#xff0c;而SSL证书作为确保网站安全的重要工具&#xff0c;其重要性不言而喻。本文将详细探讨一种特殊的SSL证书——多域名通配符SSL证书&#xff0c;它为网站管理员提供了一种高效、经济的方式来保护多个域名及其子…

MyBatis从入门到“入土“

&#x1f495;喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&#xff01;&#x1f495;(●◡●) 目录 一、Mybatis为何物&#xff1f;&#x1f44c; 二、快速入门&#x1f923; 1、新建项目&#x1f60a; 2、数据库建表&#x1f60a; 3、导入依赖的jar包&#x1f60a;…

Linux学习笔记6

TFTP 服务器搭建和测试 关于TFTP:TFTP&#xff08;Trivial File Transfer Protocol&#xff0c;简单文件传输协议&#xff09;&#xff0c;是一个基于UDP 协议实现 的用于在客户机和服务器之间进行简单文件传输的协议&#xff0c;适合于开销不大、不复杂的应用场合 搭建服务器…

后量子密码的发展和应用

后量子算法&#xff0c;特别是后量子密码(PQC)&#xff0c;是近年来密码学领域的一个热门话题。随着量子计算技术的快速发展&#xff0c;传统的公钥密码算法面临着被量子计算机破解的威胁。为了应对这一挑战&#xff0c;后量子密码应运而生&#xff0c;成为了一种能够抵抗量子计…

【论文笔记】| 蛋白质大模型ProLLaMA

【论文笔记】| 蛋白质大模型ProLLaMA ProLLaMA: A Protein Large Language Model for Multi-Task Protein Language Processing Peking University Theme: Domain Specific LLM Main work&#xff1a; 当前 ProLLM 的固有局限性&#xff1a;&#xff08;i&#xff09;缺乏自然…

Redis篇 在linux系统上安装Redis

安装Redis 在Ubuntu上安装Redis 在Ubuntu上安装Redis 在linux系统中,我们安装Redis,必须先使它有root权限. 那么在linux中,如何切换到root用户权限呢? sudo su 就可切换到用户权限了. 在切换到用户权限后,我们需要用一条命令来搜索Redis相关的软件包 apt search redis 会出现非…

ROS2学习——节点话题通信(2)

目录 一、ROS2节点 1.概念 2.实例 &#xff08;1&#xff09;ros2 run &#xff08;2&#xff09;ros2 node list &#xff08;3&#xff09;remapping重映射 &#xff08;4&#xff09;ros2 node info 二、话题 &#xff08;1&#xff09; ros2 topic list &#xf…

头歌openGauss-存储过程第1关:创建存储过程

编程要求 1、创建第1个存储过程&#xff0c;并调用&#xff1b; 1&#xff09;创建存储过程&#xff0c;查询emp表数据&#xff1b; 2&#xff09;调用存储过程&#xff1b; --创建存储过程&#xff0c;获得计算机&#xff08;cs&#xff09;系学生选课情况并将结果写入临时表t…

人脸识别:基于卷积神经网络(CNN)分类思想的人脸识别系统

本文来自公众号 “AI大道理” —————— 项目配套视频课程&#xff1a; 平台&#xff1a;荔枝微课 链接&#xff1a;十方教育 项目地址&#xff1a;https://github.com/AIBigTruth/CNN_faces_recognition 之前很多人来询问这个项目怎么做&#xff0c;代码跑不起来&#…

USB数据恢复软件:轻松找回U盘重要数据!

USB数据丢失的原因 USB数据丢失有一些常见原因&#xff0c;了解这些原因有利于恢复数据。 文件意外删除病毒攻击软件错误未安全弹出USB设备格式化USB设备 顺便一提&#xff0c;如果你通过快捷键“Ctrl D”删除了数据&#xff0c;那你可以从回收站中还原它们。如果你永久删除…

Isaac Sim仿真平台学习(1)认识Isaac Sim

0.前言 上一个教程中我们下载好了Isaac Sim&#xff0c;这一章我们将来简单了解一下Isaac Sim平台。 isaac Sim仿真平台安装-CSDN博客 1.Isaac Sim是啥&#xff1f; What Is Isaac Sim? — Omniverse IsaacSim latest documentation Isaac Sim是NVDIA Omniverse平台的机器…

【编译原理复习笔记】属性文法

属性文法 也称为属性翻译文法&#xff0c;由 Knuth 提出&#xff0c;以上下文无关文法为基础 &#xff08;1&#xff09;为每个文法符号&#xff08;终结符与非终结符&#xff09;配备相关的属性&#xff0c;代表与该文法符号相关的信息 &#xff08;2&#xff09;属性文法对于…

数据链路层协议——以太网协议

1. 数据链路层 网络层用于将数据从一台主机发送到另一台主机。传输层用于将数据可靠的从一台主机发送到另一台主机。&#xff08;网络层没有保证可靠性的策略&#xff0c;传输过程中可能会出现各种意外&#xff0c;例如&#xff1a;丢包&#xff0c;网络拥塞等。通过传输层可以…

跨域问题的4种解决方案

文章导读 前言 跨域问题指的是在Web开发中&#xff0c;由于浏览器的同源策略限制&#xff0c;当一个网页尝试访问与它不同源&#xff08;协议、域名或端口不同&#xff09;的资源时&#xff0c;可能会遇到安全限制导致无法正常访问的问题。这种策略旨在防止恶意网站读取或修改其…

订餐系统总结、

应用层&#xff1a; SpringBoot:快速构建Spring项目&#xff0c;采用“约定大于配置”的思想&#xff0c;简化Spring项目的配置开发。 SpringMvc&#xff1a;Spring框架的一个模块&#xff0c;springmvc和spring无需通过中间整合层进行整合&#xff0c;可以无缝集成。 Sprin…

完整的数据可视化方法集

在当前的大数据时代&#xff0c;了解如何可视化数据是UI/UX设计师技能的重要组成部分。如今&#xff0c;几乎所有的公司都需要良好的数据可视化作为确定业务方向和决策的参考。数据的可视化结果越好&#xff0c;用户的决策就越科学。 1、什么是数据可视化 数据可视化是将信息…