linux入门---信号的保存和捕捉

目录标题

  • 信号的一些概念
  • 信号的保存
    • pending表
    • block表
    • handler表
  • 信号的捕捉
    • 内核态和用户态
    • 信号的捕捉

信号的一些概念

1.进程会收到各种各样的信号,那么程序对该信号进行实际处理的动作叫做信号的递达。
2.我们之前说过当进程收到信号的时候可能并不会立即处理这个信号,而是先将信号进行保存,那么我们把信号从产生到抵达之间的状态称为信号未决。
3.进程可以阻塞某个信号,这样即使发送信号给对应的进程进程也不会做出任何的处理。
4.被阻塞的信号会一直保持在未决的状态,只有当进程解除了对此信号的阻塞时才会执行该信号的动作。
5.阻塞和忽略是两个不同的东西,一个信号要是被阻塞说明即使收到了该信号也不会执行该信号的动作,而忽略是收到该信号之后根据该信号执行的一个动作,只不过该动作是忽略也就是什么都不做而已。

信号的保存

之前的学习中我们知道操作系统是要给每个进程保存收到的信号的,而保存的位置就是task_struct中的一个位图,这是我们当时说的保存方法,但是信号存在三种状态比如说是否收到了信号,是否阻塞了信号,以及信号与之对应的动作以及动作是否被自定义修改了,所以内核使用一张图来保存信号肯定是不够用的,所以在实际的应用中使用了三张表一起来保存了信号,这三个表分别为:pending表,block表和handler表,那么接下来我们来一一介绍这三个表的功能。

pending表

pinding表本质上就是位图,我们之前说进程在运行的任何时候都会收到信号,这个信号并不会被立即处理,所以进程得保存这个信号,保存信号的方式是位图,那么这个位图就是pending表,位图的比特位位置表示哪个信号,比特位的值表示是否收到了该信号,如果收到了信号就将对应位置的值修改为1,如果没有收到信号对应位置的值就是0.

在这里插入图片描述

block表

block表也是一个位图,位图的位置表示信号编号,位图的值表示是否阻塞了对应的信号,被阻塞的信号不会被递达,只有当阻塞被解除了信号才会被递达,即使没有收到对应的信号我们也是可以阻塞一些信号的,这里的逻辑可以用下面的伪代码来表示:

