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,再递达。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用WindowsSpyBlocker防止Windows系统被恶意监控和跟踪

关于WindowsSpyBlocker WindowsSpyBlocker是一款功能强大的Windows系统安全防护工具&#xff0c;该工具基于Go语言开发&#xff0c;WindowsSpyBlocker以一个单独的可执行程序发布&#xff0c;可以帮助广大用户防止自己的Windows系统被恶意监控和跟踪。 WindowsSpyBlocker能够利…

【手势识别-UIPinchGestureRecognizer捏合-UIPanGestureRecognizer缩放 Objective-C语言】

一、接下来,我们来说这个捏合,和,这个缩放啊 1.捏合, 首先呢,步骤,也都是一样的啊, 1)创建手势对象 2)添加手势 3)实现手势方法 pinch:捏合 UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:(id) action:(SEL)]; U…

使用大模型结合Mermaid实现业务流程图快速生成

一、需求描述 在日常系统研发过程中&#xff0c;经常面临前期要写投标技术文档&#xff0c;中期要写系统概要设计、详细设计等各类文档&#xff0c;最耗时间的便是画一些业务流程图。随着大模型的不断普及&#xff0c;大模型对文字的处理越来越强&#xff0c;现可以找一个能简化…

MySQL主从复制+读写分离(ShardingJDBC)

MySQL主从复制读写分离 MySQL主从复制介绍二进制日志&#xff1a; MySQL的主从复制原理如下搭建主从复制准备工作主库配置从库配置 测试 读写分离案例ShardingJDBC介绍数据库环境初始工程导入读写分离配置测试1). 保存数据2). 修改数据3). 查询数据4). 删除数据 MySQL主从复制 …

LVS精益价值管理系统 DownLoad.aspx 任意文件读取漏洞复现

0x01 产品简介 LVS精益价值管理系统是杭州吉拉科技有限公司研发的一款专注于企业精益化管理和价值流优化的解决方案。该系统通过集成先进的数据分析工具、可视化的价值流映射技术和灵活的流程改善机制&#xff0c;帮助企业实现高效、低耗、高质量的生产和服务。 0x02 漏洞概述…

Java ( 框架界面 , 按钮 , 动作监听ActionListener ,鼠标监听MouseListener,键盘监听KeyListener)的使用方法

