Linux进程 ----- 信号处理

前言

从信号产生到信号保存,中间经历了很多,当操作系统准备对信号进行处理时,还需要判断时机是否 “合适”,在绝大多数情况下,只有在 “合适” 的时机才能处理信号,即调用信号的执行动作。

一、信号的处理时机

1.1 处理时面临的情况

普通情况

所谓的普通情况就是指 信号没有被阻塞,直接产生,记录未决信息后,再进行处理

在这种情况下,信号是不会被立即递达的,也就无法立即处理,需要等待合适的时机。

特殊情况

当信号被 阻塞 后,信号 产生 时,记录未决信息,此时信号被阻塞了,也不会进行处理

当阻塞解除后,信号会被立即递达,此时信号会被立即处理

普通情况 就有点难搞了,它需要等待 “合适” 的时机,才能被 递达,继而被 处理

1.2 “合适”的时机

信号的产生是 异步 的

        也就是说,信号可能随时产生,当信号产生时,进程可能在处理更重要的事,此时贸然处理信号显然不够明智

比如进程正在执行一个重要的 IO,突然一个终止信号发出,IO 立即终止,对进程、磁盘都不好

因此信号在 产生 后,需要等进程将 更重要 的事忙完后(合适的时机),才进行 处理

合适的时机:进程从 内核态 返回 用户态 时,会在操作系统的指导下,对信号进行检测及处理

至于处理动作,分为:默认动作、忽略、用户自定义

搞清楚 “合适” 的时机 后,接下来需要学习 用户态 和 内核态 相关知


二、用户态与内核态

对于 用户态、内核态 的理解及引出的 进程地址空间 和 信号处理过程 相关知识是本文的重难点

2.1 概念理论

先来看看什么是 用户态和内核态

  • 用户态:执行用户所写的代码时,就属于 用户态
  • 内核态:执行操作系统的代码时,就属于 内核态

自己写的代码被执行很好理解,操作系统的代码是什么?

  • 操作系统也是由大量代码构成的
  • 在对进程进行调度、执行系统调用、异常、中断、陷阱等,都需要借助操作系统之手
  • 此时执行的就是操作系统的代码

也就是说,用户态 与 内核态 是两种不同的状态,必然存在相互转换的情况

用户态 切换为 内核态

  • 当进程时间片到了之后,进行进程切换动作
  • 调用系统调用接口,比如 open、close、read、write 等
  • 产生异常、中断、陷阱等

内核态 切换为 用户态

  • 进程切换完毕后,运行相应的进程
  • 系统调用结束后
  • 异常、中断、陷阱等处理完毕

信号的处理时机就是 内核态 切换为 用户态,也就是 当把更重要的事做完后,进程才会在操作系统的指导下,对信号进行检测、处理

下面来结合 进程地址空间 深入理解 操作系统的代码 及 状态切换 的相关内容(拓展知识)

2.2 再现 进程地址空间

首先简单回顾下 进程地址空间 的相关知识:

  • 进程地址空间 是虚拟的,依靠 页表+MMU机制 与真实的地址空间建立映射关系
  • 每个进程都有自己的 进程地址空间,不同 进程地址空间 中地址可能冲突,但实际上地址是独立的
  • 进程地址空间 可以让进程以统一的视角看待自己的代码和数据

不难发现,在 进程地址空间 中,存在 1 GB 的 内核空间,每个进程都有,而这 1 GB 的空间中存储的就是 操作系统 相关 代码 和 数据,并且这块区域采用 内核级页表 与 真实地址空间 进行映射

为什么要区分 用户态 与 内核态 ?

  • 内核空间中存储的可是操作系统的代码和数据,权限非常高,绝不允许随便一个进程对其造成影响
  • 区域的合理划分也是为了更好的进行管理

所谓的 执行操作系统的代码及系统调用,就是在使用这 1 GB 的内核空间

进程间具有独立性,比如存在用户空间中的代码和数据是不同的,难道多个进程需要存储多份操作系统的代码和数据吗?

  • 当然不用,内核空间比较特殊,所有进程最终映射的都是同一块区域,也就是说,进程只是将 操作系统代码和数据 映射入自己的 进程地址空间 而已
  • 而 内核级页表 不同于 用户级页表,专注于对 操作系统代码和数据 进行映射,是很特殊的

当我们执行诸如 open 这类的 系统调用 时,会跑到 内核空间 中调用对应的函数