if(1<<(signo)&pcb->block))
{//信号是被阻塞的,不递达
}
else
{if((1<<(signo-1))&pcb->pending){//递达该信号}
}

那这里就可以这么来理解,操作系统会扫描PCB中的位图来判断是否有信号需要被处理,如果信号对应在block上的值为1就直接跳过,如果对应在block上的值为0就接续查看对应在panding位图上的值,如果值为1的活就执行的对应的方法,那么这就是block表的功能。
在这里插入图片描述

handler表

handler表是一个函数指针数组,每个元素都是一个函数指针,数组的位置(下标)表示信号的编号,数组下标对应的内容就表示对应信号的处理方法,signal函数可以修改信号对应的方法,那么这个本质上就是修改handler表对应元素的指向,当信号被递达时就可以根据信号的值来找到handler表中处理信号的方法并执行该方法,那么这里的图片就是下面这样:
在这里插入图片描述

所以看到这里我们可以得出三个结论:如果一个信号没有产生的话,并不妨碍他可以先被阻塞,因为我们只需修改block表中的值跟记录是否收到信号的pending表没有关系,如果阻塞的过程中收到了信号,那么我们就修改pending位图上对应的值并不会接着去找handler表中的方法 2.进程为什么能够识别信号,是因为内核中存在三个表这三个表能让进程认识信号并处理对应的信号。 3.如果SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。

信号的捕捉

信号产生的时候不会立即被处理,而是在合适的时候被处理,那这个合适的时间是什么时候呢?并且我们上面说到操作系统会在某些时刻检查block表和pending表,那这个时刻又是指的什么时候呢?那么要想解决这些问题我们就得谈谈什么是内核太什么是用户态。

内核态和用户态

我们自己写的代码经过编译和运行之后都是运行在用户态上的,但是在我们在编写代码的时候难免会访问到操作系统的资源(getpid,waitpid)和硬件资源(printf,read,write),当我们访问操作系统的资源或者硬件资源的时候,我们都得直接或者间接的访问系统提供的借口,通过这些接口来访问操作系统的资源,我们把这些接口称为系统调用
在这里插入图片描述
调用系统调用的时候,普通用户不能以自己的身份来调用系统调用,必须将自己的身份变为内核态,
这就好比当我们是一个公司的基层时副总裁的办公室我们几乎不能直接进出,但是当我们的身份变成了公司的CEO时,副总裁的办公室我们就可以随意的进出,所以当我们的身份变成了内核态时我们才能够有资格使用或者访问内核态提供的代码,实际执行系统调用的人是进程,但是身份是内核态,因为用户态调用内核态的时候要发生身份的转换,所以系统调用往往比较费时间一些,所以要尽量避免频繁的调用系统调用
在这里插入图片描述
但是这里存在一个问题,你说进程只是那一个进程,但是却存在两个身份,那该操作系统是如何来实现这一点的呢?那么这里我们就得提到寄存器这个东西

cpu中存在大量的寄存器,寄存器分为两种:1.可见寄存器,2.不可见寄存器,虽然寄存器分为两种但是只要和当前进程强相关的寄存器我们都将其称为上下文数据,比如说cpu中存在一个寄存器专门用来指向当前进程的pcb这样就可以快速的知道当前运行的进程是哪个,再比如说有个寄存器中存储的是当前页表的起始地址,这样就可以快速的找到当前进程的页表,

cpu中还存在一个名为CR3的寄存器,这个寄存器中的内容表征当前进程的运行级别,0表示内核态,3表示用户态,所以想要判断当前的进程是用户态还是内核态就只需要查看CR3里面的内容就行,这里存在一个问题:我是一个进程,进程是怎么跑到内核中执行对应的方法呢?之前我们提到的进程地址空间往往指的是用户空间,我们写的代码存放或者申请空间都是通过用户级地址空间+页表来进行映射,这个空间的大小为3GB
在这里插入图片描述

这里的页表是用户级页表该页表每个进程都有一份,但是地址空间的总大小是4GB,用户级空间只占了3GB那剩下的1GB空间用来干什么呢?我们把这个1GB的空间称为内核级空间,这一块空间也对应了一个页表,这个页表就叫内核级页表,这个页表的作用就是将操作系统级别的代码从内核虚拟地址空间映射到内存上面,
在这里插入图片描述

因为操作系统的代码只有一份,在机器启动的时候会将这份代码加载到内存上,并且每个进程都要使用操作系统代码,所以内核级页表只有一份,每个进程都通过这个页表来映射找到内存上的操作系统的代码,每一个进程都有自己的地址空间(用户空间独占),内核空间(被映射到了每个进程的地址空间的3-4G),所以进程要想访问操作系统的接口,其实只需要在自己的地址空间上进行跳转即可,由用户区跳转到内核区然后再由用户级页表跳转访问内存上的内核代码即可,每一个进程的进程地址空间都有3-4GB的内容,都会共享一个内核级页表,所以无论进程如何切换都不会修改进程地址空间中3-4GB的内容。那用户凭什么能够执行并访问内核的接口或者数据呢?原因是当操作系统发现你要访问内核的数据和代码时,会帮进程修改CR3寄存器的内容,这样就从用户态变成了内核态那么这时就有权利访问内核的数据,那操作系统为什么能知道我们要访问内核的数据和代码呢?答案是当我们要访问操作系统的接口时最开始还是用户态执行的,当以用户态执行系统调用接口时,系统调用接口做的最多的事情还是讲寄存器中的3号状态修改成为0号状态也就是将用户态改成内核态,然后才跳转区域访问内核的数据和代码,那么这就是用户态和内核态的概念

信号的捕捉

我们说操作系统会在合适的时候处理信号,那么这个合适的时候就是从内核态返回用户态的时候对信号进行处理,那么这就说明我们之前一定先进入了内核态,

在这里插入图片描述

当执行系统调用和进程切换(一个进程没有执行完,那一定是放到运行队列或者等待队列,那放进队列的时候一定是以操作系统的身份把我放了进去,所以得先变成内核态 就会变成内核态)
在这里插入图片描述

当操作系统进入内核态并且马上要返回普通状态的时候还会做一件事就是检查内核中的三张表,

在这里插入图片描述

如果block中的信号为0,pending中的信号也为0就会接着检查下一个信号,当block中的值为1就算pending中的值为1的话也不会执行该信号,当block的值为0并且penging的值为1的话就会执行该信号,然后就去handler中查找对应的方法,处理的方法有默认,忽略,自定义,默认的方法中有70%是终止进程,因为当前的身份是内核态所以可以很轻松的终止当前进程,忽略就是要处理该信号,但是处理的动作是什么都不做,所以直接将pending对应位置的信号设置为0就行,自定义的方法的实现在用户态,那这里就存在一个问题:我们能不能以内核态的身份来执行用户的代码呢?从技术的角度上我们可以以内核态的身份访问用户的代码,但是从设计的角度上来看是不能的,因为操作系统不相信任何人,handler方法中可能会有对系统造成危险的操作,而这些操作操作系统是无法识别是安全还是有害的,所以当我们以内核态的身份执行用户的代码的话,这部分代码可能会被恶意分子利用,然后进行一部分越权的非法动作,所以即使从技术上的角度能这么干,操作系统也不让你这么干,所以当要执行自定义代码的时候操作系统得通过特定的调用,将自己的身份从内核态转换称为用户态,然后再执行自定义代码,那么这个时候自定方法出现了问题就是用户自己的问题了,这个时候想干什么坏事情就会收到操作系统的管制了
在这里插入图片描述

执行完自定义方法之后也不能直接返回之前调用方法的地方,因为我们无法知道当初是从哪里进行跳转的,不能从用户态的一个地方跳转到另外一个地方,这里必须得有操作系统的支持,因为在从用户态跳转到内核态的时候操作系统保存了你的上下文信息,所以执行完自定义方法后得从用户态再跳转回内核,再通过特定的系统调用由内核态回到用户态上次的地方再继续向后执行
在这里插入图片描述
那么这就是信号捕捉的全部流程希望大家能够理解。

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

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

相关文章

[BJDCTF2020]Mark loves cat

先用dirsearch扫一下&#xff0c;访问一下没有什么 需要设置线程 dirsearch -u http://8996e81f-a75c-4180-b0ad-226d97ba61b2.node4.buuoj.cn:81/ --timeout2 -t 1 -x 400,403,404,500,503,429使用githack python2 GitHack.py http://8996e81f-a75c-4180-b0ad-226d97ba61b2.…

@Slf4j注解的使用说明

Slf4j的作用 该注解的作用主要是操作在idea中的控制台中打印的日志信息。 等价于代码&#xff1a; private final Logger logger LoggerFactory.getLogger(当前类名.class); 使用指定类初始化日志对象&#xff0c;在日志输出的时候&#xff0c;可以打印出日志信息所在类 当…

程序在线报刊第一期

文章目录 程序在线报刊第一期排序算法&#xff1a;优化数据处理效率的核心技术回顾区块链技术&#xff1a;去中心化引领数字经济新时代展望AI未来&#xff1a;智能化时代的无限可能 程序在线报刊第一期 排序算法&#xff1a;优化数据处理效率的核心技术 近年来&#xff0c;随…

软件设计师_计算机网络_学习笔记

文章目录 4.1 网路技术标准与协议4.1.1 协议4.1.2 DHCP4.1.3 DNS的两种查询方式 4.2 计算机网络的分类4.2.1 拓扑结构 4.3 网络规划与设计4.3.1 遵循的原则4.3.2 逻辑网络设计4.3.3 物理网络设计4.3.4 分层设计 4.4 IP地址与子网划分4.4.1 子网划分4.4.2 特殊IP 4.5 HTML4.6 无…

ReactNative学习笔记

文章目录 基础环境搭建创建项目安装vscode插件调试工具基础语法掌握ReactStyleSheetRN中的样式和CSS的不同通过style属性直接声明在style属性中调用StyleSheet声明的样式 Flexbox术语属性响应式布局 组件和API简介核心组件**最常用的一些核心组件**各核心组件的演示代码Alert和…

MyBatisPlus(八)范围查询

说明 范围查询&#xff0c;包括&#xff1a; 大于大于等于小于小于等于在范围内在范围外 大于&#xff1a;gt 代码 Testvoid gt() {LambdaQueryWrapper<User> wrapper new LambdaQueryWrapper<>();wrapper.gt(User::getAge, 20);List<User> users mapp…

QT实现TCP服务器客户端的实现

ser&#xff1a; widget.cpp&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器server new QTcpServer(this);// 此时&#xf…

逆强化学习

1.逆强化学习的理论框架 1.teacher的行为被定义成best 2.学习的网络有两个&#xff0c;actor和reward 3.每次迭代中通过比较actor与teacher的行为来更新reward function&#xff0c;基于新的reward function来更新actor使得actor获得的reward最大。 loss的设计相当于一个排序问…

CocosCreator3.8研究笔记(二十五)CocosCreator 动画系统-2d骨骼动画spine

大家都知道&#xff0c;在游戏中 一般用帧动画或者骨骼动画&#xff0c;实现 人物的行走、奔跑、攻击等动作。 帧动画&#xff0c;在上一篇已经做了介绍&#xff0c;感兴趣的朋友可以前往阅读&#xff1a; CocosCreator3.8研究笔记&#xff08;二十四&#xff09;CocosCreator …

C++_pen_重载(1)

普通运算符重载 C准许以运算符命名函数 string love "i";love " love";//(love, " love"); love " you";//(love, " you");cout<< "i love you";// <<(cout, "i love you");运算符分类 …

RabbitMQ安装与简单使用

安装 下载资源 可以访问官网查看下载信息rabbitmq官网 选择合适的版本&#xff0c;注意&#xff1a;rabbitmq需要下载一个Erlang才能使用 我自己是在一下两个连接中下载的 rabbitmq 3.8.8 erlang 21.3.8.15 需要下载其他版本的同学注意erlang版本是否匹配&#xff0c;可以访…

小谈设计模式(13)—外观模式

小谈设计模式&#xff08;13&#xff09;—外观模式 专栏介绍专栏地址专栏介绍 外观模式主要目的角色分析外观&#xff08;Facade&#xff09;角色子系统&#xff08;Subsystem&#xff09;角色客户端&#xff08;Client&#xff09;角色 工作原理核心思想总结简化接口解耦客户…

【多模态融合】TransFusion学习笔记(1)

工作上主要还是以纯lidar的算法开发,部署以及系统架构设计为主。对于多模态融合(这里主要是只指Lidar和Camer的融合)这方面研究甚少。最近借助和朋友们讨论论文的契机接触了一下这方面的知识&#xff0c;起步是晚了一点&#xff0c;但好歹是开了个头。下面就借助TransFusion论文…

GEO生信数据挖掘(五)提取临床信息构建分组,分组数据可视化(绘制层次聚类图,绘制PCA图)

检索到目标数据集后&#xff0c;开始数据挖掘&#xff0c;本文以阿尔兹海默症数据集GSE1297为例 上节做了很多的基因数据清洗&#xff08;离群值处理、低表达基因、归一化、log2处理&#xff09;操作&#xff0c;本节介绍构建临床分组信息。 我们已经学习了提取表达矩阵的临床…

蓝桥杯每日一题2023.10.4

双向排序 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 六十分解法如下&#xff1a;按照题意简单排序 #include<bits/stdc.h> using namespace std; const int N 2e5 10; int n, m, p, q, a[N]; bool cmp(int x, int y) {return x > y; } int main() {cin >&g…

postgresql-备份与恢复

postgresql-备份与恢复 基本概念备份类型物理备份与逻辑备份在线备份与离线备份全量备份与增量备份 备份恢复工具备份与恢复逻辑备份与还原备份单个数据库psqlpg_dumppg_store 备份整个集群 基本概念 服务器系统错误、硬件故障或者人为失误都可能导致数据的丢失或损坏。因此&am…

【Java 进阶篇】JDBC 数据库连接池详解

数据库连接池是数据库连接的管理和复用工具&#xff0c;它可以有效地降低数据库连接和断开连接的开销&#xff0c;提高了数据库访问的性能和效率。在 Java 中&#xff0c;JDBC 数据库连接池是一个常见的实现方式&#xff0c;本文将详细介绍 JDBC 数据库连接池的使用和原理。 1…

Qt扩展-QCustomPlot绘图基础概述

QCustomPlot绘图基础概述 一、概述二、改变外观1. Graph 类型2. Axis 坐标轴3. 网格 三、案例1. 简单布局两个图2. 绘图与多个轴和更先进的样式3. 绘制日期和时间数据 四、其他Graph&#xff1a;曲线&#xff0c;条形图&#xff0c;统计框图&#xff0c;… 一、概述 本教程使用…

调度程序以及调度算法的评价指标

1.调度器/调度程序 调度程序决定调度算法&#xff0c;时间片大小 ②&#xff0c;③由调度程序引起&#xff0c;调度程序决定: 1.调度时机 创建新进程进程退出运行进程阻塞I/O中断发生&#xff08;可能唤醒某些阻塞进程)非抢占式调度策略&#xff0c;只有运行进程阻塞或退出…

小谈设计模式(14)—建造者模式

小谈设计模式&#xff08;14&#xff09;—建造者模式 专栏介绍专栏地址专栏介绍 建造者模式角色分类产品&#xff08;Product&#xff09;抽象建造者&#xff08;Builder&#xff09;具体建造者&#xff08;Concrete Builder&#xff09;指挥者&#xff08;Director&#xff0…