Linux:信号的处理

news2024/10/6 20:32:50

文章目录

  • 信号处理

本篇总结的是关于信号的处理

信号处理

在之前有这样的观点:信号在合适的时候被处理好,当进程收到信号后,当前进程可能在做优先级更高的事,所以它来不及处理这个信号,那么就会把这个信号暂时保存起来,在后续需要进行处理这个信号的时候,就会对这个信号进行处理,那么现在的问题是,它是要在什么时候进行处理?这个合适的时候是值什么时候?

通俗来说,这个合适的时候指的是从内核态返回用户态的时候,这个过程中进行信号的检测和处理

对于信号的处理,用户可能会定义有对应的自定义方法,自定义方法的存储位置就在用户空间内,而对应的进程控制块,pending表,还有handler表等等内容,这些数据结构都是在操作系统中进行存储的,未来对于进程来说,上述内容都是进程中的一部分,而和这些内容相关的代码存储位置并不在用户空间中,所以在未来的代码执行中,可能会执行到和这些内容相关的时候,就会需要进入操作系统内部,之后操作系统内部把重要的事处理结束之后,返回的时候,就会从内核态切换为用户态,而在这个过程中就会对信号进行检测,去查看处理的结果是什么结果,这里想突出的一点是,信号的处理是一个宏观的过程,它本质上是从内核态返回到用户态,从而进行信号的检测和处理

用下图来简单表示这个过程

在这里插入图片描述
有了上面的初步结论,先引入第一个问题,关于用户态和内核态的问题

用户态和内核态

  • 用户态是一种受控的状态,能够访问的资源是有限的
  • 内核态是一种操作系统的工作状态,能够访问大部分系统资源

对于用户态来说,在进行一些操作的时候会有权限约束,这就表现出了一定的受控,同时从代码的角度来讲,在访问野指针空指针等等内容的时候会报错,其实这也是一种权限受限的问题,操作系统不允许用户访问某些区域,这就叫做用户是处于一种受控的状态

对于内核态来说,内核态是一种操作系统,可以理解为让操作系统处于一种操作系统级别的工作状态,能够访问系统中的绝大部分资源,由此又引出了系统调用的概念,在日常的使用库函数中,绝大部分其实内部都封装了系统调用,只要涉及到对于硬件的访问,就必然会有封装底层的系统调用,这是毋庸置疑的,只有操作系统才有资格对于硬件进行操作,所以在日常使用的大部分的操作系统,其实都是借助系统调用来进行使用的,而在系统调用这个层次其实就包含了一定的身份变化

在这里插入图片描述
还是沿用之前的这张图,从这张图中可以看出,每一个进程都有一个对应的地址空间,其中分成0-3GB这个空间以及3-4GB这个空间,这两个空间分别对应的就是用户空间和内核空间,在之前的内容中也有过这样的基础,大部分讲述的都是对于用户空间的使用,比如有动态库的加载,以及其他的变量定义和代码调用,大多都是在用户空间进行跳转,而又由于这是虚拟地址空间,所以对应的用户空间和页表等对于每一个进程来说都要私有一份,这是用户空间的定义

但是对于内核空间来说,就有些不一样了,例如操作系统是需要提前加载的,操作系统的代码和数据加载要更早一些,操作系统的内部也有各种的代码和跳转的,例如有进程管理内存管理等等,那么操作系统也有对应的数据,并且操作系统对于资源的管理基本都是用数据来体现的,所以操作系统中必定会有相当庞大的数据

所以问题就来了,CPU是如何对于操作系统中的这些代码和数据有认识的?其实每一个进程都有对应的用户空间,用户空间的内容是私有的,但是对于内核空间来说,却是公共的,内核级别的页表其实只需要一张就足够了,所有进程对于操作系统的代码也都是共享的,数据也是共享的,只需要一个内核级的页表,就能把虚拟地址的内容和物理地址建立一个映射,所以这个过程非常简单,而CPU就可以直接通过虚拟地址和内核页表进行映射,进而找到操作系统的代码和数据,而每一个进程的内核空间都是一样的,因为都是由操作系统来管理的,所以不管如何进行进程的切换,CPU访问操作系统的位置都是一样的,所以CPU可以随时任意的找到操作系统

那前面有这样的知识基础,操作系统的驱动,其实就是借助一些硬件,通过CPU来执行时钟中断,最后找到中断对应的处理方法,就有了一个调度的方法,这也就是相当于完成了一个调度,那么本质上来说操作系统就是一个死循环,这也就意味着当进行时钟中断的时候,CPU可以直接通过当前进程对应的地址空间,快速的找到操作系统进行代码的执行,那么也就意味着,系统可以在硬件层面上随时随地的找到操作系统,这就是上述要得出的一个结论