而 跑到内核空间 就是 用户态 切换为 内核态 了(用户空间切换至内核空间

这个 跑到 是如何实现的呢?

在 CPU 中,存在一个 CR3 寄存器,这个 寄存器 的作用就是用来表征当前处于 用户态 还是 内核态

  • 当寄存器中的值为 3 时:表示正在执行用户的代码,也就是处于 用户态
  • 当寄存器中的值为 0 时:表示正在执行操作系统的代码,也就是处于 内核态

通过一个 寄存器,表征当前所处的 状态,修改其中的 ,就可以表示不同的 状态,这是很聪明的做法

那么进程又是如何被调度的呢?

  1. 操作系统的本质
    操作系统也是软件啊,并且是一个死循环式等待指令的软件
    存在一个硬件:操作系统时钟硬件,每隔一段时间向操作系统发送时钟中断
  2. 进程被调度,就意味着它的时间片到了,操作系统会通过时钟中断,检测到是哪一个进程的时间片到了,然后通过系统调用函数 schedule() 保存进程的上下文数据,然后选择合适的进程去运行

2.3 信号处理过程

当在 内核态 完成某种任务后,需要切回 用户态,此时就可以对信号进行 检测 并 处理 了

情况1:信号被阻塞,信号产生/未产生

信号都被阻塞了,也就不需要处理信号,此时不用管,直接切回 用户态 就行了

情况2:当前信号的执行动作为 默认

大多数信号的默认执行动作都是 终止 进程,此时只需要把对应的进程干掉,然后切回 用户态 就行了

情况3:当前信号的执行动作为 忽略

当信号执行动作为 忽略 时,不做出任何动作,直接返回 用户态

情况4:当前信号的执行动作为 用户自定义

这种情况就比较麻烦了,用户自定义的动作位于 用户态 中,也就是说,需要先切回 用户态,把动作完成了,重新坠入 内核态,最后才能带着进程的上下文相关数据,返回 用户态

在 内核态 中,也可以直接执行 自定义动作,为什么还要切回 用户态 执行自定义动作?

  • 因为在 内核态 可以访问操作系统的代码和数据,自定义动作 可能干出危害操作系统的事
  • 在 用户态 中可以减少影响,并且可以做到溯源

为什么不在执行完 自定义动作 直接后返回进程?

  • 因为 自定义动作 和 待返回的进程 属于不同的堆栈,是无法返回的
  • 并且进程的上下文数据还在内核态中,所以需要先坠入内核态,才能正确返回用户态

注意: 用户自定义的动作,需要先切换至 用户态 中执行,执行结束后,还需要坠入 内核态

三、信号的捕捉

3.1 内核实现

如果信号的执行动作为 用户自定义动作,当信号 递达 时调用 用户自定义动作,这一动作称为 信号捕捉

用户自定义动作 是位于 用户空间 中的

        当 内核态 中任务完成,准备返回 用户态 时,检测到信号 递达,并且此时为 用户自定义动作,需要先切入 用户态 ,完成 用户自定义动作 的执行;因为 用户自定义动作 和 待返回的函数 属于不同的 堆栈 空间,它们之间也不存在 调用与被调用 的关系,是两个 独立的执行流,需要先坠入 内核态 (通过 sigreturn() 坠入),再返回 用户态(通过 sys_sigreturn() 返回)

3.2 sigaction

sigaction 也可以 用户自定义动作,比 signal 功能更丰富

#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;	//一些选项,一般设为 0void     (*sa_restorer)(void);	//实时信号相关,不用管
};

返回值:成功返回 0,失败返回 -1 并将错误码设置

参数1:待操作的信号

参数2:sigaction 结构体,具体成员如上所示

参数3:保存修改前进程的 sigaction 结构体信息

这个函数的主要看点是 sigaction 结构体

struct sigaction 
{void     (*sa_handler)(int);	//自定义动作void     (*sa_sigaction)(int, siginfo_t *, void *);	//实时信号相关,不用管sigset_t   sa_mask;	//待屏蔽的信号集int        sa_flags;	//一些选项,一般设为 0void     (*sa_restorer)(void);	//实时信号相关,不用管
};

其中部分字段不需要管,因为那些是与 实时信号 相关的,我们这里不讨论

sa_mask当信号在执行 用户自定义动作 时,可以将部分信号进行屏蔽,直到 用户自定义动作 执行完成

也就是说,我们可以提前设置一批 待阻塞 的 屏蔽信号集,当执行 signum 中的 用户自定义动作 时,这些 屏蔽信号集 中的 信号 将会被 屏蔽(避免干扰 用户自定义动作 的执行),直到 用户自定义动作 执行完成

四、信号部分小结

截至目前,信号 处理的所有过程已经全部学习完毕了

信号产生阶段:有四种产生方式,包括 键盘键入、系统调用、软件条件、硬件异常

信号保存阶段:内核中存在三张表,blcok 表、pending 表以及 handler 表,信号在产生之后,存储在 pending 表中

