【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处理完才会生效:

相关推荐
落羽的落羽7 小时前
【Linux系统】C/C++的调试器gdb/cgdb,从入门到精通
linux·服务器·c语言·c++·人工智能·学习·机器学习
张彦峰ZYF7 小时前
高频面试题(含笔试高频算法整理)基本总结回顾5
linux·运维·服务器
liuccn7 小时前
Ubuntu 22.04 离线升级 OpenSSH 到 9.8p1
linux·ubuntu·github
DO_Community7 小时前
裸金属 vs. 虚拟化 GPU 服务器:AI 训练与推理应该怎么选
运维·服务器·人工智能·llm·大语言模型
徐子元竟然被占了!!7 小时前
Linux的df和du
linux·运维·服务器
集大周杰伦7 小时前
Linux网络编程核心实践:TCP/UDP socket与epoll高并发服务器构建
linux·tcp/ip·网络编程·socket·字节序·套接字·i/o多路复用
星哥说事7 小时前
NAS/SAN存储:NFS/iSCSI/FC 存储协议与应用场景
运维
科技峰行者7 小时前
华为发布Atlas 900 DeepGreen AI服务器:单机柜100PF算力重构AI训练基础设施
服务器·人工智能·华为·aigc·gpu算力
Mr. Cao code7 小时前
实战:Docker构建Haproxy负载均衡镜像
linux·运维·ubuntu·docker·容器·负载均衡