总结一下前面的结论:

  • 用户态只能访问0-3GB空间,而内核态可以让用户以操作系统的身份访问其余空间内的内容
  • 无论进程如何调度,CPU可以直接访问操作系统中的代码和数据
  • 所有代码的执行都可以在地址空间的方式进行函数的调用和返回
  • 操作系统内部提供了一些重要的方法集,就叫做系统调用,不管是如何进行代码跳转,本质上都是在进程自己的地址空间内进行的跳转,所以在软件层面上,地址空间内可以来回跳转,就可以快速的实现从正文到任何地方,从代码的任何位置到自己想要跳转的地方
  • 跳转的位置大概有共享区和内核区,其中对于内核区的跳转会涉及到权限约束的问题

内核态和用户态如何标识?

前面只说,内核态可以做什么,用户态不能做什么,但是这有什么用呢?操作系统是如何认识到这一点的,它是如何知道现在是处于什么状态呢?

结论是回归到CPU的硬件上,在CPU的硬件上伴随着有对应的工作级别,操作系统本身是一个软硬件结合起来设计的一款软件,那么在其本质上,是CPU内存中存在寄存器,其中主要包含有CR系列寄存器和CS系列寄存器

代码段寄存器(Code Segment Register):

CS:代码段寄存器,存储了当前代码段的段选择子。在x86架构中,CS寄存器是一个16位的寄存器,用于存储代码段的段选择子,其中包括段的基地址和访问权限等信息。CS寄存器的内容在不同特权级别下有不同的值,用于指示CPU当前执行的代码所处的特权级别

所以不管怎么说,用户态还是内核态,其实本质就是借助两个比特位进行身份的识别,而这样的识别机制在很多种情况下都被广泛的使用和借鉴

控制寄存器(Control Registers):

CR0:控制处理器的运行模式和特性。其中的一位(位0)用于控制保护模式(Protected Mode)和实模式(Real Mode)之间的切换。当该位被设置为1时,处理器处于保护模式,可以使用分段和分页机制,允许多任务处理和内存保护等特性;当该位被清除为0时,处理器处于实模式,不支持分段和分页,是最初的x86处理器模式
CR3:页目录基址寄存器(Page Directory Base Register),用于存储页目录的物理地址,用于虚拟地址到物理地址的转换
CR4:包含了一系列处理器特性的标志位,如页大小、物理地址扩展等

CR3寄存器是用来保存当前进程的页表信息的,比如现在CPU内部是如何知道当前进程的位置和页表的呢?其实,都是有对应的寄存器来保存的,比如说这个CR3寄存器中保存的就是用户级的页表,而这个当中存储的数据,其实本质上就是物理地址,这样做的目的就是为了快速找到页表的物理地址,进而通过这个机制找到页表中

操作系统是最早启动的软件,所以操作系统可以加载到物理内存的最低处,这也就使得可以很方便的快速找到操作系统中的代码和数据

但是在自己的地址空间中,代码用到的地址都是虚拟地址,而CPU真正读取到的地址是物理地址,所以CPU才会进行虚拟地址到物理地址的转换,也就是MMU这个硬件,这个硬件就是专门负责进行转换的,一旦转换完成之后,CPU中拿到的就是物理地址了,就可以进行访问对应的代码和数据了

CR2寄存器:当访问地址空间中的一个地址不存在的时候,操作系统就会触发缺页中断,而触发了缺页中断后就会重新开辟和申请物理内存,建立新的映射,当内存重新申请建立映射关系之后,当用户重新访问历史上曾经引发缺页中断的这个地址,那这个地址就被存储在这个寄存器中,再比如说当访问程序遇到野指针的时候,在进行debug遇到野指针的时候,会提示访问到野指针,提示当前地址是不可以被写入的,为什么会提示呢?因为这个地址一旦被访问,它所访问的目标地址就不存在,不存在就会有缺页中断,而此时会发现这个地址不能被归属于缺页中断的范畴中,而是用户的这次访问属于非法访问,所以就直接报错了,操作系统向目标进程发送信号,发送信号后进程要终止,但是终止的原因也是需要知道的,所以就让当前对应的系统去读取CR2寄存器,里面保存的就是引发异常的地址,这样就能看到因为访问哪个地址所以导致异常了

