linux异步信号handle浅析
Linux系统是一种支持多任务并发执行的操作系统,它可以同时运行多个进程,从而提高系统的利用率和效率。但是,如果这些进程之间需要进行数据交换和协作,就需要使用一些进程间通信(IPC)的方式,例如消息队列、共享内存、信号量等。其中,信号是一种比较简单而灵活的IPC方式,它可以让一个进程向另一个进程发送一个简短的消息,通知它发生了某种事件或异常。Linux系统中的信号有两种类型,分别是同步信号和异步信号。本文将浅析linux异步信号handle的方法,包括异步信号的含义、产生、发送、接收、处理和忽略等方面。
在初学linux编程的时候,一直觉得异步信号handle是个很神奇的东西,用户程序可以使用singal之类的系统调用为某某信号注册一个信号处理函数(handle函数)。
程序的二进制代码在内存中都有着确定的执行流程,为什么收到异步信号以后,程序会被“中断”,然后跳转到这个handle函数里面去运行呢?内核怎么有能力让程序做这样的跳转呢,总不可能临时修改程序的可执行代码吧?
后来学习了一些内核知识,才知道原来进程收到信号以后,并不是立即就被“中断”的,而是先在进程的控制结构(task_struct)中记录下收到了某某信号,然后等到进程即将从内核态返回用户态的时候,流程才被“中断”,handle函数才被调用。
用户进程什么时候会从内核态返回用户态呢?一般主要是三种情况:系统调用(用户进程主动进入内核)、中断(用户进程被动进入内核)、被调度执行(用户进程从等待执行变为正在执行)。
进程从收到信号到它从内核态返回用户态的过程,是需要一定时间的。但是这个时间一般会很短,至少时钟中断会以较大的频率(比如1毫秒一次)将用户进程带入内核(当然,只针对正在执行的进程)。
在进程即将从内核态返回用户态时,如果有信号需要处理,对应的handle函数将被调用(当然,可能没有注册handle,这时内核对信号进行默认的处理)。注意,现在进程还在内核态,内核是怎么调用用户态的handle函数的呢?
直接调用可以吗?当然不行。内核代码运行在高CPU特权级别下,如果直接调用handle函数,则handle函数也将在相同的CPU特权下被执行。那么用户将可以在handle函数里面为所欲为。
所以,调用handle必须先返回用户态。但是返回用户态后,程序流程又不受内核控制了,难不成内核还真的把用户进程的可执行代码临时改掉?
内核实际的做法还是比较巧妙。用户进程进入内核以后,都会在其对应的内核栈上留下返回地址,以便流程返回。内核调用handle函数的办法就是临时改掉栈上的返回地址,然后按原有的返回用户态的流程去返回。结果这一返回,就到了handle函数去了。(当然,需要修改的并不止是返回地址,而是一整个调用栈。)
虽然现在临时把返回地址改了,但是用户进程最终还是要返回到原先那个返回地址去的。那么,原先的返回地址及其调用栈应该保存在哪里呢?进程的内核栈空间有限,并且还需要应付handle函数中可能发生的系统调用,所以内核把这些信息放在内核栈上是不现实的,只能压到了用户栈上去。
当handle函数执行完毕,执行流程要返回到内核去。同样,由于CPU特权级别不同,从handle函数返回内核时不能单纯地利用RET指令去返回的。需要执行一次系统调用。
在handle执行完后,为什么要回到内核,再从内核返回到原始返回地址呢?如果直接返回到原始的返回地址那自然是很便捷。并且要这么做也不难,原始返回地址及其调用栈已经被压到了用户栈上,内核只需要在handle函数的调用栈上稍做手脚就行了。
1、返回到原始返回地址并不是回到那个地址就行了,需要把整个现场都恢复(主要是寄存器什么的)。当然,内核也可以在用户栈上面压一些代码,来完成这些事情;
2、现在可能不止一个信号要处理,最好让用户进程返回内核,继续处理其他信号;
为了返回内核,首先,内核在返回到handle函数之前,先将某个返回地址压到用户栈上,以便从handle返回时能够返回到指定的地址上。这个指定的地址其实也在进程的用户栈上,内核又在这个地址上放了几条指令(在栈上放置可执行代码),让进程去调用一个名叫sigreturn的系统调用。
返回到handle函数前的用户栈大致如下:
原有数据 -> 调用sigreturn的指令(设其地址为a) -> 原始返回地址及其调用栈 -> 返回地址(值为a) -> handle的栈变量
内核在handle函数的调用栈上放置sigreturn指令,这是在linux 2.4时的做法。每次调用用户的handle函数都需要向用户栈拷贝这么几条指令,这并不太好。
linux 2.6有一个叫vsyscall page的页面,上面包含了内核为用户程序准备的一些指令,其中就包括调用sigreturn指令。这个vsyscall页被映射到每个进程的虚拟地址空间靠近末尾的部分,被所有用户进程共享,对于用户进程是只读的。这样,handle函数的调用栈上就不需要再塞入sigreturn指令了,直接将handle函数的返回地址设为vsyscall页中对应的代码即可。
为了让handle执行完以后自动调用sigreturn返回内核,内核做了很多事情。那么可不可以约定好,让用户自己去调用sigreturn呢?
当然,这是可以的。只是为了让信号处理机制成为一套完整的机制,内核并没有这么做。否则用户在handle函数里面忘记调用sigreturn的话,可能莫名其妙地进程就崩溃了。而编译器也很难找出这样的错误。
进程调用sigreturn系统调用重新进入内核后,压在用户栈上的原始返回地址及其调用栈被获取。最终内核又会修改栈,让进程返回用户空间时返回到这个原始返回地址上。
本文浅析了linux异步信号handle的方法,包括异步信号的含义、产生、发送、接收、处理和忽略等方面。通过了解和掌握这些知识,我们可以掌握Linux信号处理的核心知识,从而提高系统的稳定性和效率。当然,linux异步信号handle还有很多其他的特性和用法,需要我们不断地学习和研究。希望本文能给你带来一些启发和帮助。
以上是linux异步信号handle浅析的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

