<操作系统>OS5 设备管理

本文最后更新于:2023年6月27日 上午

OS5 设备管理

I/O 设备:输入输出设备。能将数据输入计算机,或接收计算机输出数据的外部设备。是计算机中的硬件部件。

按照使用特性,I/O 设备分为三种:人机交互类外部设备、存储设备、网络通信设备

按照传输速率,I/O 设备分为:低速设备、中速设备、高速设备

按照信息交换单位,I/O 设备分为:块设备(传输快、可寻址)、字符设备(传输慢、不可寻址、常采用中断驱动)

OS5.1 I/O 控制

I/O 设备由机械部件与电子部件组成。I/O 设备的电子部件通常是一块插入主板扩充槽的印刷电路板。

#I/O 控制器

CPU 不能直接控制 I/O 设备的机械组件,因此 I/O 设备需要一个电子部件作为 CPU 与 I/O 设备的中介,用于实现 CPU 对设备的控制。这些电子部件就是 I/O 控制器(设备控制器)。CPU 能控制 I/O 控制器,而 I/O 控制器能操纵机械部件。

I/O 控制器的功能有以下几点:

  • 接收识别 CPU 指令:I/O 控制器设置有相应的 控制寄存器 来存放命令和参数。

  • 向 CPU 报告设备状态:I/O 控制器设置有相应的 状态寄存器 来记录设备的状态。

  • 数据交换:I/O 控制器设置有相应的 数据寄存器

    输出时暂存 CPU 发来的数据,由控制器传送给设备。输入时暂存设备发来的数据,由 CPU 从中取走数据。

  • 地址识别:为区分各个寄存器,I/O 控制器也会给寄存器 编址。I/O 控制器通过 CPU 给出的地址判断要读写的目标寄存器。

I/O 控制器的组成分为三部分:

  • CPU 与控制器的接口:实现 CPU 与控制器的通信。

    CPU:通过 控制线 发出命令;通过 地址线 指明操作的设备;通过 数据线 来取出/放入数据。

  • I/O 逻辑:负责接收与识别 CPU 的命令,并对设备发出指令

  • 控制器与设备的接口:实现控制器与设备的通信。

一个控制器可能对应多个设备。同时,各类寄存器也可能有多个。为给寄存器编址,有以下两种策略:

  • 内存映像 I/O:让寄存器占用内存地址的一部分。

    控制器中的寄存器与内存地址统一编制,其地址编号追加在内存地址之后。

    这种情况下,可以采用对内存操作的指令来操作控制器。

  • 寄存器独立编址:采用 I/O 专用地址。

    控制器中的寄存器使用单独的地址,其地址编号与内存无关。

    此时需要专门的指令实现对控制器的操作,不仅要指明寄存器地址,还要指明控制器编号。

#I/O 控制方式

