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

news2024/12/23 1:55:38

目录标题

  • 信号的一些概念
  • 信号的保存
    • 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.coloradmin.cn/o/1060506.html

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

相关文章

DevEco Studio设置Nodejs提示路径只能包含英文、数字、下划线等

安装DevEco Studio 3.1.1 Release 设置Nodejs路径使用nodejs默认安装路径 &#xff08;C:\Program Files\nodejs&#xff09; 提示只能包含英文、数字、下划线等 , 不想在安装nodejs请往下看 nodejs默认路径报错 修改配置文件 1、退出DevEco Studio 2、打开配置文件 cmd控制台…

Linux高性能服务器编程 学习笔记 第十章 信号

信号是由用户、系统、进程发送给目标进程的信息&#xff0c;以通知目标进程某个状态的改变或系统异常。Linux信号可由以下条件产生&#xff1a; 1.对于前台进程&#xff0c;用户可通过输入特殊终端字符来给它发送信号&#xff0c;如输入CtrlC通常会给进程发送一个中断信号。 2…

最短路径专题5 最短路径

题目&#xff1a; 样例&#xff1a; 输入 4 5 0 2 0 1 2 0 2 5 0 3 1 1 2 2 3 2 2 输出 3 0->3->2 思路&#xff1a; 根据题目意思&#xff0c;求最短路&#xff0c;这个根据平时的Dijkstra&#xff08;堆优化&#xff09;即可&#xff0c;关键在于求路径的方法&#x…

阿里云新账户什么意思?老用户、产品首购详细说明

阿里云新账户、老账号、产品首购和同人账号什么意思&#xff1f;阿里云账号分为云新账户、老账户、产品首购、同人账号和同一用户&#xff0c;阿里云官方推出的活动很多是限制账号类型的&#xff0c;常见的如阿里云新用户&#xff0c;什么是阿里云新用户&#xff1f;是指从未在…

mysql面试题11:讲一讲MySQL主从复制模式

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:讲一讲MySQL主从复制模式? MySQL主从复制的配置步骤如下: 在主服务器上配置: 打开主服务器的配置文件my.cnf,启用二进制日志(binary log)功…

【Linux】[gdb]Linux环境下如何调试代码

一、code.c文件 我们首先创建一个code.c文件&#xff0c;写一段简单代码&#xff0c;用于测试。 二、makefile文件 然后&#xff0c;我们可以编写makefile文件&#xff0c;使得code.c文件能够进行编译。&#xff08;当然也可以不写makefile文件&#xff0c;直接对code.c进行编…

mysql面试题14:讲一讲MySQL中什么是全同步复制?底层实现?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:讲一讲mysql中什么是全同步复制?底层实现? MySQL中的全同步复制(Synchronous Replication)是一种复制模式,主服务器在写操作完成后,必须等待…

PG 多表连接查询

写法&#xff1a; 使用 select 表名.键名 from 表1 join表2 on 相同的主键 构造出来一张新表 多表要用表名.键名 才能知道是哪一张表 传统写法也行 类型&#xff1a; 内 而外的要这样写

[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.…

虚拟机VMware的使用流程以及出现的问题附解决方法

虚拟机VMware的使用流程以及出现的问题附解决方法 下载安装 略。。。 创建虚拟机 虚拟机的设置如下&#xff1a;注意网络适配器为NAT 如果出现ip addr 命令&#xff1a;不显示IP地址的话&#xff1a; 解决方式如下&#xff1a; 首先设置网卡&#xff1a;先查看一下onboot是…

python二次开发CATIA:测量点的坐标

首先新建一个Part文件&#xff0c;插入一个几何图形集&#xff0c;在该几何图形集中插入一个点&#xff0c;坐标为&#xff08;100&#xff0c;0&#xff0c;0&#xff09;​&#xff0c;如下图所示&#xff1a; 下面通过python来测量该点的坐标​&#xff1a; import win32co…

国庆10.4

QT实现TCP服务器客户端 服务器 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器头文件 #include <QTcpSocket> //客户端头文件 #include <QList> //链表容器 #include <QMe…

蓝桥杯每日一题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…

C++ YAML使用

C++工程如何使用YAML-cpp 一、前期准备工作 1、已安装minGW、cmake、make等本地工具。 2、下载YAML-cpp第三方开源代码(一定要下载最新的release版本,不然坑很多)。 3、生成YAML-cpp静态库 (1)在yaml-cpp-master下建立build文件夹; (2)在该文件夹下生成MakaFile文…

wzsc_文件上传(条件竞争)

打开题目链接&#xff0c;很常见的文件上传框 经过尝试&#xff0c;发现上传东西后会调用upload.php&#xff0c;猜测文件被传到upload目录下 随便传了几个类型的文件&#xff0c;访问upload目录 发现.php文件以及.htaccess、.user.ini这种配置文件都没有传上去 但是通过抓包…

软件工程与计算总结(三)示例项目描述

本节介绍一个标准的项目描述&#xff0c;大家可以作为蓝本学习~ 目录 一.背景 二.目标 三.系统用户 四.用户访谈要点 1.收银员 2.客户经理 3.总经理 4.系统管理员 五.项目实践过程 一.背景 A是一家刚刚发展起来的小型连锁商店&#xff0c;其前身是一家独立的小百货门面…

lv7 嵌入式开发-网络编程开发 07 TCP服务器实现

目录 1 函数介绍 1.1 socket函数 与 通信域 1.2 bind函数 与 通信结构体 1.3 listen函数 与 accept函数 2 TCP服务端代码实现 3 TCP客户端代码实现 4 代码优化 5 练习 1 函数介绍 其中read、write、close在IO中已经介绍过&#xff0c;只需了解socket、bind、listen、acc…

Web版Photoshop来了,用到了哪些前端技术?

经过 Adobe 工程师多年来的努力&#xff0c;并与 Chrome 等浏览器供应商密切合作&#xff0c;通过 WebAssembly Emscripten、Web Components Lit、Service Workers Workbox 和新的 Web API 的支持&#xff0c;终于在近期推出了 Web 版 Photoshop&#xff08;photoshop.adobe…

JUC第十四讲:JUC锁: ReentrantReadWriteLock详解

JUC第十四讲&#xff1a;JUC锁: ReentrantReadWriteLock详解 本文是JUC第十四讲&#xff1a;JUC锁 - ReentrantReadWriteLock详解。ReentrantReadWriteLock表示可重入读写锁&#xff0c;ReentrantReadWriteLock中包含了两种锁&#xff0c;读锁ReadLock和写锁WriteLock&#xff…

动态规划-状态机(188. 买卖股票的最佳时机 IV)

状态分类&#xff1a; f[i,j,0]考虑前i只股票&#xff0c;进行了j笔交易&#xff0c;目前未持有股票 所能获得最大利润 f[i,j,1]考虑前i只股票&#xff0c;进行了j笔交易&#xff0c;目前持有股票 所能获得最大利润 状态转移&#xff1a; f[i][j][0] Math.max(f[i-1][j][0],f[…