本质上有了上述的概念,对于系统调用,本质上就进入到3-4GB这个范围的地址空间内,但是操作系统是如何识别到可以让一个不明身份的人进入操作系统级别的地址空间?本质上就是有寄存器上的两个比特位的帮助,如果要将用户态切换到内核态,就把对应的比特位从3换成0即可,就完成了用户内核态的转变

用户内核态转变的细节问题

用户态和内核态的转变,必然不是随便进行转变的,在执行到系统调用的时候,就相当于是要在系统调用的起始地点来进行用户到内核态的转换

CPU有针脚这样的结构,它可以使得CPU可以接收各种各样的外部中断,那么收到了对应的外部中断后,就有对应的中断号,再结合对应的中断号去找中断向量表,即可执行对应的函数方法,这套过程是硬件帮助完成的,而最终执行的工作肯定是由软件完成,但整个这一套的接收信息处理等等,实际上是由硬件驱动软件来完成的,在CPU的工作模式中,除了一些能够接受外部的中断,还有一些来自内部的中断,这些来自内部的中断就叫做陷阱,实际上CPU内部有各种各样的例如int类型的指令,这些指令有对应的中断号,而其中的部分指令就负责了对身份的转变

所以回到最开始的问题,信号是在什么时候被处理的?其实就是从内核态返回到用户态的时候会进行检测,当准备进行返回的时候,又会有一次从内核态到用户态的转变,而检测到对应的信号后,首先要对pending位图进行标记,其次在合适的时候要对信号进行处理了,要看这个信号对应的block表是否被阻塞,如果没有阻塞就在这个时候执行对应的handler方法,对信号进行处理

系统调用和用户库函数

在之前的使用中,将open/fork这些都归为是系统调用,其实也并不是,在底层也是封装过才有的这些函数,真正的底层函数其实是sys_fork()等

综上,有了上面的这些理论基础,就可以画出下面的这个信号捕捉流程图:

在这里插入图片描述
信号的捕捉流程大致就是如上所示的流程,如图所示,当操作系统执行结束一个内核级的任务,处理结束之后在返回的过程中就要进行信号的检测,紧接着就是执行用户的自定义的捕捉方法,执行结束之后就可以返回到用户态了,以红线为界,上面是用户态,下面是内核态,在这之间一共会涉及到四次状态转换,每一次切换都是寄存器中数据的改变,进而引起权限改变,最终导致的是当前工作模式的状态变换

sigaction函数

在这里插入图片描述
上述是sigaction函数的相关信息,这个函数的作用主要是可以读取和修改与指定信号相关联的处理动作,它本质上也是一种和signal一样的函数,只是可以掌控的信息更多

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

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

相关文章

spring aop @annotation的用法

直接看原文: spring aop annotation的用法-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- annotation用在定义连接点时,对连接点进行限制。比如我们想对标注了…

双非本科准备秋招(18.2)—— 图解Monitor

对象头 普通对象: 数组对象: java中对象存储结构分为对象头(Header)、实例数据(Instance Date)和对齐填充(Padding)。 对象头存储着Mark Word和Klass Word,通过Klass Wo…

【MySQL】操作库 —— 库的操作 -- 详解

一、增删数据库 1、创建数据库 create database db_name; 本质就是在 /var/lib/mysql 创建一个目录。 说明: 大写的表示关键字。[ ] 是可选项。CHARACTER SET:指定数据库采用的字符集。COLLATE:指定数据库字符集的校验规则。 2、数据库删除…

背包问题(理论)

对于面试的话,掌握01背包、完全背包,就够用了,最多可以再来一个多重背包。 至于背包九讲其他背包,面试几乎不会问,都是竞赛级别的了,leetcode上连多重背包的题目都没有,所以题库也告诉我们&…

NodeJS安装(windows)

NodeJS安装(windows) 1、官网地址 NodeJS官网地址:https://nodejs.org/en 2、安装 3、验证NodeJS环境变量 cmd后,运行:node -v 4、配置npm的全局安装路径(需要管理员身份运行) npm conf…

【后端高频面试题--设计模式上篇】

🚀 作者 :“码上有前” 🚀 文章简介 :后端高频面试题 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 什么是设计模式?怎么理解设计模式? 设计模式是在软件设计中&#xff0c…

三.AV Foundation 视频播放 - 播放控制

引言 前面的博客我们已经实现了视频的播放功能,但是作为一个完整的视频播放器仅仅有播放功能是不够的,暂停,快进,播放进度条,显示播放时间,显示视频标题和字幕都是必不可少的功能。 本篇博客我们就对视频…

Spring Cloud Gateway 网关路由

