【Linux】信号的保存信号的捕捉信号集零碎知识点总结

news2024/12/28 5:01:52

【Linux】信号的保存&信号的捕捉&信号集&零碎知识点总结

  • 一、信号的保存
    • 1.1 信号几种概念
    • 1.2 信号在内核中的表示
  • 二、信号的捕捉
    • 了解用户态和内核态
    • 2.1 捕捉过程
    • 2.2 信号的捕捉方法
    • 2.3 信号捕捉规则
    • 2.4 多信号屏蔽问题
  • 三、信号集
    • 3.1 概念
    • 3.2 信号集(sigset_t)操作函数
  • 四、可重入函数
  • 五、volatile关键字
  • 六、SIGCHLD

在这里插入图片描述

在这里插入图片描述

一、信号的保存

1.1 信号几种概念

实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞 (Block )某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

1.2 信号在内核中的表示

原理图,一图速览内核中信号的基本数据结构构成
内核中信号基本数据结构构成

在进程内部要保存信号周边的信息,有3种数据结构与之是强相关的,pending表,Block表,Handler表

  1. 进程可能在任何时候收到OS给它发送的信号,该信号可能暂时不被处理,所以需要暂时被保存,进程为了保存信号采用位图来保存,这个位图就是pending位图,被置于pending位图的信号处于未决状态。OS向进程发信号就是向目标进程的pending位图设置比特位,从0到1就是当前进程收到该信号,所以发信号应该是写信号,PCB属于OS内核结构,只有OS有权力修改pending位图,所以发送信号的载体只能是OS。
  2. block位图:block位图比特位的位置代表信号标号,比特位的内容代表是否阻塞了该信号
  3. Handler表,内核中有指针指向该数组,这个数组称为当前进程所匹配的信号递达的所有方法,数组的位置(下标)代表信号的编号,数组下标对应的内容表示对应信号的处理方法.

⚠️重点:我们之前所谈到的信号接口signal(signo,handler)的本质是:根据信号编号,找到数组对应的下标,然后将用户层设置的handler函数的地址填到数组对应下标处,等信号产生时候,修改pending表比特位,根据Block表判断该比特位是否被阻塞。信号被递达时,OS拿到信号根据信号位置得到信号的编号,进而访问数组得到信号的处理方法。

二、信号的捕捉

信号产生的时候,可能不会立即处理,会在合适的时候从内核态返回用户态的时候处理。

了解用户态和内核态

  • 用户为了访问内核或者硬件资源必须要使用系统调用,系统调用是OS提供的接口,而普通用户不能以用户态的身份执行系统调用,必须让自己的身份切换成成内核态。

  • 一个进程在执行时必须把上下文信息切换到CPU中,CPU中有大量的寄存器,寄存器可分为可见寄存器(eax,ebx…),不可见寄存器(状态寄存器…),凡是和当前进程强相关的,是上下文数据。

    寄存器中还有非常多的寄存器在进程中有特定作用,寄存器可以指向进程PCB,也可以保存当前用户级的页表,指向页表起始地址

    寄存器中还有CR3寄存器:表征当前进程的运行级别:0表示内核态,3表示用户态

进程如何去OS中执行方法
在这里插入图片描述

  • 以前所说的进程地址空间0-3G是用户级页表,通过用户级页表映射到不同的物理空间处,而除了用户级页表之外,还有内核级页表,OS为了维护从虚拟地址到物理地址之间的OS级别的代码所构成的内核级映射表。
  • 3G-4G是OS内部的映射,所以进程建立映射的时候不仅仅把用户的代码、数据和进程产生关联,每一个进程都要通过内核级页表和OS产生关联,而每一个进程都有自己的地址空间,其中用户级空间自己占有,而内核空间是被映射到了每一个进程的3-4G空间,每一个进程都可以通过页表映射到OS,而且每个进程看到的OS都是一样的,所以进程要访问OS的接口,其实只需要在自己的地址空间上进行跳转就可以了
  • 每一个进程都有3-4GB,都会共享一个内核级页表,无论进程如何切换,都不会更改任何的3-4GB。

用户通过什么能够执行访问内核的接口或者数据

  • 当要访问3-4G任何一个地址时,OS立马读取CPU中的CR3寄存器,得到运行状态。所以系统调用接口起始的位置会帮我们把用户态变成内核态,从3号状态改成0号状态。
    OS是如何通过系统调用把用户态变成内核态的
    中断汇编指令int 80就是陷入内核,简单理解把状态由用户态改成内核态。调用结束时再切回来

2.1 捕捉过程

