Skip to content

I/O软件层次结构

2026 大纲 五(一)3 I/O 软件层次结构,补充说明点名四层:中断处理程序、驱动程序、设备独立软件、用户层 I/O 软件。

四种控制方式,怎么变成一句 read()

上一节把 CPU 等设备的四种姿势讲完了。但它们全都太硬—— 轮询要死盯状态位,DMA 要写三个寄存器再仲裁总线,通道还要写一段通道程序。 没有哪个应用程序员愿意为了读一个字符去干这些事。

而且设备还有上一节没提的另一半麻烦:每种设备的寄存器布局都不一样。 就算你愿意直接写,换一块网卡也得重写一遍。

所以 I/O 软件必须分层,而层怎么切不是随便定的,它由四条设计目标推出来: 要设备无关(换设备不改应用)、要能处理出错、要同时支持同步与异步、 要屏蔽硬件细节

分完之后,归层只需一条判据:这一步的代码换一种设备要不要重写?

要重写 → 设备驱动程序(它是唯一真正碰硬件细节的一层); 不用重写但在内核态 → 设备独立软件; 在用户态 → 用户层 I/O 软件; 由中断信号触发、处理的是中断机制本身 → 中断处理程序

⚠️ 有一处画法容易误导:中断处理程序画在最底层,但它并不比驱动程序更靠近硬件—— 它面对的是硬件中断机制(判中断源、保存现场、唤醒进程),不是某台设备的寄存器布局。 层次图的上下表达的是调用与响应方向,不是"离硬件多近"。

这一节最实用的产出是最后那条完整流程——一次读盘从用户程序走到硬件再走回来, 每一步落在哪一层。真题反复考它,而且三年考了同一件事。

一、为什么要分层:四条设计目标推出四层

I/O 软件的分层不是"为了整齐",是四条互相冲突的设计目标逼出来的:

设计目标若不分层会怎样于是切出哪一层
设备无关性:程序员写程序时尽量与具体物理设备无关换一台打印机就要改应用程序设备独立软件(做命名映射、统一块大小)
出错处理:错误尽量在靠近硬件的位置解决,不让高层感知一次磁盘重试的抖动要一路冒泡到用户程序驱动程序(重试)+ 设备独立软件(报告)
同步/异步:进程发出 I/O 后要能被阻塞、也要能继续跑每个应用都得自己写等待与唤醒逻辑中断处理程序(负责唤醒)
屏蔽硬件细节:上层不该知道控制器有几个寄存器每个应用都要懂每种控制器驱动程序(唯一与硬件相关的一层)

推导链是这样的:

要让上层不改代码就能换设备 ⇒ 必须有一层专门吸收设备差异 ⇒ 这层必须知道寄存器布局,于是它每种设备一份(驱动程序) ⇒ 既然每种设备一份,那些与设备无关的公共动作(命名、权限、缓冲、分配、通用差错)就不该在每份驱动里各写一遍 ⇒ 抽出来放到驱动之上(设备独立软件) ⇒ 设备完成时要能主动通知,且这套通知机制是硬件中断机制而非某台设备的语义 ⇒ 再切一层(中断处理程序) ⇒ 应用不该直接调内核,得有库函数封装、有些功能(如 SPOOLing)在内核外做更合适 ⇒ 最上面一层(用户层 I/O 软件)

二、各层的功能

第 1 层:用户层 I/O 软件(用户态)——提供 open/close/read/write/ioctl 等系统调用接口(详见输入输出应用程序接口)与库函数封装(printfscanf 这类;C 库函数与系统调用大体一一对应,Windows 的 Win32 API 则与系统调用一一对应);SPOOLing 的守护进程运行在内核之外,但仍属 I/O 系统。

第 2 层:设备独立软件(内核态)

功能具体做什么
驱动程序的统一接口要求每个驱动与 OS 之间的接口相同或相近,使新增驱动变容易;并把抽象设备名映射到具体驱动的入口
设备保护禁止用户直接访问设备,检查访问权限
缓冲管理为字符设备与块设备分别配置单缓冲、双缓冲、循环缓冲、缓冲池,详见缓冲区管理
差错控制只处理驱动程序处理不了的错误
设备分配与回收独占设备必须由系统统一分配,详见设备分配与回收
提供与设备无关的逻辑块大小不同磁盘扇区大小可能不同,本层把它们统一成大小一致的逻辑数据块再交给上层