I/O 控制器控制设备读写的方式有以下几种:

  • 程序直接控制方式

    最早期的控制方式。

    sequenceDiagram
    autonumber
    participant 存储器
    participant CPU
    participant I/O 控制器
    CPU ->> I/O 控制器: 发出读命令
    loop
    	I/O 控制器 -->> CPU: 检查状态
    end
    I/O 控制器 ->> CPU: 读取字
    CPU ->> 存储器: 写入字

    该方式每次读写一个 。读写时,每个字的操作都要 CPU 帮助。

    该方式下,CPU 需要不断轮询检查,干预频繁。CPU 与 I/O 设备只能串行工作,CPU 长期处于忙等状态,利用率低。

  • 中断驱动方式

    引入中断机制。发出读写指令后,让等待 I/O 的进程阻塞。I/O 完成后,向 CPU 发出中断信号,此时 CPU 中断当前任务、保存运行环境,并读取数据,写入主存。接着,CPU 恢复原先进程的运行环境,并继续执行。

    sequenceDiagram
    autonumber
    participant 存储器
    participant CPU
    participant I/O 控制器
    CPU ->> I/O 控制器: 发出读命令
    CPU --> CPU: 处理其他进程
    note left of I/O 控制器: 就绪后
    I/O 控制器 ->> CPU: 发出中断信号
    CPU --> CPU: 中断当前进程
    I/O 控制器 ->> CPU: 读取字
    CPU ->> 存储器: 写入字
    CPU --> CPU: 恢复当前进程

    该方式每次读写一个 。读写时,每个字的操作都要 CPU 帮助。

    虽然等待 I/O 时 CPU 可以切换到其他任务执行,CPU 与 I/O 设备能并行工作,但频繁的中断处理会消耗较多 CPU 时间。

  • 直接存储器存取方式(DMA 方式)

    主要用于块设备的 I/O 控制。

    DMA 方式的数据传输单位是 。数据从设备直接放入内存,仅传输开始、结束时需 CPU 干预,中途不需要 CPU 帮助。

    sequenceDiagram
    autonumber
    participant CPU
    participant I/O 控制器
    participant 存储器
    CPU ->> I/O 控制器: 发出读命令
    CPU --> CPU: 处理其他进程
    I/O 控制器 ->> 存储器: 写入数据
    note left of I/O 控制器: 完成后
    I/O 控制器 ->> CPU: 发出中断信号

    DMA 控制器 中设置了以下寄存器:

    • MAR(内存地址寄存器):提示数据在内存的什么位置
    • DR(数据寄存器):暂存数据
    • DC(数据计数器):表示剩余要读写的字节数
    • CR(命令/状态寄存器):存放 CPU 的指令,或设备的状态信息。

    CPU 仅在传送开始/结束时才需要介入。每次读写一个或多个连续块(并写入连续的存储空间),数据不需要经过 CPU。

  • 通道控制方式

    通道:一种硬件。可以识别并执行一系列通道指令。与 CPU 相比,通道能执行的指令非常单一。通道程序放在主机内存中,与 CPU 共享内存。

    一个通道可控制多个设备控制器,一个设备控制器可控制多个设备。

    sequenceDiagram
    autonumber
    participant CPU
    participant 内存
    participant 通道
    participant I/O 控制器
    participant I/O 控制器2
    CPU ->> 通道: 发出指令
    CPU --> CPU: 处理其他进程
    内存 ->> 通道: 通道程序(读取任务清单)
    通道 ->> I/O 控制器: 执行任务
    通道 ->> I/O 控制器2: 执行任务
    note left of 通道: 完成后
    通道 ->> CPU: 中断指令

    通道控制方式需要额外硬件实现。CPU 的干预频率极低。每次读写一组数据块(可以是非连续),数据在通道控制下进行,不需要经过 CPU。

OS5.2 I/O 软件层次结构

I/O 软件层次结构自上而下分为:用户层软件、设备独立性软件、设备驱动软件、中断处理软件、硬件。

  • 用户层软件(系统调用处理层)

    用户层软件实现了与用户交互的接口,用户直接使用该层提供的、与 I/O 操作相关的库函数,以操作设备。

    用户层将用户请求翻译成格式化的 I/O 请求,并通过系统调用请求来操作系统内核的服务。

  • 设备独立性软件(设备无关性软件)

    与设备硬件特性无关的功能几乎都在本层实现。

    本层向上层提供统一的调用接口;实现设备保护(类似于文件保护);进行差错处理;实现设备的分配与回收;管理数据缓冲区;建立逻辑设备名与物理设备名的映射(通过设备逻辑表 LUT 完成),并选择调用的驱动程序。

  • 设备驱动软件

    设备驱动程序主要负责对硬件设备的具体控制,将上层发出的指令转化为针对特定设备的一系列操作。

    不同的 I/O 设备特性不同,厂家要为其提供设备的硬件特性设计并提供相应驱动程序。

  • 中断处理软件

    进行中断处理。

    I/O 任务完成时,I/O 控制器会发送中断信号。系统根据中断信号类型执行相应的中断处理程序。

  • 硬件