通过系统调用,陷入内核,OS返回用户态之前,会在进程的上下文中搜索可以传递的信号,OS能从CPU寄存器中拿到task_struct找到进程,查3张表,先查block表:block为0说明没被阻塞,继续看pending,pending为0继续下一个…

理论上是可以从内核态访问用户态(waitpid),但是实际上我们不能以内核态去访问用户态,OS不相信任何用户

在这里插入图片描述

简化图:
在这里插入图片描述

2.2 信号的捕捉方法

signal:

#include <signal.h>
typedef void (*sighandler_t)(int);//函数指针
sighandler_t signal(int signum, sighandler_t handler);

sigaction:
act:结构体对象,输入型参数;oldact:输出型参数,获取特定信号老的处理方法

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

struct sigaction {
               void     (*sa_handler)(int);//回调方法
               void     (*sa_sigaction)(int, siginfo_t *, void *);//处理实时信号,不关心
               sigset_t   sa_mask;//信号集
               int        sa_flags;//设置0就行
               void     (*sa_restorer)(void);
           };
RETURN VALUE:返回值
     sigaction() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.

2.3 信号捕捉规则

  1. 当我们进行正在递达某一个信号期间,同类型信号无法递达:当前信号正在被捕捉,系统会自动将当前信号加入到进程的信号屏蔽字(即BLOCK表),自动将2号信号屏蔽。
  2. 而当信号完成捕捉动作,系统又会自动解除对该信号的屏蔽
  3. 一般一个信号被解除屏蔽的时候,如果该信号已经被pending的话,会自动进行递达当前屏蔽信号,没有就不做任何动作
  4. 进程处理信号的原则是串行的处理同类的信号,不允许递归式处理
  5. 信号的自定义捕捉行为在执行之前就会把pending对应的信号比特位由1置0,然后再去执行行为,避免重复抵达问题

在这里插入图片描述

2.4 多信号屏蔽问题

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;

void Count(int cnt)
{
    while(cnt)
    {
        printf("cnt:%d\r",cnt);
        fflush(stdout);
        cnt--;
        sleep(1);
    }
    cout<<endl;
}

void handler(int signo)
{
    cout<<"get a signo"<<signo<<"正在处理信号"<<endl;
    Count(20);//倒计时打印
}