设备独立性的落点是逻辑设备表 LUT(Logical Unit Table)

逻辑设备名物理设备名驱动程序入口地址

这和地址变换是同一个套路:应用程序里用逻辑地址、系统用物理地址,中间靠页表;应用程序里用逻辑设备名、系统用物理设备名,中间靠 LUT。都是"引入一层间接,换取上层不必知道下层的具体位置"。

第 3 层:设备驱动程序(内核态)——唯一与设备硬件细节相关的一层,每种设备一份。接收上层的抽象命令(read 一个盘块号),转换为具体的低层操作序列(柱面号、磁头号、扇区号,写进控制器寄存器),启动设备并在完成后向上报告。详见设备驱动程序接口

第 4 层:中断处理程序(内核态)——进程发出 I/O 请求后通常被阻塞,直到数据传输结束产生 I/O 中断。工作流程:① 检查设备状态寄存器,判断中断产生的原因 → ② 若传输出错,向上层报告并尝试重新执行 → ③ 若正常结束,唤醒等待该数据传输的进程使其转为就绪态 → ④ 若还有排队的 I/O 请求,通知相关软件启动下一个。

三、一次读磁盘的完整流程:每步标出所属层次

步骤所属层次这一步为什么归它
用户层 I/O 软件发生在用户态,只是发起调用
② ③设备独立软件参数校验、缓冲命中、名字映射、权限检查、排队与阻塞——全都与是哪台设备无关
设备驱动程序要写具体控制器的寄存器、要知道用轮询还是 DMA,换设备就得重写
硬件控制器与设备自己完成
⑥ ⑦中断处理程序面向硬件中断机制:判原因、报错误、唤醒进程
驱动程序 + 设备独立软件驱动把数据从控制器搬出,设备独立软件拷入用户缓冲区
用户层 I/O 软件回到用户态,系统调用返回

设备独立软件与驱动程序的界限是浮动的

教材提到,这条界限因 OS 和设备而略有浮动:出于效率考虑,本该由设备独立软件做的事有时被下放到驱动里。判据仍是"换设备要不要重写",但具体系统的切法可以不同。

考点速记

  1. 四层自上而下用户层 I/O 软件 → 设备独立软件 → 设备驱动程序 → 中断处理程序 → 硬件,由设备无关性、出错处理、同步/异步、屏蔽硬件细节四条设计目标推出。
  2. 归层唯一判据:这一步的代码换一种设备要不要重写? 要重写 → 驱动程序;不用重写但在内核态 → 设备独立软件;在用户态 → 用户层;由中断信号触发、处理的是中断机制本身 → 中断处理程序。
  3. ⚠️只有驱动程序真正碰硬件细节。 中断处理程序虽画在最底层,但它面对的是硬件中断机制(判中断源、保存现场、唤醒进程),不是某台设备的寄存器布局。层次图的上下是调用与响应方向,不是"离硬件多近"。
  4. 只有用户层 I/O 软件跑在用户态(库函数、系统调用封装、SPOOLing 守护进程),其余三层全在内核态——四层之间只有第 1 层与第 2 层之间那一次态切换
  5. 差错处理按"能不能就地消化"分层:驱动先扛(传输出错就地重传,连续多次仍失败才上报);设备独立软件只管驱动处理不了的,并决定是终止请求进程还是只通知它。离硬件越近,越知道这个错误是不是暂时性的。
  6. 两类错误暂时性错误(电源波动、网络丢包)靠重试纠正;持久性错误(掉电、盘面划痕)需查明原因,个别可由 OS 消化(如把坏块记入坏块表)。
  7. 术语对齐:考纲用词是「设备独立软件」,教材里的"与设备无关的 I/O 软件""设备无关性软件"是同一层
  8. 完整流程:用户程序 → 系统调用处理程序(用户层/设备独立软件的入口)→ 设备独立软件设备驱动程序 → 启动设备 → 设备完成后发中断 → 中断处理程序 → 唤醒进程 → 数据经内核缓冲区拷到用户空间 → 系统调用返回。
  9. 中断处理程序负责把数据从控制器的数据寄存器搬进内核缓冲区,并唤醒等待的进程;数据进用户缓冲区要等系统调用返回时才做(详见 I/O 控制方式)。
  10. 分层的代价是每多一层多一次数据拷贝外加一次态切换——缓冲公式里的 M、内存映射文件、DMA 分别对应这笔代价的量化与两种省法。