设备独立性软件、设备驱动软件、中断处理软件 三层属于操作系统内核部分。即 I/O 核心子系统(I/O 系统)

#假脱机技术(SPOOLing 技术)

SPOOLing 技术是由软件方式模拟脱机技术,处于用户层。要实现 SPOOLing 技术,必须有多道程序技术的支持。系统会建立 输入进程 和 输出进程。

一个独占式设备,可以通过该技术改造成共享设备。

当多个用户发出指令后,系统由假脱机管理进程为其进行如下操作:

  1. 在磁盘输出井中为进程申请一个空闲缓冲区,并将进程指令的数据放入其中
  2. 为用户进程创建一张指令表,将该指令表挂到假脱机队列上。
  3. 设备空闲时,输出进程从假脱机队列上取出一个指令表,把所需数据从输出井转移到输出缓冲区,再输出给设备执行。

#设备的分配与回收

设备分配时,要考虑的因素有:

  • 设备的固有属性

    分为:独占设备、共享设备、虚拟设备(SPOOLing 技术共享)。

  • 设备分配算法

    先来先服务、高优先级优先、短任务优先等

  • 设备分配的安全性

    从安全性上考虑,有两种分配方式

    • 安全分配方式:为进程分配设备后即将其阻塞,直到 I/O 完成后再将进程唤醒。

      虽然不会死锁,但 CPU 与 I/O 设备只能串行工作。

    • 不安全分配方式:进程发出 I/O 请求后,系统为其分配设备,进程可以继续执行,之后还能发出更多请求。直到某个请求不满足时才阻塞。

      虽然 CPU 与 I/O 设备能并行工作,但可能发生死锁。

为进程分配设备的方式分为静态和动态分配:

  • 静态分配:进程运行前为其分配所有所需资源,运行结束后归还资源

  • 动态分配:进程运行时动态申请设备资源

设备分配管理中,会用到一些数据结构:

  • 设备控制表(DCT):系统为每个设备配置一张 DCT,用于记录设备情况。包含:

    • 设备类型
    • 标识符(设备的物理设备名)
    • 设备状态
    • 指向控制器控制表的指针(找到该设备所属的控制器)
    • 重复执行次数(重复多次 I/O 后仍不成功则认为此次 I/O 失败)
    • 设备队列指针(等待该设备的进程队列)
  • 控制器控制表(COCT):每个设备控制器对应一张 COCT,系统根据 COCT 信息对控制器进行操作和管理。包含:

    • 控制器标识符(各控制器的唯一 ID)
    • 控制器状态
    • 指向通道表的指针(找到该设备所属的通道)
    • 控制器队列的队首指针与队尾指针(等待该控制器的进程队列)
  • 通道控制表(CHCT):每个设备控制器对应一张 CHCT,系统根据 CHT 信息对通道进行操作和管理。包含:

    • 通道标识符(通道的唯一 ID)
    • 通道状态
    • 与通道连接的控制器表的指针(找到该通道管理的所有控制器的信息 COCT)
    • 通道队列的队首指针与队尾指针(等待该通道的进程队列)
  • 系统设备表(SDT):记录了系统中 全部设备 的情况。每个设备对应一个条目。

    表项包含:设备类型、设备标识符、设备控制表(DCT)、驱动程序入口

  • 逻辑设备表(LUT):建立了逻辑设备名与物理设备名之间的映射关系

    用户进程第一次使用设备时使用逻辑设备名向操作系统发出请求。操作系统会根据用户进程指定的设备类型查找 SDT,将一个空闲设备分配给进程,并在 LUT 中添加表项。

    之后,用户再次通过相同逻辑设备名发出请求时,操作系统根据 LUT 表即可确定用户实际要使用的是哪个设备,也能确定驱动程序。

    可以在整个系统中只设置一张 LUT;也能为每个用户单独设置 LUT。

设备分配的流程如下:

