目录
[六、int 0x80 的思考](#六、int 0x80 的思考)
一、进程阻塞的过程
进程调用了一个系统调用函数去访问资源,CPU去执行系统调用的代码,也就是内核代码,内核代码里写了 if (资源不可用) { 阻塞当前进程->执行阻塞原语; } 这个逻辑,系统调用间接触发了内核中的阻塞原语。
CPU 执行内核代码 → 内核代码里调用阻塞原语 → 把当前进程链入等待队列
也就是说进程本身的代码不会管资源能不能用,而是自己只调用了一个系统调用去访问资源,至于资源是否可用、状态的切换,都是由CPU执行操作系统的代码来完成的,但这种行为算是进程主动的阻塞自己
-
"进程主动阻塞" → 强调的是:触发点是进程自己发起的系统调用
-
"操作系统把进程阻塞" → 强调的是:实际动作是内核执行的
二、阻塞队列
CPU是没有自己的阻塞队列的,书上说的CPU阻塞队列其实都是那些阻塞事件的阻塞队列;进程从事件的阻塞队列到CPU的就绪队列上后,等待CPU的调度,有了资源后,CPU使用资源=CPU执行代码去使用资源,(进程使用资源的过程也是代码,也要CPU来执行)
资源准备好了,CPU不会自动使用,资源准备好了,只是"可以继续用",不是"已经用了"
其实就CPU回到没执行完的地方,继续执行:

当然,去使用资源的代码是程序员写的,具体使用资源的底层是OS的代码的,
资源就绪后,进程并不会自动使用资源;CPU 调度该进程后,会从上次阻塞的位置继续执行进程代码,由这些代码(程序员写的或 OS 提供的)真正去访问和使用资源。
三、对时钟中断与中断的思考🤔
所有的中断响应过程都会有:关中断、保存断点和程序状态、识别异常和中断并转到相应的处理程序。
在时钟中断中,它是这样处理的:
时钟中断发生,CPU自动保存进程A的断点和当前程序状态(压入A的内核栈)
✅ 此时:
-
断点 = 进程 A
-
栈 = 进程 A 的内核栈
中断处理过程中发生了"进程切换"
(CPU执行代码)
保存现场:
把 CPU 里的寄存器
→ 复制到 进程 A 的 PCB
恢复现场:
把 进程 B 的 PCB
→ 复制到 CPU 寄存器
| 内容 | 原来 | 现在 |
|---|---|---|
| PC | 进程 A | ✅ 变成进程 B |
| SP | A 的内核栈 | ✅ 变成 B 的内核栈 |
| 所有寄存器 | A 的 | ✅ 变成 B |
此时,中断返回时,CPU就会回到进程B的断点处
时钟中断确实会"返回断点",但这个断点,在返回前已经被操作系统换成了进程 B 的断点。
四、虚拟地址的思考
看这 : 虚拟地址空间,就是方便你写代码的地址描述图,假的

这不就虚拟地址,前面是地址,后面是指令
为什么有虚拟地址:
在一个程序编译好后,例如进程A的代码段会存在一些指令:
mov eax, [850] ;从起始地址为850处,取出数据执行
还有 JMP 等指令,这些指令涉及到了指令和数据的地址。
可见,在形成可执行文件时,就已经给出了每个指令和数据的地址。那么好,进程在内存中调入时,换进换出时,那个指令所在的位置可能已经变了,比如变成了400,真实地址是400,但在指令中写的是850 ,那么CPU去执行这个代码时,就会找不到正确的地址。
在中断响应中,不是有一些其他的硬件来执行这一系列操作,而是CPU自动执行的,在它内部电路中设计好了:只要发生中断,CPU就自动去执行这个流程也就是中断响应
那在中断响应中,PC要指向中断服务程序的地址入口,请问,CPU都不知道内核代码的具体位置,它怎么跳转到 那里去,最好的结果不就是拿到进程中的保存的内核虚拟地址,在执行时再转换到真实地址上去
我们不关心应用程序或内核程序的代码的物理地址具体在哪,我们只需要使用虚拟地址即可。在执行时通过页表找到真实的物理地址这步骤我们并不关心"
程序员/编译器/链接器:只和虚拟地址打交道
写代码、编译、链接时用的全是虚拟地址,只有在CPU去找这个地址时,才会涉及到真实的物理地址

五、保存程序状态
在中断响应中,保存程序状态可以理解为就是保存PSW。
六、int 0x80 的思考
执行陷入指令:int 0x80,这里的int就是x86的软中断的指令,执行它主动产生一个中断
而0x80 表示中断号/中断向量号,CPU知道了中断号(知道了中断源)就去中断向量表 ,找到中断向量=中断服务程序的入口地址,从而找到该中断源的中断服务程序, int 0x80 是系统调用的入口,中断服务程序会进一步根据EAX(不就eax寄存器吗,大写我还以为是什么呢) 中的系统调用号,分发到具体的系统调用处理函数。
七、中断源
中断源 就是"能够引发中断的事件/设备",常见分类:
-
硬盘 是一个中断源 ✅:硬盘完成读写后,磁盘控制器会向 CPU 发一个硬件中断信号(如 IRQ 14/15),通知"我干完了"。
-
系统调用 也是一个中断源 ✅:通过 int 0x80 或 syscall 指令主动触发软中断/陷入,让 CPU 陷入内核态。
每个中断源(或者说每个中断向量)都有对应的中断服务程序(ISR):
-
硬盘的 IRQ → 对应硬盘驱动中的中断处理程序(处理数据传输完成、错误处理等)
-
int 0x80 → 对应系统调用统一入口处理程序(如 system_call),再根据具体系统调用号分发
不过要注意一个细节:
-
多个外部设备可能共享同一个 IRQ 线,这时一个中断向量可能对应多个 ISR,内核会依次调用。
-
但逻辑上每个中断源都有自己专属的处理程序,这是驱动开发的基本模型。
总结一句话
中断响应时,硬件自动保存断点(PC)和程序状态(PSW/FLAGS),软件再保存其余现场;int 0x80
触发一个软中断,让 CPU 从用户态陷入内核态,跳转到系统调用统一入口处理程序
用中断号索引中断向量表找到服务程序;系统调用和硬盘都是中断源,各自有对应的中断处理程序。所以每个中断源都有自己的一些中断处理程序。
八、陷入机制
所以"陷入"也只是一个机制,int 就能产生中断,系统调用也只是利用这个机制而已,
在 int 0x80 之前,系统调用是要通过寄存器传参:
write(1, "hello", 5);
汇编代码:
mov eax, 4 ; sys_write
mov ebx, 1 ; fd = stdout
mov ecx, msg ; buffer
mov edx, 5 ; length
int 0x80
1、用 eax 表示"要调用哪个系统调用"
eax = 系统调用号,例如:
2、用其他寄存器传参数
流程就是:CPU 把eax/ebx/ecx/edx ..... 设置参数,执行到int 0x80 ,陷入内核态,跳转到系统调用服务程序的地址,从eax 取出系统调用号,查系统调用表 sys_call_tablreax ,在去执行具体的系统调用函数
九、MMU的简略描述

十、王道题目知识点总结
- 进程映像也就是进程实体,就像是给进程在运行过程中,拍了一张照片。主要包括三个部分:程序段、相关数据段、PCB。
- 程序是一个静态的概念由代码和数据组成
- 进程是一个动态的概念由程序、和该程序的运行上下文组成
PS:进程时一个程序在运行时,OS方便管理这个程序的执行而提出的概念,它的堆、栈、通用寄存器的值、PC的值... ,都是记录在这个进程映像/实体,随着程序的执行,里面的值是不断在变化的,所以,与程序相比(当然也只能和程序比),最重要的特性就是动态。
- 一个进程就是一个正在运行的程序,由这个程序和在计算机中涉及到这个程序的所有状态信息组成(无非就是在内存和CPU中的状态,也就是运行上下文,以及一些系统资源)
- 进程的生命周期是断断续续的,并发的进程具有间断运行的特点
- 进程具有失去封闭性:进程的执行结果与速度有关,使得进程的执行具有不可再现性(会相互影响,体现在速度不同,共享变量,而导致执行结果与速度有关)
- 优先级分为静态和动态,动态优先级是随运行情况而随时调整的
- 单处理器系统发生死锁时,有可能进程全部都处于阻塞态
- 并发进程执行的相对速度不是只由优先级有关,最主要的还是与调度策略有关
- 一个进程在其生命周期中可执行多个程序;(没弄懂)
- 正文段=数据段+代码段
- 涉及用户级线程切换的事件不会设计操作系统
- 导致创建新进程的事件 :
- 操作系统启动
- 用户发出请求,创建一个新进程(也就是用户与OS的交互会创建新..)
- CPU执行一个进程代码,执行到了创建新进程的系统调用