int main()
{
    struct sigaction act,oact;
    act.sa_handler=handler;
    act.sa_flags=0;
    sigemptyset(&act.sa_mask);
    //屏蔽多个信号可以把信号添加到sa_mask
    sigaddset(&act.sa_mask,3);
    

    sigaction(SIGINT,&act,&oact);

    while (true)
    {
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

三、信号集

3.1 概念

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态

3.2 信号集(sigset_t)操作函数

使用者只能调用以下函数来操作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);

sigprocmask :读取或更改进程的信号屏蔽字(阻塞信号集)Block表
如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在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参数更改信号屏蔽字

sigpending :读取pending信号集

#include <signal.h>
int sigpending(sigset_t  *set)
调用成功则返回0,出错则返回-1

关于这些函数的具体使用可参考我的码云

四、可重入函数

在信号层面解释:如果在main中和在handler中,该函数被重复调用,此时出现冲突问题,则该函数(比如list.insert)称为不可重入函数;相反如无冲突,则是可重入函数。

例如:main函数调用insert,向链表head插入Node1,insert只做了第一步,然后就被中断(或者因为信号原因执行信号捕捉),此时进程挂起,然后回到用户态之前检查有信号待处理,于是执行sighandler方法,sighandler也调用了insert函数,把Node2头插到链表里,Node2的next结点指向下一个结点位置,下一步就是head指向Node2,完成Node2的头插,信号捕捉完之后就成功把Node2插入,接下来回到main执行流,对Node1完成插入的第二步动作,此时把head指向Node1,最后只有Node1真正插入到链表之中。
在这里插入图片描述

而我们目前大部分情况下用的接口,全部都是不可重入的,重入不重入是特性。

识别不可重入函数
调用了malloc或free,因为malloc也是用全局链表来管理堆的。

调用了标准I/O库 函数。标准I/O库的汗多实现都以不可重入的方式使用全局数据结构。

五、volatile关键字

volatile保持内存可见性

#include <stdio.h>
#include <signal.h>
int quit = 0;
void handler(int signo)
{
    printf("%d号信号,正在被捕捉\n",signo);
    printf("quit:%d",quit);
    quit = 1;
    printf("->%d\n",quit);
}
int main()
{
    signal(2,handler);
    while(!quit);
    printf("注意,我是正常退出的\n");
    return 0;
}

以上代码正常编译是以下情况
在这里插入图片描述
但是增加了-O3优化后变成以下情况

mysignal:mysignal.c
	gcc -o $@ $^  -O3 

在这里插入图片描述
具体原因:
寄存器的存在遮盖了物理内存当中quit变量存在的事实

在这里插入图片描述
解决办法:int quit = 0;增加关键字 volatile-->volatile int quit=0

六、SIGCHLD

父进程可以用wait和waitpid函数清理僵尸进程【子进程先于父进程退出后,子进程的PCB需要其父进程释放,但是父进程并没有释放子进程的PCB,这样的子进程就称为僵尸进程】,父进程可以阻塞等待子进程结束,也可以非阻 塞地查询是否有子进程结束等待清理(也就是轮询的方式),这两种方式都是局限性。
子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略。

要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGNsignal(SIGCHLD, SIG_IGN);,这样fork出来的子进程在终止时会自动清理掉,不 会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略 通常是没有区别的,但这是一个特例。

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

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

相关文章

【视频教程解读】Window上安装和使用autogluon V0.7

1.使用conda安装的python环境 教程使用的是极简版miniconda,由于我们的电脑中安装了anaconda&#xff0c;所以不需要进行进一步安装。python版本为3.9&#xff0c;博客里面有anaconda和python版本的对应关系。注意查看版本autogluon V0.4需要3.8或者3.9和3.10&#xff0c;pip版…

2023年第二十届五一数学建模B题:快递需求分析问题-思路详解

一、题目简析 今年的B题是一道较为综合的题目&#xff0c;包括了数据分析、综合评价、时间序列预测、最优化问题以及概率估计问题。考察范围广&#xff0c;但是整体看来题目背景简单&#xff0c;切入点多&#xff0c;难度适中。 二、逐问思路 1.问题1&#xff1a;附件1为该快…

私有GitLab仓库 - 本地搭建GitLab私有代码仓库并随时远程访问「内网穿透」

文章目录 前言1. 下载Gitlab2. 安装Gitlab3. 启动Gitlab4. 安装cpolar内网穿透5. 创建隧道配置访问地址6. 固定GitLab访问地址6.1 保留二级子域名6.2 配置二级子域名 7. 测试访问二级子域名 转载自远控源码文章&#xff1a;Linux搭建GitLab私有仓库&#xff0c;并内网穿透实现公…

迷你主机安装openwrt软路由系统(附启动盘制作教程+ISO、IMG镜像文件)

之前在迷你主机上刷了一个openwrt的软路由&#xff0c;安装过程分享给大家&#xff0c;镜像文件在文章末尾~ 一般需要做软路由系统的机器&#xff0c;是需要至少两个网口的&#xff0c;一个做wan口&#xff0c;一个做lan口 由于其他因素&#xff0c;不能直接将openwrt直接安装…

ChatGPT是什么?ChatGPT里的G、P、T分别指什么

文章目录 ChatGPT是什么GTP中的 生成式 是什么意思GTP中的 预训练 是什么意思GTP中的 变换模型 是什么意思 什么是Transformer什么是注意力机制 监督学Xi、无监督学Xi、强化学Xi ChatGPT是什么 GPT: Generative Pre-trained Transformer 生成式预训练变换模型 ChatGPT是由Ope…

学习RHCSA的day.02

目录 2.3常用简单命令 2.4使用Bash执行命令 2.5 命令帮助 2.3常用简单命令 常用系统工作命令 1、echo命令 echo命令用于在终端设备上输出字符串或变量提取后的值&#xff0c;语法格式为&#xff1a;“echo [字符串] [$变量]”。 这是在Linux系统中最常用的几个命令之一&am…

蒙蒂霍尔悖论

贝叶斯与频率主义对蒙蒂霍尔问题的解 在定义概率时&#xff0c;通常有两种思想流派&#xff1a;贝叶斯主义和频率主义。前者将概率视为我们对事件发生的信念程度&#xff0c;而后者则将其视为事件发生的相对频率。这篇文章介绍了使用贝叶斯和频率主义方法来解决著名的蒙蒂霍尔问…

C++每日一练:小艺照镜子(详解分治法)

文章目录 前言一、题目二、解题1.分析 总结 前言 大过节的&#xff0c;不想去看人后脑勺&#xff0c;就做点题来玩。挑了小艺照镜子&#xff0c;百分通过~ 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 题目名称&#xff1a; 小艺照镜子 …

【论文解读】(如何微调BERT?) How to Fine-Tune BERT for Text Classification?

文章目录 论文信息1. 论文内容2. 论文结论2.1 微调流程2.2 微调策略(Fine-Tuning Strategies)2.3 Further Pretrain 3. 论文实验介绍3.1 实验数据集介绍3.2 实验超参数3.3 Fine-Tuning策略探索3.3.1 处理长文本3.3.2 不同层的特征探索3.3.3 学习率探索&#xff08;灾难性遗忘探…

Baumer工业相机堡盟相机如何使用ROI感兴趣区域功能( PARTIAL SCAN ROI功能的优点和行业应用)(C#)

项目场景 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能&#xff0c;可以实时传输高分辨率图像。此外&#xff0c;该相机还具…

利用 ChatGPT4 回复的 markdown 文本生成 ppt

本篇博文不涉及账号以及基础网络知识&#xff0c;大伙可以自动搜索。 比如我最近要分享一篇关于 TCP 的分享&#xff0c;那么我可以设置如下 Prompt 我最近要做一篇关于 tcp 入门的 ppt 分享&#xff0c;帮我列出大纲以及需要注意的事项&#xff1f; 接下来就是 ChatGPT4 给…

RocketMQ的学习历程(3)----RocketMQ部署(docker版)

RocketMQ部署&#xff08;docker版&#xff09; 1. 部署开始前的准备 一台linux机器。(我这里使用的是阿里云的一个centos7的服务器)docker环境以及相关的简单知识。一些计算机网络的简单知识。&#xff08;可以帮你透彻了解为什么这么部署&#xff09; docker部署十分简单快捷…

JAVA85-135

JAVA85-135 字符集详解解码与编码方法 字符流FileWriter 拷贝文件夹字节缓冲流拷贝文件&#xff08;一次读写一个字节&#xff09;字节缓冲流拷贝文件&#xff08;一次读写一个字节数组&#xff09; 字符缓冲流控制软件运行次数 序列化流反序列化流/对象操作输入流打印流字节打…

macOS Monterey 12.6.5 (21G531) OC 0.9.1 / Cl 5151 / PE 三分区原版黑苹果镜像

苹果近期发布了 macOS Big Sur 11.7.6 和 macOS Monterey 12.6.5 更新&#xff0c;本次更新重点修复了标记为 CVE-2023-28206 的漏洞&#xff0c;在 macOS 13.3.1 更新中已修复&#xff0c;推荐大家安装升级。 镜像下载&#xff1a; macOS Monterey 12.6.5 (21G531) 三分区原版…

【面试】嵌入式C语言题目整理

【面试】嵌入式C语言题目整理 描述内存四区。 内存四区分为&#xff1a;代码区、静态区、堆区、栈区 代码区就是用来存放代码的。 静态区用来存放全局变量、静态变量、常量&#xff08;字符串常量、const修饰的全局变量&#xff09;。 堆区中的内存是由程序员自己申请和释放的&…

《高性能MySQL》读书笔记

《高性能MySQL》 第一章 MySQL架构与历史第二章 MySQL基准测试第三章 服务器性能剖析第四章 Schema与数据类型优化第五章 创建高性能的索引第六章 查询性能优化第七章 MySQL高级特性第八章 优化服务器设置第九章 操作系统与硬件优化第十章 复制第十一章 可扩展的MySQL第十二章 …

sed进阶之多行命令

shell脚本编程系列 前面使用sed编辑器的基础命令时&#xff0c;所有的命令都是针对单行数据执行操作的。在sed编辑器读取数据流时&#xff0c;它会根据换行符的位置将数据分成行。sed编辑器会根据定义好的脚本命令&#xff0c;一次处理一行数据&#xff0c;然后移到下一行重复这…

numpy稀疏矩阵拼接

今天我发现numpy中的array拼接时dense矩阵和sparse矩阵拼接使用的形式是不一样的&#xff0c;测试如下 普通矩阵拼接 import numpy as npaa np.random.randn(4,3) bb np.ones((4,3)) ccnp.c_[aa,bb] cc.shape结果如下 sparse矩阵拼接 from scipy.sparse import *row [1,1,…

DC-7通关详解

信息收集 漏洞发现 web提示我们说弱口令可能不会奏效 那么我们就先不考虑弱口令 searchsploit搜payload打打看,无果 看别人的wp知道了是通过web左下角的这个玩意去github搜 在这个仓库用户唯一的仓库中看config.php 发现账号密码 尝试后台和ssh登录 ssh登录成功 提权 当前…

一款免安装、多平台兼容的 拾色器(Color Picker)

文章目录 场景需求场景需求 Chrome Google DevTools 中的 拾色器 用法其他浏览器 场景需求 场景 我是一个前端开发人员&#xff0c;我写好的界面给老板过目。老板说有个地方颜色需要调整&#xff0c;然后发我一张图片指了指说就用这个位置这样的红色&#xff0c;我看挺合适。…