graph LR
0(( ))--请求--> 1{{SDT}}--查找-->2{{DCT}}-->2c{忙碌?}--否-->3{{COCT}}-->3c{忙碌?}-->4{{CHCT}}-->4c{忙碌?}-->f(分配成功)
2c--是-->2r[等待队列]-.->2c
3c--是-->3r[等待队列]-.->3c
4c--是-->4r[等待队列]-.->4c
  1. 分配设备时,先根据请求的 逻辑设备名(即设备类型),从 SDT 中找出指定类型的、空闲的设备的 DCT。
  2. 若设备忙碌则将进程 PCB 挂到设备等待队列中,不忙碌则将设备分配给进程,并在 LUT 中新增表项。
  3. 之后,根据 DCT 找到 COCT,若控制器忙碌则将进程挂到控制器等待队列中,否则将控制器分配给进程。
  4. 再根据 COCT 找到 CHCT,若通道忙碌则将进程挂到通道等待队列中,否则将通道分配给进程。
  5. 设备、控制器、通道都分配成功时,设备分配成功。之后便可启动 I/O 设备进行数据传输。

#缓冲区管理

缓冲区:一个存储区域。可以由专门的寄存器组成,也能利用内存作为缓冲区。

缓冲区数据非空时,不能向缓冲区冲入数据,而只能将数据传出。当缓冲区为空时,可以向缓冲区冲入数据,但必须将缓冲区充满后才能传出数据。

缓冲区的作用:

  • 缓和 CPU 与 I/O 设备间速度不匹配的矛盾

    CPU 可将数据快速放入缓冲区,由 I/O 设备慢慢从缓冲区中取走数据

  • 减少对 CPU 的中断频率,放宽对 CPU 中断响应时间的限制

  • 解决数据粒度不匹配的问题

  • 提高 CPU 与 I/O 设备间的并行性

缓冲区管理策略:

  • 单缓冲

    操作系统在主存中为用户分配一个缓冲区(一般大小是一个块)。

    下面是 T>CT>C 的情况

    gantt
    
    dateFormat x
    axisFormat %L
    
    section 冲入缓冲区
    T: 0, 3
    T: 4, 7
    T: 8, 11
    T: 12, 15
    section 传出缓冲区
    M: 3, 4
    M: 7, 8
    M: 11, 12
    M: 15, 16
    section 处理数据
    C: 0, 2
    C: 4, 6
    C: 8, 10
    C: 12, 14
    

    可见,单缓冲策略下,处理数据的平均耗时为 max(C,T)+M\max(C,T)+M

  • 双缓冲

    操作系统在主存中为用户分配两个缓冲区。

    下面是一种 M+C>TM+C>T 的情况

    gantt
    
    dateFormat x
    axisFormat %L
    
    section 冲入缓冲区1
    T: 4, 8
    T: 12, 16
    section 冲入缓冲区2
    T: 0, 4
    T: 8, 12
    T: 17, 21
    
    section 传出缓冲区1
    M: 0, 2
    M: 10, 12
    section 传出缓冲区2
    M: 5, 7
    M: 15, 17
    section 处理数据
    C: 2, 5
    C: 7, 10
    C: 12, 15
    C: 17, 20

    采用双缓冲策略,处理数据块的平均耗时为 max(T,C+M)\max(T, C+M)

  • 循环缓冲区

    将多个大小相等的缓冲区链接成一个循环队列。

    会有一个 in 指针指向下一个能被冲入数据的空缓冲区,一个 out 指针指向下一个可取出数据的满缓冲区。

  • 缓冲池

    由系统中共用的缓冲区组成。这些缓冲区按使用情况分为:空缓冲队列、输入队列(装满输入数据)、输出队列(装满输出数据)

    从功能上划分,也能分为:hin(空输入数据缓冲区)、sin(满输入数据缓冲区)、hout(空输出数据缓冲区)、sout(满输出数据缓冲区)


<操作系统>OS5 设备管理
https://i-melody.github.io/2023/01/27/操作系统/5 设备管理/
作者
Melody
发布于
2023年1月27日
许可协议