I/O硬件原理
I/O硬件分类
按外设特性分类
- 使用特征:存储、输入输出、终端
- 数据传输率:低速、中速、高速
- 信息组织特征:单个字符或数据块
I/O设备的特点
- 种类多
- 差异大(控制和速度)
- 在速率相差多个数量级的不同设备上保持相对良好的性能
块设备和字符设备
块设备
将信息存储在可寻址的固定大小的数据块中
- 通常数据块大小为512字节到32768字节不等
- 块设备的主要特征是能够独立地读写单个的数据块
- 磁盘是最常见的块设备
字符设备
发送或接受字符流
- 无法编址,也不存在任何寻址操作
- 如打印机、网络接口、鼠标等
设备控制器
I/O设备通常包含一个机械部件和一个电子部件。
为了达到设计的模块性和通用性,一般将其分开。电子部分称为设备控制器或适配器,在个人计算机中,它常常是一块可以插入主板扩展槽的印刷电路板。机械部分则是设备本身。
控制器负责将驱动器读出来的比特流转换成字节块并纠错,通常该字节块是在控制器中的缓冲区中逐个比特汇集而成。在对检查和进行校验证实数据正确之后,该数据随后被拷贝到主存中。
I/O控制技术
程序控制I/O
- I/O操作由程序发起,并等待操作完成。数据的每次读写通过CPU
- 每个控制器都有一些用来与CPU通信的寄存器及数据缓存区
- 通过写入寄存器,操作系统可以命令设备发送数据、接收数据、开启或关闭或其他操作
- 通常设备有一个数据缓冲区,以供操作系统读写数据
- 设备编址方式
- I/O端口
设备寄存器单独编址,即I/O端口号
- 内存映射I/O
设备数据缓冲区按内存地址空间进行统一编址
中断驱动方式
- I/O操作是否可以开始或完成
- 检测设备控制寄存器中的状态标志位
- 使用中断方式通知CPU
- 中断驱动方式
- I/O操作由程序发起,在操作完成时(如数据可读或已经写入)由外设向CPU发出中断,通知该程序。数据的每次读写通过CPU。
- 优点
在外设进行数据处理时,CPU不必等待,可以继续执行该程序或其他程序
- 缺点
CPU每次处理的数据量少(通常不超过几个字节),只适于数据传输率较低的设备
直接存储访问方式DMA
由程序设置DMA(Direct Memory Access)控制器中的若干寄存器值(如内存起始地址,传送字节数),然后发起I/O操作,而后者完成内存与外设的成批数据交换,在操作由DMA控制器向CPU发出中断
优点:CPU只需干预I/O操作的开始和结束,而其中一批数据读写无需CPU控制,适于高速设备。
DMA传送操作
通道控制方式
通道控制器有自己专用的存储器,可以执行由通道指令组成的通道程序,因此可以进行较为复杂的I/O控制。
通道程序通常由操作系统构造,放在内存里。
优点:执行一个通道程序可以完成几批I/O操作
- 选择通道:可以连接多个外设,而一次只能访问其中你一个外设
- 多路通道:可以并发访问多个外设。分为字节多路和数组多路通道
I/O软件原理
I/O软件目标
- 设备无关性
- 程序员写出的软件无需修改便能读出软盘、硬盘以及CD-ROM等不同设备上的文件
- 统一的命名
- 一个文件或设备名简单地只是一个字符串或一个整数,而完全不依赖设备
- 容错功能
- 错误应在尽可能接近硬件的地方处理,低层软件可以自行处理错误,尽可能向上层软件透明
- 协同同步和异步传输
- 多数物理I/O是异步传输,用户接口是阻塞的,需要使之协同
- 设备共享
- 某些设备可同时被多个用户使用,另一些设备则在某一时刻只能供一个用户专用
中断处理器
中断需要尽量加以屏蔽,需将其放在操作系统的底层进行处理,以便其余部分尽可能少地与之发生联系。
- 屏蔽中断的最好方法是将每一个进行I/O操作的进程挂起,直至I/O操作结束并发生中断。
- 进程自己阻塞的方法有:执行信号量的DOWN操作、条件变量的WAIT操作或接收一条消息等等。
当中断发生时,中断处理程序执行相应的操作,然后接触相应进程的阻塞状态
- 一些系统中是执行信号量的UP操作,在管程中可能是对一个条件变量执行SIGNAL操作,另一些系统则可能是向阻塞的进程发一条消息,总之其作用是将刚才被阻塞的进程恢复执行。
设备驱动程序
- 设备驱动程序中包括了所有与设备相关的代码,每个设备驱动程序只处理一种设备,或者一类紧密相关的设备
- 设备驱动程序的功能是从与设备无关I/O软件中接受抽象的请求,并负责执行该请求
- 设备驱动程序放在系统内核中,可以获得良好的性能,但会影响系统的可靠性;MINIX3将其作为用户模式的进程,以提高其可靠性。
驱动程序的工作流程
- 执行一条I/O请求的第一步,是将它转换为更具体的形式
- 例如对磁盘驱动程序,它包含:计算出所请求块的物理地址、检查驱动器电机是否在运转,检测磁头臂定位是否在正确的柱面等等。
- 简言之,它必须确定需要哪些控制器命令以及命令的执行次序。
- 一旦决定应向控制器发送什么命令,驱动程序将向控制器的设备寄存器中写入这些命令
- 某些控制器一次只能处理一条命令,另一些则可以接受一串命令并自动进行处理。
- 这些控制命令发出后,存在两种情况
- 驱动程序需等待控制器完成一些操作,所以驱动程序无需阻塞。
例如在有些终端上滚动屏幕内只需往控制器寄存器中写入几个字节,无需任何机械操作,所以整个操作可在几微秒内完成。
设备无关I/O软件
- 设备无关软件的基本功能是执行适用于所有设备的常用I/O功能,并向用户层软件提供一个一致的接口。
设备无关软件和设备驱动程序之间的精确界限在各个系统都不尽相同。对于一些以设备无关方式完成的功能,在实际中由于考虑到执行效率等因素,也可以考虑由驱动程序完成。
- 设备无关I/O软件的功能包括
- 设备驱动程序的统一接口
- 缓冲
- 错误报告
- 分配和释放专用设备
- 提供与设备无关的块大小
设备驱动程序的统一接口
- I/O设备和驱动程序的对外接口需要尽可能的相同
- 在标准接口情况下,可以方便地加入新的驱动程序
- 设备无关I/O软件负责将设备名映射到相应的驱动程序
- 在UNIX中,一个设备名,如/dec/tty00唯一的确定了一个i-节点,其中包含了主设备号,通过主设备号就可以找到相应的设备驱动程序。i-节点也包含了次设备号,它作为传给驱动程序的参数指定具体的物理设备。
- 设备作为命名对象出现在文件系统中,通过对文件的常规保护规则,确保对设备的访问权限
缓冲
对于块设备,硬件每次读写均以块为单元,而用户程序则可以读写任意大小单元。如果用户进程写半个块,操作系统将在内部保留这些数据,直到其余数据到齐后才一次性地将这些数据写到盘上。
对字符设备,用户向系统写数据的速度可能比向设备输出的速度快,所以需要进行缓冲。超前的键盘输入同样也需要缓冲。
错误报告
错误处理多数由驱动程序完成,多数错误是与设备紧密相关的,因此只有驱动程序知道应如何处理(如重试、忽略、严重错误)。
一种典型错误是磁盘块受损导致不能读写。驱动程序在尝试若干次读操作不成功后将放弃,并向设备无关软件报错,从此处往后错误处理就与设备无关了。
- 如果在读一个用户文件时出错,则向调用者报错即可。
- 如果实在读一些关键系统数据结构时出错,比如磁盘使用状况位图,则操作系统只能打印出错信息,并终止运行。
分配和释放专用设备
一些设备,如CD-ROM记录器,在同一时刻只能由一个进程使用。
这要求操作系统检查对该设备的使用请求,并根据设备的忙闲状况来决定是接受或拒绝此请求。
- 一种简单的处理方法是通过直接用OPEN打开相应的设备文件来进行申请。若设备不可用,则OPEN失败,关闭独占设备的同时释放该设备。
提供与设备无关的块大小
不同磁盘的扇区大小可能不同,设备无关软件屏蔽了这一事实,并向高层软件提供统一的数据块大小
- 如将若干扇区作为一个逻辑块,这样上层软件只和逻辑块大小相同的抽象设备交互,而不管物理扇区的大小。
- 如有些字符设备对字节进行操作,另一些则使用比字节大一些的单元(网卡)。这类差别也可以进行屏蔽。
用户层I/O软件
- I/O相关的库例程
- 假脱机系统
- Spooling是在多道程序系统中处理专用I/O设备的一种方法
- 创建一个特殊的守护进程daemon以及一个特殊的目录,称为Spooling目录
- 打印一个文件之前,进程首先产生完整的待打印文件并将其放在Spooling目录下
- 由该守护进程进行打印,只有该守护进程能够使用打印机设备文件
I/O系统的层次结构及功能
死锁
死锁是指系统中多个进程无限制地等待永远不会发生的条件
实例
过桥问题
- 单向流通
- 桥的每一个部分可以看为一个源头
- 如果死锁发生,只要一边的车倒退就可以解决
- 可能要好几部车都要倒退
- 可能会发生饥饿现象
交通格锁 / 死锁
资源
进程对设备、文件等获得独占性的访问权时有可能会发生死锁,为了尽可能地通用化,将这种需排他使用的对象称为资源。
- 可剥夺式资源
其他进程可从拥有它的进程处剥夺而没有任何副作用,存储器就是一类可剥夺资源
- 不可剥夺资源
无法在不导致相关计算失败的情况下将其从属主进程处剥夺,如打印机
死锁原理
有资源R1,R2,…,Rm,每个资源有Wi实例,每个进程使用资源的过程为请求→使用→释放。
死锁就是一个单元里每个进程的运行都需要等待另一个进程完成,从而导致没有一个进程运行。
死锁的必要条件
- 互斥
任一时刻只允许一个进程使用资源
- 请求和保持
进程在请求其余资源时,不主动释放已经占用的资源
- 非剥夺
进程已经占用的资源不会被强制剥夺
- 环路等待
环路中的每一条边是进程在请求另一进程已经占有的资源
死锁资源分配图
- V:顶点集合 E:边集合
- V被分割成两部分
- 请求边是Pi到Rj的有向边
- 指派边是Rj到Pi的有向边
资源分配图实例
发生死锁的资源分配图
P1请求R1 R1分配给P2 P2请求R3 R3被分配给P3 P3请求R2 但R2被分配给P1和P3 发生环路等待,因此有死锁
没有发生死锁的资源分配图
P1请求R1 R1被分配给P2和P3 P3请求R2 P2被分配给P1和P4 此时P4会运行
发生死锁的基本规律
- 如果图中没有回路,肯定没有死锁
- 如果图中有回路
- 如果一个资源被分配给一个实例,那么会发生回路
- 如果一个资源被分配给几个实例,那么可能发生回路
解决回路的方法
- 确保系统永远都不会进入死锁状态
- 允许系统进入死锁状态之后恢复
- 忽略死锁问题,假装什么都没有发生
鸵鸟算法
对死锁视而不见
死锁检测与恢复
检测
保存资源的请求和分配信息,利用某种算法对这些信息加以检查,以判断是否存在死锁。
主要检查是否有循环等待。
恢复
- 通过撤销代价最小的进程以解除死锁
- 挂起某些死锁进程并抢占它的资源以解除死锁
撤销原则
死锁预防
对进程施加适当的限制以从根本上消除死锁
条件 |
方法 |
互斥 |
对所有资源进行spooling |
保持并等待 |
初始时申请所有资源 |
不可剥夺 |
将资源剥夺 |
循环等待 |
对资源进行编号 |
全局编号
所有资源赋予一个全局编号,进程申请资源必须按照编号顺序
改进:不允许进程申请编号比当前所占有资源编号低的资源
避免死锁
单种资源的银行家算法
基本思想:一个小镇的银行家(操作系统)向一群客户(进程)分别承诺了一定的贷款额度(设备),考虑所有客户不会同时申请最大额度贷款,他只保留较少单位的资金来为客户服务
算法:
- 对每个请求进行检查,检查如果满足它是否会导致不安全状态。若是,则不满足该请求;否则便满足。
- 检查状态是否安全的方法是看他是否有足够的资源满足某一客户。如果可以,则这笔投资认为是能够收回的,然后检查最接近最大限度的客户,如此反复。若所有投资最终都被收回,则该状态时是安全的,最初的请求可以批准。
(a)有足够资源满足任一客户
(b)最接近最大限度的客户是C,现在有资源2,C还需2,则可以满足
(c)最接近最大限度的客户是C,但现在只有1,则不可满足
资源轨迹图
- 处理两个进程和两种资源
- 横轴表示进程A的指令执行过程,纵轴表示进程B的指令执行过程
进程A在I1处请求一台打印机,在I3处释放,在I2处申请一台绘图仪,在I4处释放。
进程B在I5-I7间需要绘图仪,I6-I8间需要打印机。
如果系统一旦进入由I1、I2和I5、I6组成的矩形区域,那么最后一定会到达I2和I6的交叉点,此时会发生死锁
在t处唯一的办法是运行进程A直到I4,过了I4后可以按任意路线前进
多种资源的银行家算法
两个矩阵
- 左边的显示出对5个进程分别已分配的各种资源数
- 右边的则显示了使各进程运行完所需的各种资源数
三个向量
- 总的资源E
- 已分配资源P
- 剩余资源A
检查一个状态是否安全
- 查找右边矩阵中是否有一行,其未被满足设备数均小于等于向量A。若找不到则死锁。
- 若找到这一行,则可以假设它获得所需资源并运行结束,将该进程标记为结束,并将资源加到向量A上。
- 重复以上两部,直到所有进程都标记为结束。若能够达到所有进程结束,则状态是安全的,否则发生死锁。
- 如果第一步中同时存在若干进程均符合条件,则不管挑哪个都可以。
二阶段加锁法
- 第一阶段,进程试图将其所需的全部记录加锁,一次锁一个记录
- 若成功,则开始第二阶段,完成更新数据并释放锁
- 若有些记录已被上锁,则它将以上所的记录解锁并重新开始第一阶段
MINIX3 I/O概述
MINIX3 I/O 结构
从上到下
用户请求一个I/O操作
- 用户进程:进行I/O引用,Spooling
- 设备无关软件:命名、保护、阻塞、缓存、开辟
- 设备驱动:设置设备寄存器;检查状态
- 中断处理器:当I/O操作完成时唤醒驱动
- 硬件:进行I/O操作
再从下到上返回