package 拼图阶段任务.ui;import javax.swing.*; import java.awt.*; import java.awt.event.*;public class UseMethod {public static void main(String[] args) { // 框架的用法JFrame jf new JFrame();// 设置界面的宽高jf.setSize(603,680);// 设置界面的标题jf.setTitle…

Redis的下载、安装、启动和初尝试【超级简单】

redis最好是在Linux系统中使用&#xff0c;这是最接近生产实际的环境。 不过&#xff0c;我们初学者&#xff0c;目的是学习Redis的使用、原理&#xff0c;如果在Linux下直接学习Redis&#xff0c;很可能会因为命令不熟悉而劝退&#xff0c;这是不好的。 因此&#xff0c;我主张…

国际货币基金组织警告:网络攻击影响全球金融稳定

近日&#xff0c;在一份关于金融稳定的报告中&#xff0c;国际货币基金组织&#xff08;IMF&#xff09;用了一章&#xff08;共三章&#xff09;的篇幅描述了网络攻击对金融环境的影响&#xff0c;并警告称&#xff0c;全球金融稳定正受到日益频繁和复杂的网络攻击的威胁。同时…

kubernetes(k8s) v1.30.1 创建本地镜像仓库 使用本地docker镜像仓库部署服务 Discuz X3.5 容器搭建论坛

1 master11创建本地镜像仓库 [rootmaster11 ~]# docker run -d -p 5000:5000 --restartalways --name registry registry:2 Unable to find image registry:2 locally 2: Pulling from library/registry 79e9f2f55bf5: Pull complete 0d96da54f60b: Pull complete 5b27040df…

是德科技 DSOS104A MSOS104A示波器

产品 带宽 通道数 最大存储器深度 DSOS104A 高清晰度示波器 1 GHz 4 个模拟通道 800 Mpts MSOS104A 高清晰度示波器 1 GHz 4 个模拟通道和 16 个数字通道 800 Mpts 商品介绍 …

ELK 日志监控平台(一)- 快速搭建

文章目录 ELK 日志监控平台&#xff08;一&#xff09;- 快速搭建1.ELK 简介2.Elasticsearch安装部署3.Logstash安装部署4.Kibana安装部署5.日志收集DEMO5.1.创建SpringBoot应用依赖导入日志配置文件 logback.xml启动类目录结构启动项目 5.2.创建Logstash配置文件5.3.重新启动L…

锁相环的一些学习笔记--(1)

下图两组1.2.3可以对应起来&#xff1b; 参考资料&#xff1a; 1. Matlab https://www.bilibili.com/video/BV1bR4y1Z7Xg/?spm_id_from333.1296.top_right_bar_window_history.content.click&vd_source5556680656536651c49f5e55d7d4df23 2. https://www.bilibili.com/…

Hadoop开发之JavaAPI操作HDFS

目录 一、maven的安装与配置1.maven的下载2.maven的安装与配置&#xff08;1&#xff09;解压&#xff08;2&#xff09;创建本地仓库文件夹&#xff08;3&#xff09;修改settings.xml配置文件&#xff08;4&#xff09;配置maven的环境变量&#xff08;5&#xff09;idea中ma…

将list对象里的某一个属性取出组成一个新的list

使用Java8将对象里的某一个属性取出组成一个新的list List<Spgg1> listnew ArrayList<>();Spgg1 spgg1new Spgg1();spgg1.setSpdm("测试");spgg1.setGgdm("001");list.add(spgg1);Spgg1 spgg2new Spgg1();spgg2.setSpdm("测试2");sp…

不用从头训练,通过知识融合创建强大的统一模型

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的开发和训练是一个复杂且成本高昂的过程。数据需求是一个主要问题&#xff0c;因为训练这些模型需要大量的标注数据来保证其准确性和泛化能力&#xff1b;计算资源也是一个…

基于 Prometheus 的超算弹性计算场景下主机监控最佳实践

作者&#xff1a;左知 超算场景的业务特点 主机监控&#xff0c;或许是监控/可观测领域最传统和普遍的需求。在超算训练&#xff0c;AI 大规模训练的业务场景下&#xff0c;主机监控又有哪些痛点和难点呢&#xff1f;根据我们针对多个大规模超算客户的需求整理&#xff0c;超…

LeetCode:柱状图中最大的矩形

文章收录于LeetCode专栏 LeetCode地址 柱状图中最大的矩形 题目 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例1 **输入&#xff1a;**heights …

FastAPI单元测试:使用TestClient轻松测试你的API

当使用FastAPI进行单元测试时&#xff0c;一个重要的工具是TestClient类。TestClient类允许我们模拟对FastAPI应用程序的HTTP请求&#xff0c;并测试应用程序的响应。这使我们能够在不启动服务器的情况下对API进行全面的测试。 下面我将详细讲解TestClient的使用方法和常见操作…

empirecms 文件上传 (CVE-2018-18086)

漏洞环境&#xff1a;vulfocus 到管理后台 使用用户名密码&#xff1a;admin:123456登录&#xff0c;然后到后台找到文件上传点 发现需要后缀名为.mod 创建生成一句话木马的php脚本&#xff0c;并添加.mod后缀名&#xff0c;然后提交 <?php file_put_contents("shell…

攻防世界---web---warmup

1、题目描述 2、查看源码&#xff0c;发现有个source.php 3、访问该文件&#xff0c;得到这一串代码 4、分析代码 5、访问hint.php&#xff0c;提示flag在ffffllllaaaagggg这个文件下 6、构造payload ?filesource.php?/../../../../../../ffffllllaaaagggg