这一节在真题里被考过的形式

最突出的特点是同一个问题被问了三年——2011、2012、2013 连续三道题问的都是 "用户程序发出磁盘 I/O 请求后,系统的处理流程",只是包装略有不同。

  • 问 I/O 处理流程的顺序(2011-26、2012-26、2013-25)。答案都是同一条链:用户程序(或用户级 I/O 软件)→ 系统调用处理程序 / 设备无关软件 → 设备驱动程序 → 中断处理程序。⚠️ 四个选项的花样只有一种——把驱动程序和中断处理程序对调。判据是因果方向:驱动程序负责"发出请求、启动设备",中断处理程序负责"设备干完了通知回来",必须先有请求才有完成,所以驱动一定在中断处理之前。2013-25 换了个问法(问流程中的某一环是什么),答设备驱动程序,本质仍是同一条链。
  • 问 I/O 数据流各段归谁(2010-32、2024-31、2026-32,与 I/O 控制方式共享,那边详述)。核心是速记第九条——中断处理程序只把数据搬到内核缓冲区
  • 给一次键盘输入的六个操作,问顺序、进程状态与态、以及哪段属于驱动程序(2023-46,大题)。正确顺序是 ⑥ 用户按键 → ④ 启动键盘中断处理程序 → ③ 字符从键盘控制器读入系统缓冲区 → ① 将 P 插入就绪队列 → ⑤ P 从系统调用返回,而 ② 将 P 插入阻塞队列发生在最前面(P 发出系统调用后没数据可读,立刻阻塞)。⚠️ 四个分问的判据:② 之后 CPU 一定切走(进程阻塞就必须让出);① 之后调度程序才可能选中 P③ 那段代码属于键盘驱动程序(它要读控制器的寄存器,换一种键盘就要重写);中断处理程序执行时 P 处于阻塞态、CPU 处于内核态

复习优先级必须拿满,而且性价比极高。 三道选择题问的是同一条链, 判据只有一句"先有请求才有完成,所以驱动在中断处理之前"。 大题 2023-46 把本章与进程状态串在一起,但每个分问都能回到速记第二条那个归层判据。 第三条(中断处理程序并不比驱动更靠近硬件)是最容易被层次图误导的一处,要单独记。

易错:把设备驱动程序和中断处理程序在流程里的先后对调。驱动发出请求在前,中断处理响应完成在后

易错:认为中断处理程序比驱动程序更接近硬件。只有驱动程序碰设备的寄存器布局;中断处理程序面对的是中断机制。

易错:认为四层之间每层都要态切换。只有第 1 层与第 2 层之间那一次——下面三层全在内核态。

易错:认为出错一律上报给上层。驱动先就地重试,连续多次失败才上报;离硬件越近越知道这错是不是暂时的。

易错:认为中断处理程序执行时进程处于就绪态。它处于阻塞态——正是因为等 I/O 才阻塞的,要等数据到位后才被插入就绪队列。

教材出处
  • 与设备无关软件的五项功能(驱动程序统一接口、缓冲、错误报告、分配与释放专用设备、提供与设备无关的块大小)、逻辑设备名与 I/O 重定向、逻辑设备表 LUT:汤小丹《计算机操作系统》6.5.1~6.5.4 节,印刷 p199–203
  • 暂时性错误与持久性错误的区分及处理分工:同书 6.5.2 节,印刷 p200
  • I/O 软件的四条设计考虑与分层结构、一次读操作的完整步骤、中断处理程序的工作流程:孙钟秀、费翔林《操作系统教程》(第 6 版)4.2.1~4.2.2 节,印刷 p129–131

相关知识

I/O 控制方式输入输出应用程序接口设备驱动程序接口缓冲区管理设备分配与回收

真题练习