CentOS 和 Ubuntu 的关键差异在于:起源(CentOS 源自 Red Hat,面向企业;Ubuntu 源自 Debian,面向个人)、包管理(CentOS 使用 yum,注重稳定;Ubuntu 使用 apt,更新频率高)、支持周期(CentOS 提供 10 年支持,Ubuntu 提供 5 年 LTS 支持)、社区支持(CentOS 侧重稳定,Ubuntu 提供广泛教程和文档)、用途(CentOS 偏向服务器,Ubuntu 适用于服务器和桌面),其他差异包括安装精简度(CentOS 精

CentOS 安装步骤:下载 ISO 映像并刻录可引导媒体;启动并选择安装源;选择语言和键盘布局;配置网络;分区硬盘;设置系统时钟;创建 root 用户;选择软件包;开始安装;安装完成后重启并从硬盘启动。

CentOS将于2024年停止维护,原因是其上游发行版RHEL 8已停止维护。该停更将影响CentOS 8系统,使其无法继续接收更新。用户应规划迁移,建议选项包括CentOS Stream、AlmaLinux和Rocky Linux,以保持系统安全和稳定。

CentOS系统下GitLab的备份与恢复策略为了保障数据安全和可恢复性,CentOS上的GitLab提供了多种备份方法。本文将详细介绍几种常见的备份方法、配置参数以及恢复流程,帮助您建立完善的GitLab备份与恢复策略。一、手动备份利用gitlab-rakegitlab:backup:create命令即可执行手动备份。此命令会备份GitLab仓库、数据库、用户、用户组、密钥和权限等关键信息。默认备份文件存储于/var/opt/gitlab/backups目录,您可通过修改/etc/gitlab

Docker利用Linux内核特性,提供高效、隔离的应用运行环境。其工作原理如下:1. 镜像作为只读模板,包含运行应用所需的一切;2. 联合文件系统(UnionFS)层叠多个文件系统,只存储差异部分,节省空间并加快速度;3. 守护进程管理镜像和容器,客户端用于交互;4. Namespaces和cgroups实现容器隔离和资源限制;5. 多种网络模式支持容器互联。理解这些核心概念,才能更好地利用Docker。

CentOS硬盘挂载分为以下步骤:确定硬盘设备名(/dev/sdX);创建挂载点(建议使用/mnt/newdisk);执行mount命令(mount /dev/sdX1 /mnt/newdisk);编辑/etc/fstab文件添加永久挂载配置;卸载设备使用umount命令,确保没有进程使用设备。

如何使用 Docker Desktop?Docker Desktop 是一款工具,用于在本地机器上运行 Docker 容器。其使用步骤包括:1. 安装 Docker Desktop;2. 启动 Docker Desktop;3. 创建 Docker 镜像(使用 Dockerfile);4. 构建 Docker 镜像(使用 docker build);5. 运行 Docker 容器(使用 docker run)。

CentOS 停止维护后,用户可以采取以下措施应对:选择兼容发行版:如 AlmaLinux、Rocky Linux、CentOS Stream。迁移到商业发行版:如 Red Hat Enterprise Linux、Oracle Linux。升级到 CentOS 9 Stream:滚动发行版,提供最新技术。选择其他 Linux 发行版:如 Ubuntu、Debian。评估容器、虚拟机或云平台等其他选项。
