【Linux】从内存布局到信号屏蔽:Linux 内核态与用户态交互核心知识点汇总

前言:欢迎 各位光临 本博客,这里小编带你直接手撕,文章并不复杂,愿诸君耐其心性,忘却杂尘,道有所长!!!!

IF'Maxue :个人主页
🔥 个人专栏 :
《C语言》
《C++深度学习》
《Linux》
《数据结构》
《数学建模》

⛺️生活是默默的坚持,毅力是永久的享受。不破不立!

文章目录


内存中的程序与操作系统

程序一运行,它的代码和要用的数据就会"住进"物理内存;操作系统本身也是软件,自然也得占一块内存空间。

每个用户程序(进程)都有自己专属的"地址映射表"(用户页表)------就像每家有自己的门牌号对照表,所以这类表会有很多份;但操作系统的"地址映射表"(内核页表)全系统只需要一份,所有进程共用。

为啥这么设计?很简单:操作系统的代码和数据是固定的,一份映射表就够让所有进程找到它,不管进程怎么切换,都能精准定位到操作系统。

那操作系统的内存里都装了啥?看下面这张图就清楚了:


用户态与内核态:权限边界

用户进程和操作系统(内核)共用0-4GB的"虚拟内存地盘"。这时候你可能会问:用户进程会不会偷偷跑到内核的地盘,乱访问内核的代码和数据?

答案是:绝对不会!因为操作系统对谁都不放心,它用"用户态"和"内核态"划了条严格的权限红线:

  • 用户态:进程以普通用户身份运行,只能在自己的0-3GB虚拟内存里折腾;不用麻烦操作系统时,直接用自己的虚拟地址就能操作自己的资源;
  • 内核态:进程以内核身份运行(比如要调用系统功能时),能访问整个0-4GB虚拟内存,负责管理电脑的全局资源(比如CPU、内存)。

权限识别与切换

CPU里有个cs寄存器,它的前两个比特位是"权限身份证"(CPL),能判断当前进程的权限:

  • 数值0:内核态;
  • 数值3:用户态。

如果用户态进程敢碰3-4GB的内核地盘,CPU一检测到越权,就会直接终止这个进程,绝不留情。

那用户态怎么切到内核态?得用专门的"指令钥匙":

  • int 0x80:比较老的系统调用方式;
  • syscall:更高效的系统调用方式。
    这两个指令的作用很简单:把cs寄存器前两位改成0(切到内核态),再跳转到内核的内存地址------相当于"进入内核的办公区"。

段描述符表控权

除了用户态、内核态的大划分,还有"段描述符表"(分全局、局部两种)来细化权限管理。表里面的RPL和DPL是两个"权限检查官":

  • DPL:某块内存区域(段)本身的权限级别,规定了访问它至少需要什么权限;
  • RPL:请求访问该区域的进程的权限级别。内核会对比这两个级别,只有满足要求,才允许进程访问。

捕捉信号:sigaction用法

在Linux里,除了signal函数能处理信号,sigaction是更灵活的"信号处理器"------既能查看当前信号的处理方式,也能修改它的处理动作。

sigaction函数结构

这张图把函数的"长相"和参数分工讲得很清楚:

  • signum:要操作的信号编号(比如SIGINT,就是按Ctrl+C触发的信号);
  • act:指向sigaction结构体的指针,里面装着新的信号处理配置(比如用哪个函数处理信号);
  • oldact:用来保存原来的信号处理配置,不用保存的话填NULL就行。

函数返回值

  • 成功:返回0;
  • 失败:返回-1,还会设置errno变量,告诉你哪里出错了。

sigaction的优势

它比signal函数功能更全------不仅能处理普通信号,还能处理实时信号,应对复杂的信号场景更给力。

代码示例与运行结果

下面是实际使用代码,注释写得很细,跟着看就能懂:

比如代码里定义了sig_handler函数处理信号,再用sigaction把SIGINT信号和这个函数绑定;运行后按Ctrl+C,就能看到信号被成功捕捉,输出对应的提示------运行效果如下:


sa_mask信号集:屏蔽规则

sigaction结构体里有个sa_mask成员,它是"信号屏蔽清单"------负责控制信号处理期间,哪些信号不能进来打扰。

核心机制

当某个信号的处理函数开始工作时,内核会自动把这个信号加到"屏蔽表"(block表)里,把对应的位从0改成1------防止同一个信号反复来捣乱;等处理函数执行完返回,再把这个信号从屏蔽表里去掉,位从1改回0。

还有个"未决表"(pending),状态和屏蔽表正好相反:信号没处理时位是1,处理完就变成0。

说白了:操作系统不允许同一个信号同时被多次处理,得一个一个来。

规则更新说明

关于屏蔽表和未决表的状态变化,看这张图就能理清:

实际系统表现与扩展屏蔽

在Ubuntu 20.04、CentOS 7这些常见系统里,当前正在处理的信号会被自动屏蔽。如果想在处理某个信号时,顺便屏蔽其他信号,把那些信号加到sa_mask里就行。


扩展屏蔽代码示例

下面的代码演示了怎么给sa_mask加额外的屏蔽信号------比如处理SIGINT时,顺便屏蔽SIGQUIT(按Ctrl+\触发的信号),这样在处理SIGINT期间按Ctrl+\,信号会被屏蔽,等SIGINT处理完才会生效:

相关推荐
电梯界知识分子2 分钟前
江西赣州赣县三层设计师自建房:1700mm中空极限利用,全观光铝合金电梯的精度与防震处理
大数据·服务器·网络·人工智能·家用电梯
wtblszn1 小时前
实验室通风设备远程监控运维管理系统方案
运维
syagain_zsx2 小时前
spdlog实战:日志分级、滚动与性能调优
linux·c++·日志库·二次开发日志库
GeW14 小时前
新质生产力路线图Linux、数据库、国产化替代一次讲透
linux
aningx16 小时前
cachyos 从 GRUB 切换到 rEFInd
linux
第404号工位18 小时前
40块钱二手瘦客户端,如何跑满家庭物联网中枢?(拒绝Docker爆盘实录)
linux·架构·node.js
对象存储与RustFS18 小时前
网盘限速逼你开会员?用 RustFS 自己搭一个不限速的“私人网盘
服务器·后端·docker
骑着蜗牛撵大象32719 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
众壹新能源科技20 小时前
逆变器自带无功不够用,加装5MVar SVG后功率因数从0.85回到0.99
运维·人工智能·自动化
..Dauntless..20 小时前
【Linux】一切皆文件和缓冲区
linux·运维·服务器