当前位置: 首页 > news >正文

[Linux]内核如何对信号进行捕捉

要理解Linux中内核如何对信号进行捕捉,我们需要很多前置知识的理解:

  • 内核态和用户态的区别
  • CPU指令集权限
  • 内核态和用户态之间的切换

由于文章的侧重点不同,上面这些知识我会在这篇文章尽量详细提及,更详细内容还得请大家查看这篇文章:
内核态与用户态详解


一、内核态和用户态的区别

内核态和用户态本质上是对CPU状态的描述。内核态的权限最大,能够执行一切“特权代码”。而用户态则受限制,必须切换到内核态才能执行“特权代码”。

这就意味着内核态能够调度全部硬件资源,本质上就是对权限进行保护。由于硬件资源非常复杂,稍有不慎就会出现很大的问题,所以不是人人都有权限去调度。这样做就是为了安全性和稳定性。


二、CPU指令集权限

具体来说每一条汇编指令都对应一条CPU指令,非常多的CPU指令组成了CPU指令集。指令集则通过CPU实现软件对硬件的调度
同时CPU指令有分级权限。CPU指令能够操作硬件资源,硬件资源是非常复杂的,很容易出问题。所以操作系统直接屏蔽掉用户对CPU指令集的操作

CPU指令分级总共有四级,从高到低依次为:

  • ring0
  • ring1
  • ring2
  • ring3

Linux系统仅采用ring0和ring3这2个权限。用户态的程序工作在3,内核态的程序处于0:

  • ring0权限最高,可以使用所有CPU指令集,有对硬件的所有操作权限
  • ring3权限最低,仅能使用常规CPU指令集,不能使用操作硬件资源的CPU指令集。代码没有对硬件的直接控制权限,也不能直接访问地址的内存,程序是通过调用系统接口(System Call APIs)来达到访问硬件和内存

三、内核态和用户态之间的切换

1.如何理解进程切换?

  • 在当前进程的进程地址空间中的内核空间,找到操作系统的代码和数据。
  • 执行操作系统的代码,将当前进程的代码和数据剥离下来,并换上另一个进程的代码和数据。

注意: 当你访问用户空间时你必须处于用户态,当你访问内核空间时你必须处于内核态

从用户态切换为内核态通常有如下几种情况:

  • 需要进行系统调用时。
  • 当前进程的时间片到了,导致进程切换。
  • 产生异常、中断、陷阱等。

与之相对应,从内核态切换为用户态有如下几种情况:

  • 系统调用返回时。
  • 进程切换完毕。
  • 异常、中断、陷阱等处理完毕。

其中,由用户态切换为内核态我们称之为陷入内核。每当我们需要陷入内核的时,本质上是因为我们需要执行操作系统的代码,比如系统调用函数是由操作系统实现的,我们要进行系统调用就必须先由用户态切换为内核态

2.系统调用

用户态要主动切换到内核态要有统一的入口,它们就是内核提供的系统调用接口,下面是Linux整体架构图:
在这里插入图片描述
我们可以看出来通过系统调用将Linux整个体系分为内核态和用户态,而内核提供了一组通用的访问接口,它们使应用程序能访问到内核的资源,如CPU、内存、I/O,这些接口就叫系统调用


四、内核如何实现信号的捕捉?

当我们在执行主控制流程的时候,可能因为某些情况而陷入内核,当内核处理完毕准备返回用户态时,就需要进行信号pending的检查。(此时仍处于内核态,有权力查看当前进程的pending位图)

在查看pending位图时,如果发现有未决信号,并且该信号没有被阻塞,那么此时就需要该信号进行处理。

1.待处理信号是默认或忽略

如果待处理信号的处理动作是默认或者忽略,则执行该信号的处理动作后清除对应的pending标志位,如果没有新的信号要递达,就直接返回用户态,从主控制流程中上次被中断的地方继续向下执行即可。
在这里插入图片描述

2.待处理信号是自定义捕捉的

但如果待处理信号是自定义捕捉的,即该信号的处理动作是由用户提供的,那么处理该信号时就需要先返回用户态执行对应的自定义处理动作,执行完后再通过特殊的系统调用sigreturn再次陷入内核并清除对应的pending标志位,如果没有新的信号要递达,就直接返回用户态,继续执行主控制流程的代码。
在这里插入图片描述
注意: sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。

3.巧记

当待处理信号是自定义捕捉时的情况比较复杂,可以借助下图进行记忆:
在这里插入图片描述
其中,该图形与直线有4个交点就代表在这期间有4次状态切换,而箭头的方向就代表着此次状态切换的方向,图形中间的圆点就代表着检查pending表


当识别到信号的处理动作是自定义时,能直接在内核态执行用户空间的代码吗?不能!!!

  • 理论上来说是可以的,因为内核态是一种权限非常高的状态,但是绝对不能这样设计。
  • 如果允许在内核态直接执行用户空间的代码,那么用户就可以在代码中设计一些非法操作,比如清空数据库等,虽然在用户态时没有足够的权限做到清空数据库,但是如果是在内核态时执行了这种非法代码,那么数据库就真的被清空了,因为内核态是有足够权限清空数据库的。
  • 也就是说,不能让操作系统直接去执行用户的代码,因为操作系统无法保证用户的代码是合法代码,即操作系统不信任任何用户。

特别鸣谢:
Linux进程信号
内核态与用户态详解

http://www.lryc.cn/news/579929.html

相关文章:

  • 生成式AI版权迷局中的技术破茧之路
  • 7月4日星期五今日早报简报微语报早读
  • 面试150 赎金信
  • Winscope在aosp 13/14/15版本的使用总结
  • uni-app实现单选,多选也能搜索,勾选,选择,回显
  • uniapp 微信小程序水印
  • Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
  • Stable Diffusion Web 环境搭建
  • 九、平台相关
  • Rust实战:生成酷炫链接相关玩法
  • 创客匠人创始人IP方法论:打破行业内卷的价值竞争路径
  • 商业秘密保卫战:客户信息保护的证据攻防之道
  • 版本控制器SVN
  • 棱光 PDF 工具箱:水印管理 + 格式转换 + 批量处理提升效率
  • Android View的绘制原理详解
  • 怎么限制某些IP访问服务器?
  • 基于AR和SLAM技术的商场智能导视系统技术原理详解
  • 基于dropbear实现嵌入式系统ssh服务端与客户端完整交互
  • 适用于 vue2、vue3 的自定义指定:v-int(正整数)
  • HDMI延长器 vs 分配器 vs KVM切换器 vs 矩阵:技术区别与应用场景
  • Django+DRF 实战:从异常捕获到自定义错误信息
  • VS中将cuda项目编译为DLL并调用
  • Excel 如何处理更复杂的嵌套逻辑判断?
  • Java并发性能优化|读写锁与互斥锁解析
  • openEuler 24.03 全流程实战:用 Ansible 5 分钟部署分布式 MinIO 高可用集群
  • 分布式集合通信--学习笔记
  • Data的时区格式BUG
  • 4 位量化 + FP8 混合精度:ERNIE-4.5-0.3B-Paddle本地部署,重新定义端侧推理效率
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之高斯椭球的颜色表达
  • 替代MT6701,3D 霍尔磁性角度传感器芯片