一、路由断言 路由断言就是判断路由转发的规则 二、路由过滤器 1. 路由过滤器可以实现对网关请求的处理,可以使用 Gateway 提供的,也可以自定义过滤器 2. 路由过滤器 GatewayFilter(默认不生效,只有配置到路由后才会生效&#x…

【原创 附源码】Flutter安卓及iOS海外登录--Apple登录最详细流程

最近接触了几个海外登录的平台,踩了很多坑,也总结了很多东西,决定记录下来给路过的兄弟坐个参考,也留着以后留着回顾。更新时间为2024年2月12日,后续集成方式可能会有变动,所以目前的集成流程仅供参考&…

【GameFramework框架内置模块】1、全局配置(Config)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录: https://blog.csdn.net/q7…

AtCoder Beginner Contest 340(A-G)

A - Arithmetic Progression (atcoder.jp) 1.思路&#xff1a;循环输出即可 2.代码&#xff1a; #include <bits/stdc.h> #define rep(i,z,n) for(int i z;i < n; i) #define per(i,n,z) for(int i n;i > z; i--) #define PII pair<int,int> #define fi f…

【51单片机】串口(江科大)

8.1串口通信 1.串口介绍 2.硬件电路 3.电平标准 电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种: 电平标准是数据1和数据O的表达方式,是传输线缆中人为规定的电 压与数据的对应关系,串口常用的电平标准有如下…

Microsoft Excel 加载数据分析工具

Microsoft Excel 加载数据分析工具 1. 打开 Excel&#xff0c;文件 -> 选项2. 加载项 -> 转到…3. 分析工具库、分析工具库 - VBA4. 打开 Excel&#xff0c;数据 -> 数据分析References 1. 打开 Excel&#xff0c;文件 -> 选项 2. 加载项 -> 转到… ​​​ 3…

2013-2022年上市公司迪博内部控制指数、内部控制分项指数数据

2013-2022年上市公司迪博内部控制指数、分项指数数据 1、时间&#xff1a;2013-2022年 2、范围&#xff1a;上市公司 3、指标&#xff1a;证券代码、证券简称、辖区、证监会行业、申万行业、内部控制指数、战略层级指数、经营层级指数、报告可靠指数、合法合规指数、资产安全…

蓝桥杯-X图形

问题描述 给定一个字母矩阵。一个 X 图形由中心点和由中心点向四个 45度斜线方向引出的直线段组成&#xff0c;四条线段的长度相同&#xff0c;而且四条线段上的字母和中心点的字母相同。 一个 X 图形可以使用三个整数 r,c,L 来描述&#xff0c;其中 r,c 表示中心点位于第 r 行…

Matplotlib核心:掌握Figure与Axes

详细介绍Figure和Axes&#xff08;基于Matplotlib&#xff09; &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333; 一、Figure&#xff08;图形&#xff09;&#x1f333;&#x1f341;1. 创建Figure&#x1f341;&#x1f341;2. 添加Axes&am…

代码随想录刷题笔记 DAY 24 | 回溯算法理论基础 | 组合问题 No. 77

文章目录 Day 2401. 回溯算法理论基础1.1 什么是回溯法&#xff1f;1.2 为什么要使用回溯法&#xff1f;1.3 如何理解回溯法&#xff1f; 02. 组合问题&#xff08;No. 77&#xff09;2.1 题目2.2 笔记2.3 代码 Day 24 01. 回溯算法理论基础 1.1 什么是回溯法&#xff1f; &…

Kafka 入门笔记

课程地址 概述 定义 Kafka 是一个分布式的基于发布/订阅模式的消息队列&#xff08;MQ&#xff09; 发布/订阅&#xff1a;消息的发布者不会将消息直接发送给特定的订阅者&#xff0c;而是将发布的消息分为不同的类别&#xff0c;订阅者只接受感兴趣的消息 消息队列 消息队…

算法沉淀——位运算(leetcode真题剖析)

算法沉淀——位运算 常用位运算总结1.基础位运算2.确定一个数中第x位是0还是13.将一个数的第x位改成14.将一个数的第x位改成05.位图6.提取一个数最右边的17.删掉一个数最右边的18.异或运算9.基础例题 力扣题目讲解01.面试题 01.01. 判定字符是否唯一02.丢失的数字03.两整数之和…

Linux:搭建docker私有仓库(registry)

当我们内部需要存储镜像时候&#xff0c;官方提供了registry搭建好直接用&#xff0c;废话少说直接操作 1.下载安装docker 在 Linux 上安装 Docker Desktop |Docker 文档https://docs.docker.com/desktop/install/linux-install/安装 Docker 引擎 |Docker 文档https://docs.do…