信号处理阶段:信号在 内核态 切换回 用户态 时,才会被处理

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

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

相关文章

Uva 101: 木块问题(The Blocks Problem)

看着算法书看到了这一题&#xff0c;想着不能只看不做&#xff0c;就想着做了一下 算法书上的描述太抽象了&#xff0c;就网上找了其他的描述 当然去看英文描述是最准确的&#xff0c;算法书上说是哪一个oj网来着&#xff1f;我给忘了 STL还是很好用的 代码如下&#xff1a; …

【C++进阶】STL容器--stack和queue深度剖析优先队列适配器原理

目录 前言 1. 容器的使用 1.1 stack 1.2 queue 2. 什么是适配器 3. stack&&queue底层实现 4. deque的简单介绍 4.1 deque的缺陷 5. priority_queue 思考 6. priority_queue的实现 前言 栈和队列在C语言中大家都有所了解&#xff0c;C语言的栈和队列都是我们手动去…

如何在本地部署密码管理软件bitwarden并结合cpolar实现远程同步

文章目录 1. 拉取Bitwarden镜像2. 运行Bitwarden镜像3. 本地访问4. 群晖安装Cpolar5. 配置公网地址6. 公网访问Bitwarden7. 固定公网地址8. 浏览器密码托管设置 Bitwarden是一个密码管理器应用程序&#xff0c;适用于在多个设备和浏览器之间同步密码。自建密码管理软件bitwarde…

WebStorm下将vue的代码缩进由2个空格改为4个空格

已经找过解决方案但设置后无效的&#xff0c;可直接看文章的最后一句。 最近刚接触vue&#xff0c;发现按tab缩进代码时缩进一直是2格而不是4格&#xff0c;检查了一下WebStorm的配置&#xff1a; File > Settings > Editor > Code Style > JavaScript的设置&…

【开源项目】数字孪生农业~经典开源项目数字孪生智慧农业大棚

飞渡科技数字孪生农业管理平台&#xff0c;是基于数字孪生、物联网IOT、远程感知等技术支撑的农业生产管理模式&#xff0c;构建的多时相、高精度农业信息获取系统与智能服务平台&#xff0c;支持农业资源环境监测与信息服务能力提升。 平台首页提供直观的农田概览&#xff0c…

[ai笔记12] chatGPT技术体系梳理+本质探寻

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第12篇分享&#xff01; 这周时间看了两本书&#xff0c;一本是大神斯蒂芬沃尔弗拉姆学的《这就是ChatGPT》,另外一本则是腾讯云生态解决方案高级架构师宋立恒所写的《AI制胜机器学习极简入门》&#xf…

python学习26

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

装配制造业的MES系统种的物料齐套技术

装配是制造企业涉及产品生产加工最为普遍的一种模式&#xff0c;包括汽车、电子、电器、电气等行业。经研究表明&#xff0c;装配在整个产品制造总成本中所占比例超过了50%&#xff0c;所占用的总生产时间比例在40%-60%&#xff0c;直接影响着产品质量和成本。装配制造非常强调…

大数据开发项目--音乐排行榜

环境&#xff1a;windows10&#xff0c;centos7.9&#xff0c;hadoop3.2、hbase2.5.3和zookeeper3.8完全分布式&#xff1b; 环境搭建具体操作请参考以下文章&#xff1a; CentOS7 Hadoop3.X完全分布式环境搭建 Hadoop3.x完全分布式环境搭建Zookeeper和Hbase 1. 集成MapReduce…

Prometheus(一):Prometheus简介及安装

目录 1 Prometheus 介绍1.1 Prometheus简介1.2 Prometheus的特点1.3 Prometheus架构 2 Prometheus安装 1 Prometheus 介绍 1.1 Prometheus简介 Prometheus 是一款基于时序数据库的开源监控告警系统&#xff0c;非常适合Kubernetes集群的监控。Prometheus的基本原理是通过HTTP…

哪些网页原型设计工具易于使用?

本文介绍了七种专业易用的原型工具&#xff0c;帮助您快速制作可验证的方案原型&#xff0c;减少产品、运营和其他同事的沟通时间&#xff0c;以及设计师绘制效果图的沟通时间。我相信你可以在阅读后找到最合适的网页原型设计工具。网页界面原型设计软件有很多选择。以下是一些…

解析ChatGPT Plus相比chatgpt3.5有哪些优势

「ChatGPT Plus」提供更出色的对话体验和更广泛的应用能力&#xff0c;学生可以用来写作、职场人也可以用来写计划书、策划书等等&#xff0c;并且问它一些问题比搜索引擎好用多了简直。但普通人使用起来有一点门槛&#xff0c;并且升级4.0也难住了许多爱好者。 ChatGPT主要功能…