OS_I/O系统的层次结构&中断
I/O系统总览
I/O系统的层次结构
I/O系统中各个模块之间的层次
-
用户层软件 -
I/O系统接口
-
设备独立性(无关性)软件 -
设备驱动程序 -
中断处理程序 -
RW/HW接口
-
设备控制器
在上、下两个接口之间则是I/O系统
I/O系统的上、下接口
(1)I/O系统接口
-
它是I/O系统与上层系统之间的接口,向上层提供对设备进行操作的抽象I/O命令,以方便高层对设备的使用。 -
有不少OS在用户层提供了与I/O操作有关的库函数,供用户使用。 -
在上层系统中有文件系统、虚拟存储器系统以及用户进程等。 -
包括:
(2)软件/硬件(RW/HW)接口
I/O系统的分层
I/O设备和设备控制器
- I/O设备一般是由执行I/O操作的机械部分和执行控制I/O的电子部件组成。
- 通常将这两部分分开,
- 执行I/O操作的机械部分就是一般的I/O设备,
- 而执行控制I/O的电子部件则称为设备控制器或适配器(adapter)
- 在微型机和小型机中的控制器常做成印刷电路卡形式,因而也常称为控制卡、接口卡或网卡,可将它插入计算机的扩展槽中。
- 在有的大、中型计算机系统中,还配置了I/O通道或I/O处理机。
设备与控制器之间的接口
- 通常,设备并不是直接与CPU进行通信而是与设备控制器通信,
- 因此,在I/O设备中应含有与设备控制器间的接口,
数据信号线
- 用于在设备和设备控制器之间传送数据信号。
- 对输入设备而言,由外界输入的信号经转换器转换后,所形成的数据通常先送入缓冲器中,当数据量达到一定的比特(字符)数后,再从缓冲器通过一组数据信号线传送给设备控制器
- 对输出设备而言,则是将从设备控制器经过数据信号线传送来的一批数据先暂存于缓冲器中,经转换器作适当转换后,再逐个字符地输出。
控制信号线
- 这是作为由设备控制器向I/O设备发送控制信号时的通路。
- 该信号规定了设备将要执行的操作,如读操作(指由设备向控制器传送数据)或写操作(从控制器接收数据),或执行磁头移动等操作。
状态信号线
- 该信号线用于传送指示设备当前状态的信号。
- 设备的当前状态有正在读(或写);设备已读(写)完成,并准备好新的数据传送。
设备控制器
- 设备控制器设备控制器的主要功能是,控制一个或多个I/O设备,以实现I/O设备和计算机之间的数据交换。
- 它是CPU与I/O设备之间的接口,接收从CPU发来的命令,去控制I/O设备工作,使处理机能够从繁杂的设备控制事务中解脱出来。
- 设备控制器是一个可编址的设备,当它仅控制一个设备时,它只有一个唯一的设备地址;
- 若控制器可连接多个设备,则应含有多个设备地址,每一个设备地址对应一个设备。
- 可把设备控制器分成两类:一类是用于控制字符设备的控制器,另一类是用于控制块设备的控制器。
设备控制器的组成
由于设备控制器位于CPU与设备之间,它既要与CPU通信,又要与设备通信,还应具有按照CPU所发来的命令去控制设备工作的功能,因此,现有的大多数控制器都是由以下三部分组成:
设备控制器与处理机的接口。
- 该接口用于实现CPU与设备控制器之间的通信,在该接口中共有三类信号线:
- 数据线、地址线和控制线。
- 数据线通常与两类寄存器相连接:
- 第一类是数据寄存器,在控制器中可以有一个或多个数据寄存器,用于存放从设备送来的数据(输入),或从CPU送来的数据(输出)。
- 第二类是控制/状态寄存器,在控制器中可以有一个或多个这类寄存器,用于存放从CPU送来的控制信息或设备的状态信息。
IO逻辑
- IO逻辑用于实现对设备的控制。
- 它通过一组控制线与处理机交互,处理机利用该逻辑向控制器发送IO命令。
- 每当CPU要启动一个设备时,一方面将启动命令发送给控制器,另一方面又同时通过地址线把地址发送给控制器,由控制器的I/O逻辑对收到的地址译码,再根据所译出的命令对所选设备进行控制。
设备控制器与设备的接口
- 在一个设备控制器上,可以连接一个或多个设备。
- 相应的,在控制器中便有一个或多个设备接口。
- 在每个接口中都存在数据、控制和状态三种类型的信号。
- 控制器中的IO逻辑根据处理机发来的地址信号去选择一个设备接口。
设备控制器的基本功能
- (1)接收和识别命令。
- 设备控制器能接收并识别处理机发来的多种命令。
- 在控制器中具有相应的控制寄存器,用来存放接收的命令和参数,并对所接收的命令进行译码。
- 例如,磁盘控制器可以接收CPU发来的read、write,format等15条不同的命令,而且有些命令还带有参数。相应地,在磁盘控制器中有多个寄存器和命令译码器等。
- (2)数据交换。
- 设备控制器可实现CPU与控制器之间、控制器与设备之间的数据交换。
- 对于前者,是通过数据总线,由CPU并行地把数据写入控制器,或从控制器中并行地读出数据。
- 对于后者,是设备将数据输入到控制器,或从控制器传送给设备。
- 为此,在控制器中须设置数据寄存器。
- (3)标识和报告设备的状态。
- 控制器应记下设备的状态供CPU了解。
- 例如,仅当该设备处于发送就绪状态时,CPU才能启动控制器从设备中读出数据。
- 为此,在控制器中应设置一状态寄存器,用其中的每一位反映设备的某一种状态。
- 当CPU将该寄存器的内容读入后,便可了解该设备的状态。
- (4)地址识别。
- 就像内存中的每一个单元都有一个地址一样,系统中的每一个设备也都有一个地址。设备控制器必须能够识别其所控制的每个设备的地址。
- 此外,为使CPU能向(或从)寄存器中写入(或读出)数据,这些寄存器都应具有唯一的地址。控制器应能正确识别这些地址。
- 为此,在控制器中应配置地址译码器。
- (5)数据缓冲区。
- 由于I/O设备的速率较低,而CPU和内存的速率却很高,故在控制器中必须设置一缓冲区。
- 在输出时,用此缓冲区暂存由主机高速传来的数据,然后才以与I/O设备所匹配的速率将缓冲器中的数据传送给I/O设备。
- 在输入时,缓冲区则用于暂存从I/O设备送来的数据,待接收到一批数据后,再将缓冲区中的数据高速地传送给主机。
- (6)差错控制。
- 对于由I/O设备传送来的数据,设备控制器还兼管进行差错检测。若发现传送中出现了错误,通常是将差错检测码置位,并向CPU报告,于是CPU将本次传送来的数据作废, =并重新进行一次传送。这样便可保证数据输入的正确性。
中断&陷入
中断(外中断)
- 中断是指CPU对IO设备发来的中断信号的一种响应。
- CPU暂停正在执行的程序,保留CPU环境后,自动地转去执行该IO设备的中断处理程序。
- 执行完后,再回到断点,继续执行原来的程序。
- IO设备可以是字符设备,也可以是块设备、通信设备等。
- 由于中断是由外部设备引起的,故又称外中断。
陷入(内中断)
- 另外还有一种由CPU内部事件所引起的中断,例如进程在运算中发生了上溢或下溢,又如程序出错,如非法指令、地址越界,以及电源故障等。
- 通常把这类中断称为内中断或陷入(trap)。
- 与中断一样,若系统发现了有陷入事件,CPU也将暂停正在执行的程序,转去执行该陷入事件的处理程序。
中断和陷入的主要区别是信号的来源,即是来自CPU外部,还是CPU内部。
中断向量表和中断优先级
中断向量表&中断号
- 为了处理上的方便,通常是为每种设备配以相应的中断处理程序,并把该程序的入口地址放在中断向量表的一个表项中,并为每一个设备的中断请求规定一个中断号,它直接对应于中断向量表的一个表项中。
- 当IO设备发来中断请求信号时,由中断控制器确定该请求的中断号,根据该设备的中断号去查找中断向量表,从中取得该设备中断处理程序的入口地址,这样便可以转入中断处理程序执行。
中断优先级
- 然而实际情况是:经常会有多个中断信号源,每个中断源对服务要求的紧急程度并不相同,
- 例如,键盘终端的中断请求的紧急程度不如打印机,而打印机中断请求的紧急程度又不如磁盘等。
- 为此,系统就需要为它们分别规定不同的优先级。
对多中断源的处理方式
- 对于多中断信号源的情况,当处理机正在处理一个中断时,又来了一个新的中断请求,这时应如何处理。
- 例如,当系统正在处理打印机中断时,又收到了优先级更高的磁盘中断信号。
- 对于这种情况,可有两种处理方式:
1)屏蔽(禁止)中断
-
当处理机正在处理一个中断时,将屏蔽掉所有的中断,即处理机对任何新到的中断请求,都暂时不予理睬,而让它们等待。 -
直到处理机已完成本次中断的处理后,处理机再去检查是否有中断发生。 -
若有,再去处理新到的中断,若无,则返回被中断的程序。 -
在该方法中,所有中断都将按顺序依次处理。 -
其优点是简单,但不能用于对实时性要求较高的中断请求。
2)嵌套中断
- 在设置了中断优先级的系统中,通常按这样的规则来进行优先级控制;
- (1)当同时有多个不同优先级的中断请求时,CPU优先响应最高优先级的中断请求;
- (2)高优先级的中断请求可以抢占正在运行的低优先级中断的处理机,该方式类似于基于优先级的抢占式进程调度。
- 例如,处理机正在处理打印机中断,当有磁盘中断到来时,可暂停对打印机中断的处理,转去处理磁盘中断。
- 如果新到的是键盘中断,由于它的优先级低于打印机的优先级,故处理机继续处理打印机中断。
中断处理程序
- 当一个进程请求I/O操作时,该进程将被挂起,直到I/O设备完成I/O操作后,设备控制器便向CPU发送一个中断请求,CPU响应后便转向中断处理程序,中断处理程序执行相应的处理,处理完后解除相应进程的阻塞状态。
- 中断处理程序的处理过程可分成以下几个步骤:
- (1)测定是否有未响应的中断信号。
- 每当设备完成一个字符(字或数据块)的读入(或输出),设备控制器便向处理机发送一个中断请求信号。
- 请求处理机将设备已读入的数据传送到内存的缓冲区中(读入),或者请求处理机将要输出的数据(输出)传送给设备控制器。
- 程序每当执行完当前指令后,处理机都要测试是否有未响应的中断信号。
- 若没有,继续执行下一条指令。
- 若有,则停止原有进程的执行,准备转去执行中断处理程序,为把处理机的控制权转交给中断处理程序做准备。
- (2)保护被中断进程的CPU环境。
- 在把控制权转交给中断处理程序之前,需要先保护被中断进程的CPU环境,以便以后能恢复运行。
- 首先需要保存的是,从中断现场恢复到当前进程运行所需要的信息。
- 通常由硬件自动将处理机状态字(PSW)和保存在程序计数器(PC)中下一条指令的地址保存在中断保留区(栈)中。
- 然后,把被中断进程的CPU现场信息,即将包括所有CPU寄存器的(如通用寄存器、段寄存器等)内容都压入中断栈中。
- 因为在中断处理时可能会用到这些寄存器。
- 下图:该程序是指令在N位置时被中断的,程序计数器中的内容为N+1,所有寄存器的内容都被保留在栈中。
- (3)转入相应的设备处理程序。
- 由处理机对各个中断源进行测试,以确定引起本次中断的I/O设备,并向提供中断信号的设备发送确认信号。
- 在该设备收到确认信号后,就立即取消它所发出的中断请求信号。
- 然后,将相应的设备中断处理程序的入口地址装入到程序计数器中。
- 这样,当处理机运行时,便可自动地转向中断处理程序。
- (4)中断处理。
- 对不同的设备,有不同的中断处理程序。
- 该程序首先从设备控制器中读出设备状态,以判别本次中断是正常完成中断还是异常结束中断。
- 若是前者,中断程序便做结束处理。
- 假如这次是字符设备的读操作,则来自输入设备的中断是表明该设备已经读入了一个字符(字)的数据,并已放入数据寄存器中。
- 此时中断处理应将该数据传送给CPU,再将它存入缓冲区中,并修改相应的缓冲区指针,使其指向下一个内存单元。若还有命令,可再向控制器发送新的命令,进行新一轮的数据传送。
- 若是异常结束中断,则根据发生异常的原因做相应的处理。
- (5)恢复CPU的现场并退出中断。
- 当中断处理完成以后,需要恢复CPU的现场,退出中断。
- 但是,此刻是否返会到被中断的进程,取决于两个因素:
- ①本中断是否采用了屏蔽(禁止)中断方式,若是,就会返回被中断的进程。
- ②采用的是中断嵌套方式,
- 如果没有优先级更高的中断请求IO,在中断完成后,仍会返回被中断的进程;
- 反之,系统将处理优先级更高的中断请求。
- 如果是要返回到被中断的进程,可将保存在中断栈中的被中断进程的现场信息取出,并装入到相应的寄存器中,其中包括该程序下一次要执行的指令的地址N+1、处理机状态字PSW,以及各通用寄存器和段寄存器的内容。
- 这样,当处理机再执行本程序时,便从N+1处开始,最终返回到被中断的程序。
程序中断
程序中断方式中断是现代计算机有效合理地发挥效能和提高效率的一个十分重要的功能。
- CPU中通常设有处理中断的机构——中断系统,以解决各种中断的共性问题。
中断的基本概念
- 程序中断是指在计算机执行现行程序的过程中,出现某些急需处理的异常情况或特殊请求,CPU暂时中止现行程序,而转去对这些异常情况或特殊请求进行处理,在处理完毕后CPU又自动返回到现行程序的断点处,继续执行原程序。
程序中断的作用如下:
程序中断方式的思想:
- CPU在程序中安排好于某个时刻启动某台外设,然后CPU继续执行原来的程序,不需要像查询方式那样一直等待外设准备就绪。
- 一旦外设完成数据传送的准备工作,就主动向CPU发出中断请求,请求CPU为自己服务。
- 在可以响应中断的条件下,CPU暂时中止正在执行的程序,转去执行中断服务程序为外设服务,在中断服务程序中完成一次主机与外设之间的数据传送**,传送完成后,CPU返回原来的程序
程序中断方式工作流程
(1)中断请求中断请求是指中断源向CPU发送中断请求信号。
-
①内中断和外中断中断源是请求CPU中断的设备或事件,一台计算机允许有多个中断源。 -
根据中断源的类别,可把中断源分为内中断和外中断两种。
- 每个中断源向CPU发出中断请求的时间是随机的。
- 为记录中断事件并区分不同的中断源,中断系统需对每个中断源设置中断请求标记触发器INTR,当其状态为“1”时,表示中断源有请求。
- 这些触发器可组成中断请求标记寄存器,该寄存器可集中在CPU中,也可分散在各个中断源中。
- 外中断是指来自处理器和内存以外的部件引起的中断,包括I/O设备发出的I/O中断、外部信号中断(如用户按Esc键),以及各种定时器引起的时钟中断等。
- 外中断在狭义上一般称为中断(后文若未说明,一般是指外中断)。
- 硬件中断属于外中断。
- 内中断主要是指在处理器和内存内部产生的中断,包括程序运算引起的各种错误,如地址非法、校验错、页面失效、存取访问控制错、算术操作溢出、数据格式非法、除数为零、非法指令、用户程序执行特权指令、分时系统中的时间片中断及用户态到核心态的切换等。
-
②硬件中断和软件中断硬件中断:通过外部的硬件产生的中断。
- 软件中断:通过某条指令产生的中断,这种中断是可以编程实现的。
- 软件中断是内中断。
-
③非屏蔽中断和可屏蔽中断
- 非屏蔽中断:非屏蔽中断是一种硬件中断,此种中断通过不可屏蔽中断请求NMI控制,不受中断标志位IF的影响,即使在关中断(IF=0)的情况下也会被响应。
- 可屏蔽中断:可屏蔽中断也是一种硬件中断,此种中断通过中断请求标记触发器INTR控制,且受中断标志位IF的影响,在关中断情况下不接受中断请求。
- 也就是说,可屏蔽中断和非屏蔽中断均是外中断。
(2)中断判优
(3)CPU响应中断的条件
- CPU在满足一定的条件下响应中断源发出的中断请求,并经过一些特定的操作,转去执行中断服务程序。
- CPU响应中断必须满足以下3个条件:
- ①中断源有中断请求。
- ②CPU允许中断及开中断。
- ③一条*指令执行完毕,且没有更紧迫的任务*。
- 注意:I/O设备的就绪时间是随机的,而CPU在统一的时刻即每条指令执行阶段结束前向接口发出中断查询信号,以获取I/O的中断请求,
- 也就是说,CPU响应中断的时间是在每条指令执行阶段的结束时刻。
- 这里说的中断仅指外中断,内中断不属于此类情况。
(4)中断隐指令
- CPU响应中断后,经过某些操作,转去执行中断服务程序。
- 这些操作是由硬件直接实现的,我们将它称为中断隐指令。
- 中断隐指令并不是指令系统中的一条真正的指令,它没有操作码,所以中断隐指令是一种不允许也不可能为用户使用的特殊指令。它所完成的操作如下:
- ①关中断。
- 在中断服务程序中,为了保护中断现场(即CPU主要寄存器中的内容)期间不被新的中断所打断,必须关中断,从而保证被中断的程序在中断服务程序执行完毕后能接着正确地执行。
- ②保存断点。
- 为保证在中断服务程序执行完毕后能正确地返回到原来的程序,必须将原来程序的断点[即程序计数器(PC)的内容]保存起来。
- ③引出中断服务程序。
- 引出中断服务程序的实质是,取出中断服务程序的入口地址并传送给程序计数器(PC)
(5)中断向量
- 不同的设备有不同的中断服务程序,每个中断服务程序都有一个入口地址,CPU必须找到这个入口地址,即中断向量
- 把系统中的全部中断向量集中存放到存储器的某个区域内,这个存放中断向量的存储区就称为中断向量表,即中断服务程序入口地址表。
- CPU响应中断后,中断硬件会自动将中断向量地址传送到CPU,由CPU实现程序的切换,这种方法称为中断向量法,
- 采用中断向量法的中断称为向量中断。
- 注意:
- 中断向量是中断服务程序的入口地址,
- 中断向量地址是指中断服务程序的入口地址的地址。
(6)中断处理过程
- 不同计算机的中断处理过程各具特色,就其多数而论
- ①关中断。
- 处理器响应中断后,首先要保护程序的现场状态,在保护现场的过程中,CPU不应响应更高级中断源的中断请求。
- 否则,若现场保存不完整,在中断服务程序结束后,也就不能正确地恢复并继续执行现行程序。
- ②保存断点。
- 为保证中断服务程序执行完毕后能正确地返回到原来的程序,必须将原来的程序的断点保存起来。
- 断点可以压入堆栈,也可以存入主存的特定单元中。
- ③引出中断服务程序。
- 引出中断服务程序的实质是,取出中断服务程序的入口地址送入程序计数器(PC)。
- 通常有两种方法寻址中断服务程序的入口地址:
- 硬件向量法和软件查询法。
- 硬件向量法通过硬件产生中断向量地址,再由中断向量地址找到中断服务程序的入口地址。
- 软件查询法用软件编程的办法寻找入口地址。
- 注意:硬件产生的实际上是中断类型号,而中断类型号指出了中断向量存放的地址,因此能产生中断向量地址。
- ④保存现场和屏蔽字。
- 进入中断服务程序后首先要保存现场,现场信息一般是指
- 程序状态字、
- 中断屏蔽寄存器和
- CPU中某些寄存器的内容。
- ⑤开中断。允许更高级中断请求得到响应,实现中断嵌套。
- ⑥执行中断服务程序。这是中断请求的目的。
- ⑦关中断。保证在恢复现场和屏蔽字时不被中断。
- ⑧恢复现场和屏蔽字。将现场和屏蔽字恢复到原来的状态。
- ⑨开中断、中断返回。
- 中断服务程序的最后一条指令通常是一条中断返回指令,使其返回到原程序的断点处,以便继续执行原程序。
- 其中,
- ①?③在CPU进入中断周期后,由中断隐指令(硬件自动)完成;
- ④?⑨由中断服务程序完成。
- 注意:
- 恢复现场是指在中断返回前,必须将寄存器的内容恢复到中断处理前的状态,这部分工作由中断服务程序完成。
- 中断返回由中断服务程序的最后一条中断返回指令完成。
设备驱动程序
- 设备处理程序通常又称为设备驱动程序,它是I/O系统的高层与设备控制器之间的通信程序,其主要任务是接收上层软件发来的抽象I/O要求,
- 如read或write命令,再把它转换为具体要求后,发送给设备控制器,启动设备去执行:
- 反之,它也将由设备控制器发来的信号传送给上层软件。
- 由于驱动程序与硬件密切相关,故通常应为每一类设备配置一种驱动程序。
设备驱动程序的功能
- 为了实现I/O系统的高层与设备控制器之间的通信,设备驱动程序应具有以下功能:
- (I)接收由与设备无关的软件发来的命令和参数,并将命令中的抽象要求转换为与设备相关的低层操作序列。
- (2)检查用户I/O请求的合法性,了解I/O设备的工作状态,传递与I/O设备操作有关的参数,设置设备的工作方式。
- (3)发出I/O命令,
- 如果设备空闲,便立即启动I/O设备,完成指定的I/O操作;
- 如果设备忙碌,则将请求者的请求块挂在设备队列上等待
- (4)及时响应由设备控制器发来的中断请求,并根据其中断类型,调用相应的中断处理程序进行处理。
设备驱动程序的特点
- 设备驱动程序属于低级的系统例程,它与一般的应用程序及系统程序之间有下述明显差异:
- (1)驱动程序是实现在与设备无关的软件和设备控制器之间通信和转换的程序,具体说,
- 它将抽象的I/O请求转换成具体的I/O操作后传送给控制器。
- 又把控制器中所记录的设备状态和I/O操作完成情况,及时地反映给请求I/O的进程。
- (2)驱动程序与设备控制器以及I/O设备的硬件特性紧密相关,对于不同类型的设备,应配置不同的驱动程序。但可以为相同的多个终端设置一个终端驱动程序。
- (3)驱动程序与I/O设备所采用的I/O控制方式紧密相关,常用的I/O控制方式是中断驱动和DMA方式。
- (4)由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言书写。目前有很多驱动程序的基本部分已经固化在ROM中。
- (5)驱动程序应允许可重入。一个正在运行的驱动程序常会在一次调用完成前被再次调用。
设备处理方式
在不同的操作系统中,所采用的设备处理方式并不完全相同。根据在设备处理时是否设置进程,以及设置什么样的进程,而把设备处理方式分成以下三类:
- (1)为每一类设备设置一个进程,专门用于执行这类设备的I/O操作。
- 比如,为所有的交互式终端设置一个交互式终端进程;
- 又如,为同一类型的打印机设置一个打印进程。这种方式比较适合于较大的系统。
- (2)在整个系统中设置一个I/O进程,专门用于执行系统中所有各类设备的I/O操作。也可以设置一个输入进程和一个输出进程,分别处理系统中的输入或输出操作。
- (3)不设置专门的设备处理进程,而只为各类设备设置相应的设备驱动程序,供用户或系统进程调用。
设备驱动程序的处理过程
- 设备驱动程序的主要任务是启动指定设备,完成上层指定的I/O工作。
- 但在启动之前,应先完成必要的准备工作,如检测设备状态是否为“忙”等。
- 在完成所有的准备工作后,才向设备控制器发送一条启动命令。
- 以下是设备驱动程序的处理过程:
- (1)将抽象要求转换为具体要求。
- 通常在每个设备控制器中都含有若干个寄存器,分别用于暂存命令、参数和数据等。
- 由于用户及上层软件对设备控制器的具体情况毫无了解,因而只能发出命令(抽象的要求),这些命令是无法传送给设备控制器的。
- 因此,就需要将这些抽象要求转换为具体要求。
- 例如,将抽象要求中的盘块号转换为磁盘的盘面、磁道号及扇区。
- 而这一转换工作只能由驱动程序来完成,因为在OS中只有驱动程序才同时了解抽象要求和设备控制器中的寄存器情况,也只有它才知道命令、数据和参数应分别送往哪个寄存器。
- (2)对服务请求进行校验。
- 驱动程序在启动I/O设备之前,必须先检查该用户的I/O请求是不是该设备能够执行的。
- 一个非法请求的典型例子是,用户试图请求从一台打印机读入数据。
- 如果驱动程序能检查出这类错误便认为这次I/O请求非法,它将向I/O系统报告I/O请求出错。
- I/O系统可以根据具体情况做出不同的决定。
- 如可以停止请求进程的运行,或者仅通知请求进程它的I/O请求有错,但仍然让它继续运行。
- 此外,还有些设备如磁盘和终端,它们虽然都是既可读、又可写的,但若在打开这些设备时规定的是读,则用户的写请求必然被拒绝。
- (3)检查设备的状态。
- 启动某个设备进行I/O操作,其前提条件应是该设备正处于就绪状态。
- 为此,在每个设备控制器中,都配置有一个状态寄存器。
- 驱动程序在启动设备之前,要先把状态寄存器中的内容读入到CPU的某个寄存器中,通过测试寄存器中的不同位,来了解设备的状态,
- 例如,为了向某设备写入数据,此前应先检查状态寄存器中接收就绪的状态位,看它是否处于接收就绪状态。
- 仅当它处于接收就绪状态时,才能启动其设备控制器,否则只能等待。
- (4)传送必要的参数。
- 在确定设备处于接收(发送)就绪状态后,便可向控制器的相应寄存器传送数据及与控制本次数据传输有关的参数。
- 例如,在某种设备控制器中配置了两个控制寄存器,
- 其中一个是命令寄存器,用于存放处理机发来的各种控制命令,以决定本次I/O操作是接收数据还是发送数据等。
- 另一个是方式寄存器,它用于控制本次传送数据的速率、发送的字符长度等。
- 如果是利用RS232C接口进行异步通信,在启动该接口之前,应先按通信规程设定下述参数:波特率、奇偶校验方式、停止位数目及数据字节长度等。
- 对于较为复杂的块设备,除必须向其控制器发出启动命令外,还需传送更多的参数。
- (5)启动I/O设备。
- 在完成上述各项准备工作后,驱动程序便可以向控制器中的命令寄存器传送相应的控制命令。
- 对于字符设备,若发出的是写命令,驱动程序便把一个字符(或字),传送给控制器:
- 若发出的是读命令,则驱动程序等待接收数据,并通过读入控制器的状态寄存器中状态字的方法来确定数据是否到达。
- 在多道程序系统中,驱动程序一旦发出IO命令,启动了一个I/O操作后,驱动程序便把控制返回给I/O系统,把自己阻塞起来,直到中断到来时再被唤醒。
- 具体的I/O操作是在设备控制器的控制下进行的,
- 因此,在设备忙于传送数据时,处理机又可以去干其它的事情,实现了处理机与I/O设备的并行操作。
与设备无关的IO软件
- 为了方便用户和提高OS的可适应性与可扩展性,在现代OS的I/O系统中,都无一例外地增加了与设备无关的I/O软件,以实现设备独立性,也称为设备无关性。
- 其基本含义是:应用程序中所用的设备,不局限于使用某个具体的物理设备。
- 为每个设备所配置的设备驱动程序是与硬件紧密相关的软件。
- 为了实现设备独立性,必须再在设备驱动程序之上设置一层软件,称为与设备无关的I/O软件,或设备独立性软件。
与设备无关(DeviceIndependence)软件的基本概念
以物理设备名使用设备
-
在早期OS中,应用程序在使用I/O设备时,都使用设备的物理名称,这使应用程序与系统中的物理设备直接相关。 -
当应用进程运行时,如果所请求的物理设备(独占设备类型)己分配给其它进程,而此时尽管还有几台其它的相同设备空闲可用,但系统只能根据设备的物理名来分配,无法将另外相同的设备(但具有不同的物理设备名)分配给它,致使该应用进程请求I/O失败而被阻塞。 -
特别是,当应用程序所需要的设备在系统中已经被更新时,该应用程序将再也无法在该系统上运行。 -
可见,应用程序直接与物理设备相关是非常不灵活的,给用户带来了很大的不便,且对提高I/O设备的利用率也很不利。
2.引入了逻辑设备名
- 为了实现与设备的无关性而引入了逻辑设备和物理设备两个概念。
- 逻辑设备是抽象的设备名。
- 如/dev/printer,该设备名只是说明用户需要使用打印机来打印输出,但并没有指定具体是哪一台打印机。
- 这样,如果在应用程序中,使用逻辑设备名称请求使用某类设备,系统在对它进行设备分配时,先查找该类设备中的第一台,如它已被分配,系统可立即去查找该类设备中第二台,若又被分配,系统接着去找第三台,若它尚未分配,便可将这台设备分配给进程。
- 事实上,只要系统中有一台该类设备未被分配,进程就不会被阻塞。
- 仅当所请求的此类设备己全部分配完毕时,进程才会因请求失败而阻塞。
- 所以,应用进程就不会由于某台指定设备退役而无法在本系统上运行。
- 与设备的无关软件还可实现I/O重定向。
- 所谓I/O重定向,是指用于I/O操作的设备可以更换(即重定向),而不必改变应用程序。
- 例如,我们在调试一个应用程序时,可将程序的所有输出送往屏幕显示。
- 而在程序调试完后,若须正式将程序的运行结果打印出来,此时便须将I/O重定向的数据结构——逻辑设备表中的显示终端改为打印机即可,而不必修改应用程序。
- I/O重定向功能具有很大的实用价值,现已被广泛地引入到各类OS中。
3.逻辑设备名称到物理设备名称的转换
- 在应用程序中,用逻辑设备名称使用设备虽然方便了用户,但系统却只识别物理设备名称,因此在实际执行时,还必须使用物理名称。
- 为此,在系统中,必须具有将逻辑设备名称转换为某物理设备名称的功能。
- 关于逻辑设备名称和物理设备名称的概念,与存储器管理中所介绍的逻辑地址和物理地址的概念非常类似,在应用程序中所使用的是逻辑地址,而系统在分配和使用内存时,必须使用物理地址。
- 在程序执行时,必须先将逻辑地址转换为物理地址。
- 类似地,为实现从逻辑设备名称和物理设备名称,在系统中需要配置一张逻辑设备表。
与设备无关的软件
- 与设备无关的软件是I/O系统的最高层软件,在它下面的是设备驱动程序,其间的界限,因操作系统和设备的不同而有所差异。
- 比如,对于一些本应由设备独立性软件实现的功能,却放在设备驱动程序中实现。这样的差异主要是出于对操作系统、设备独立性和设备驱动程序运行效率等多方面因素的权衡和考虑。
- 总的来说,在与设备无关的软件中,包括了执行所有设备公有操作的软件,具体有如下几项。
- 1.设备驱动程序的统一接口
- 为了使所有的设备驱动程序有着统一的接口,一方面,要求每个设备驱动程序与OS之间都有着相同的接口,或者相近的接口,这样会使添加一个新的设备驱动程序变得很容易,同时在很大程度上方便了开发人员对设备驱动程序的编制。
- 另一方面,要将抽象的设备名映射到适当的驱动程序上,或者说,将抽象的设备名转换为具体的物理设备名,并进一步可以找到相应物理设备的驱动程序入口。
- 此外,还应对设备进行保护,禁止用户直接访问设备,以防止无权访问的用户使用。
- 2.缓冲管理
- 无论是字符设备还是块设备,它们的运行速度都远低于CPU的速度。
- 为了缓和CPU和I/O设备之间的矛盾、提高CPU的利用率,在现代OS中都无一例外地分别为字符设备和块设备配置了相应的缓冲区。
- 缓冲区有着多种形式,如单缓冲区、双缓冲区、循环缓冲区、公用缓冲池等,以满足不同情况的需要。
- 3.差错控制
- 由于设备中有着许多的机械和电气部分,因此,它们比主机更容易出现故障,这就导致I/O操作中的绝大多数错误都与设备有关。
- 错误可分为如下两类:
- (1)暂时性错误。暂时性错误是因发生暂时性事件引起的,如电源的波动。它可以通过重试操作来纠正。
- 例如,在网络传输中,由于传输路途较远、缓冲区数量暂时不足等因素,会经常发生在网络中传输的数据包丢失或延误性的暂时性错误。
- 当网络传输软件检测到这种情况后,可以通过重新传送来纠正错误。
- 又如,当磁盘传送发生错误后,开始驱动程序并不立即认为传送出错,而是令磁盘重传,只有连续多次(如10次)出错,才认为磁盘出错,并向上层报告。
- 一般地,设备出现故障后,主要由设备驱动程序处理,而设备独立性软件只处理那些设备驱动程序无法处理的错误。
- (2)持久性错误。
- 持久性错误是由持久性故障引起的,如电源掉电、磁盘上有一条划痕或者在计算中发生除以零的情况等。
- 持久性错误容易发现,有些错误是只要重复执行相同的程序就会再现的错误。
- 要排除持久性错误,通常需要查清发生错误的原因。
- 但也有某些持久性硬件错误可由操作系统进行有效的处理,而不用涉及高层软件。如磁盘上的少数盘块遭到破坏而失效,此时无需更换磁盘,而只需将它们作为坏的盘块记录下来,并放入一张坏盘块表中,以后不再使用这些坏块即可。
- 4.对独立设备的分配与回收
- 在系统中有两类设备:独占设备和共享设备。
- 对于独占设备,为了避免诸进程对独占设备的争夺,必须由系统来统一分配,不允许进程自行使用。
- 每当进程需要使用某(独占)设备时,必须先提出申请。
- OS接到对设备的请求后,先对进程所请求的独占设备进行检查,看该设备是否空闲。
- 若空闲,才把该设备分配给请求进程。
- 否则,进程将被阻塞,放入该设备的请求队列中等待。等到其它进程释放该设备时,再将队列中的第一个进程唤醒,该进程得到设备后继续运行。
- 5.独立于设备的逻辑数据块
- 不同类型的设备,其数据交换单位是不同的,读取和传输速率也各不相同,如字符型设备以单个字符(字)为单位,块设备是以一个数据块为单位。
- 即使同一类型的设备,其数据交换单位的大小也是有差异的,如不同磁盘由于扇区大小的不同,可能造成数据块大小的不一致。
- 设备独立性软件应能够隐藏这些差异而被逻辑设备使用,并向高层软件提供大小统一的逻辑数据块。与设备无关软件的功能
设备分配
- 系统为实现对独占设备的分配,必须在系统中配置相应的数据结构。
1.设备分配中的数据结构
- 在用于设备分配的数据结构中,记录了对设备或控制器进行控制所需的信息。
- 在进行设备分配时需要如下的数据结构。
1)设备控制表DCT
-
系统为每一个设备都配置了一张设备控制表,用于记录设备的情况, -
-
其中,设备控制器表对应一个设备控制器,(因此,在后面提到的分配控制器的步骤中),可以从DCT中找出该设备连接的控制器的COCT -
设备控制表中,除了有用于指示设备类型的字段type和设备标识字段deviceid外, -
还应含有下列字段:
- (1)设备队列队首指针,凡因请求本设备而未得到满足的进程,应将其PCB按照一定的策略排成一个设备请求队列,其队首指针指向队首PCB;
- (2)忙/闲标志,用于表示当前设备的状态是忙或闲:
- (3)与设备连接的控制器表指针,该指针指向该设备所连接的控制器的控制表;
- (4)重复执行次数,由于外部设备在传送数据时较易发生数据传送错误,因而在许多系统中规定了设备在工作中发生错误时应重复执行的次数,在重复执行时,若能恢复正常传送,则仍认为传送成功,仅当重复执行次数达到规定值仍不成功时,才认为传送失败。
2)控制器控制表、通道控制表和系统设备表
(1)控制器控制表(COCT)
- 系统为每一个控制器都设置了用于记录控制器情况的控制器控制表,
- 。
(2)通道控制表(CHCT)
- 每个通道都有一张通道控制表。
(3)系统设备表(SDT)
- 这是系统范围的数据结构,记录了系统中全部设备的情况,每个设备占一个表目,其中包括有设备类型、设备标识符、设备控制表及设备驱动程序的入口等项,
2.设备分配时应考虑的因素
- 系统在分配设备时,应考虑如下几个因素:
- 1)设备的固有属性
- (1)独占设备的分配策略。将一个设备分配给某进程后,便由该进程独占,直至该进程完成或释放该设备。
- (2)共享设备的分配策略。对于共享设备,可同时分配给多个进程使用,此时须注意对这些进程访问该设备的先后次序进行合理的调度。
- (3)虚拟设备的分配策略,虚拟设备属于可共享的设备,可以将它同时分配给多个进程使用。
- 2)设备分配算法对设备分配的算法,通常只采用以下两种分配算法:
- (1)先来先服务。该算法是根据诸进程对某设备提出请求的先后次序,将这些进程排成一个设备请求队列,设备分配程序总是把设备首先分配给队首进程。
- (2)优先级高者优先。在利用该算法形成设备队列时,将优先级高的进程排在设备队列前面,而对于优先级相同的I/O请求,则按先来先服务原则排队。
- 3)设备分配中的安全性
- 从进程运行的安全性上考虑,设备分配有以下两种方式:
- (1)安全分配方式。
- 每当进程发出I/O请求后,便进入阻塞状态,直到其I/O操作完成时才被唤醒。
- 在采用该策略时,一旦进程已经获得某种设备后便阻塞,不能再请求任何资源,而在它阻塞时又不保持任何资源。
- 因此,摒弃了造成死锁的四个必要条件之一的“请求和保持"条件,故设备分配是安全的。其缺点是CPU与I/O设备是顺序工作的。
- (2)不安全分配方式。
- 在这种分配方式中,进程在发出I/O请求后仍继续运行,需要时又发出第二个I/O请求、第三个I/O请求等。
- 仅当进程所请求的设备已被另一进程占用时,才进入阻塞状态。
- 该策略的优点是,一个进程可同时操作多个设备,使进程推进迅速。
- 其缺点是分配不安全,因为它可能具备“请求和保持”条件,从而可能造成死锁。
- 因此,在设备分配程序中,应对本次的设备分配是否会发生死锁进行安全性计算,仅当计算结果说明分配是安全的情况下,才进行设备分配。
3.独占设备的分配程序
-
1)基本的设备分配程序
step3
查找
检查CHCT状态字段
yes
no
CHCT
COCT控制器控制表
busy?
挂到该通道的等待队列
将通道分配给进程
step2
在DCT中查找与设备连接的控制器
控制器状态(status)
yes
no
COCT
DCT设备控制表
busy?
挂到该控制器的等待队列
执行分配step3
step1
find
设备状态(status)
yes
no
yes
No
DCT设备控制表by指针
SDT系统设备表
busy?
挂到PCB任务队列
计算本次分配安全性
safe?
执行分配step2
- 只有在设备、控制器和通道三者都分配成功时,这次的设备分配才算成功。
- 然后,便可启动该I/O设备进行数据传送。
-
2)设备分配程序的改进
- 在上面的例子中,进程是以物理设备名提出I/O请求的。
- 如果所指定的设备己分配给其它进程,则分配失败。
- 或者说上面的设备分配程序不具有与设备无关性。为获得设备的独立性,进程应使用逻辑设备名请求I/O。这样,系统首先从SDT中找出第一个该类设备的DCT。若该设备忙,又查找第二个该类设备的DCT,仅当所有该类设备都忙时,才把进程挂在该类设备的等待队列上。而只要有一个该类设备可用,系统便进一步计算分配该设备的安全性。如安全,便可把设备分配给它。
逻辑设备名到物理设备名映射的实现
- 为了实现与设备的无关性,当应用程序请求使用I/O设备时,应当用逻辑设备名。
- 但系统只识别物理设备名,因此在系统中需要配置一张逻辑设备表,用于将逻辑设备名映射为物理设备名。
逻辑设备表LUT(LogicalUnitTable)
- 在逻辑设备表的每个表目中包含了三项:
- 逻辑设备名、物理设备名和设备驱动程序的入口地址
- 当进程用逻辑设备名请求分配I/O设备时,系统根据当时的具体情况,为它分配一台相应的物理设备。
- 与此同时,在逻辑设备表上建立一个表目,填上应用程序中使用的逻辑设备名和系统分配的物理设备名,以及该设备驱动程序的入口地址。
- 当以后进程再利用该逻辑设备名请求I/O操作时,系统通过查找LUT,便可找到该逻辑设备所对应的物理设备和该设备的驱动程序。
逻辑设备表的设置问题
- 在系统中可采取两种方式设置逻辑设备表:
- 第一种方式,是在整个系统中只设置一张LUT。
- 由于系统中所有进程的设备分配情况都记录在同一张LUT中,因而不允许在LUT中具有相同的逻辑设备名,这就要求所有用户都不使用相同的逻辑设备名。
- 在多用户环境下这通常是难以做到的,因而这种方式主要用于单用户系统中。
- 第二种方式,是为每个用户设置一张LUT,
- 每当用户登录时,系统便为该用户建立一个进程,同时也为之建立一张LUT,并将该表放入进程的PCB中。
- 由于通常在多用户系统中都配置了系统设备表,故此时的逻辑设备表可以采用上图格式。
用户层的IO软件
用户层的I/O软件一般而言,大部分的I/O软件都放在操作系统内部,但仍有一小部分在用户层,其中包括与用户程序链接在一起的库函数,以及完全运行于内核之外的假脱机系统等。
1.系统调用
- 一方面,为使诸进程能有条不紊地使用I/O设备,且能保护设备的安全性,不允许运行在用户态的应用进程去直接调用运行在核心态(系统态)的OS过程。
- 但另一方面,应用进程在运行时,又必须取得OS所提供的服务,否则,应用程序几乎无法运行。
- 为了解决此矛盾,OS在用户层中引入了一个中介过程——系统调用,应用程序可以通过它间接调用OS中的I/O过程,对I/O设备进行操作。
- 系统中会有许多系统调用,它们的实现方法是基本相同的。
- 下面简单说明系统调用的执行过程。
- 当应用程序需要执行某种I/O操作时,在应用程序中必须使用相应的系统调用。
- 当OS捕获到应用程序中的该系统调用后,便将CPU的状态从用户态转换到核心态,然后转向操作系统中相应过程,由该过程完成所需的I/O操作。
- 执行完成后,系统又将CPU状态从核心态转换到用户态,返回到应用程序继续执行
- 事实上,由OS向用户提供的所有功能,用户进程都必须通过系统调用来获取,
- 或者说,系统调用是应用程序取得OS所有服务的唯一途径。
- 在早期的操作中,系统调用是以汇编语言形式提供的,所以只有在用汇编语言编写的程序中,才能直接使用系统调用,这对用户是非常不方便的,后来在C语言中,首先提供了与系统调用相对应的库函数。
2.库函数
-
在C语言以及UNIX系统中,系统调用(如read)与各系统调用所使用的库函数(如read)之间几乎是一一对应的。 -
而微软定义了一套过程,称为Win32API的应用程序接口(ApplicationProgramInterface),程序员利用它们取得OS服务,该接口与实际的系统调用并不一一对应。 -
用户程序通过调用对应的库函数使用系统调用,这些库函数与调用程序连接在一起,被嵌入在运行时装入内存的二进制程序中。 -
在C语言中提供了多种类型的库函数,对于I/O方面,主要是对文件和设备进行读/写的库函数,以及控制/检查设备状态的库函数。 -
显然这些库函数的集合也应是I/O系统的组成部分。 -
而且我们可以这样来看待内核和库函数之间的关系:内核提供了OS的基本功能,而库函数扩展了OS内核,使用户能方便取得操作系统的服务。 -
在许多现代OS中,系统调用本身已经采用C语言编写,并以函数形式提供,所以在使用C语言编写的用户程序中,可以直接使用这些系统调用。 -
另外,操作系统在用户层中还提供了一些非常有用的程序,如下面将要介绍的假脱机系统,以及在网络传输文件时常使用的守护进程等,它们是运行在内核之外的程序,但它们仍属于I/O系统。
假脱机(Spooling)系统
如果说,通过多道程序技术可将一台物理CPU虚拟为多台逻辑CPU,从而允许多个用户共享一台主机,那么,通过假脱机技术,则可将一台物理I/O设备虚拟为多台逻辑I/O设备,这样也就允许多个用户共享一台物理I/O设备。
- In computing, spooling is a specialized form of multi-programming for the purpose of copying data between different devices. In contemporary systems,[a] it is usually used for mediating between a computer application and a slow peripheral, such as a printer.
- Spooling allows programs to “hand off” work to be done by the peripheral and then proceed to other tasks, or to not begin until input has been transcribed.
- A dedicated program, the spooler, maintains an orderly sequence of jobs for the peripheral and feeds it data at its own rate.
- Conversely, for slow input peripherals, such as a card reader, a spooler can maintain a sequence of computational jobs waiting for data, starting each job when all of the relevant input is available;
- see batch processing. The spool itself refers to the sequence of jobs, or the storage area where they are held.
- In many cases, the spooler is able to drive devices at their full rated speed with minimal impact on other processing.
Spooling is a combination of buffering and queueing.
Print spooling
-
Nowadays, the most common use of spooling is printing: documents formatted for printing are stored in a queue at the speed of the computer, then retrieved and printed at the speed of the printer. -
Multiple processes can write documents to the spool without waiting, and can then perform other tasks, while the “spooler” process operates the printer.[1] -
For example, when a large organization prepares payroll cheques, the computation takes only a few minutes or even seconds, but the printing process might take hours. -
If the payroll program printed cheques directly, it would be unable to proceed to other computations until all the cheques were printed. -
Similarly, before spooling was added to PC operating systems, word processors were unable to do anything else, including interact with the user, while printing.
Spooler or print management software often includes a variety of related features, such as allowing priorities to be assigned to print jobs, notifying users when their documents have been printed, distributing print jobs among several printers, selecting appropriate paper for each document, etc.
A print server applies spooling techniques to allow many computers to share the same printer or group of printers
SPOOLing系统的组成
- 假脱机技术在20世纪50年代,为了缓和CPU的高速性与I/O设备低速性间的矛盾,而引入了脱机输入、脱机输出技术。
- 该技术是利用专门的外围控制机,先将低速I/O设备上的数据传送到高速磁盘上,或者相反。
- 这样当处理机需要输入数据时,便可以直接从磁盘中读取数据,极大地提高了输入速度。
- 反之,在处理机需要输出数据时,也可以很快的速度把数据先输出到磁盘上,处理机便可去做自己的事情。
- 事实上,当系统中引入了多道程序技术后,完全可以利用其中的一道程序,来模拟脱机输入时的外围控制机功能,把低速I/O设备上的数据传送到高速磁盘上。
- 再用另一道程序模拟脱机输出时外围控制机的功能,把数据从磁盘传送到低速输出设备上。
- 这样,便可在主机的直接控制下,实现以前的脱机输入、输出功能。
- 此时的外围操作与CPU对数据的处理同时进行,我们把这种在联机情况下实现的同时外围操作的技术称为SPOOLing(SimultaneausPeriphemalOperatingOnLine)技术,或称为假脱机技术。
- 2.SPOOLing的组成如前所述,SPOOLing技术是对脱机输入/输出系统的模拟,相应地,如图6-21(a)所示,SPOOLing系统建立在通道技术和多道程序技术的基础上,以高速随机外存(通常为磁盘)为后援存储器。
SPOOLing的工作原理
井(磁盘中)
- (1)输入井和输出井。这是在磁盘上开辟出来的两个存储区域。
- 输入井模拟脱机输入时的磁盘,用于收容I/O设备输入的数据。
- 输出井模拟脱机输出时的磁盘,用于收容用户程序的输出数据。
- 输入/输出井中的数据一般以文件的形式组织管理,我们把这些文件称为井文件。
- 输入/输出队列:一个文件仅存放某一个进程的输入(或者输出)数据,所有进程的数据输入(或输出)文件链接成为一个输入(或输出)队列。
缓冲区(内存中)
- (2)输入缓冲区和输出缓冲区。
- 这是在内存中开辟的两个缓冲区,用于缓和CPU和磁盘之间速度不匹配的矛盾。
- 输入缓冲区用于暂存由输入设备传送的数据,之后再传送到输入井。
- 输出缓冲区用于暂存从输出井传送的数据,之后再传送到输出设备。
输入输出进程
- (3)输入进程和输出进程。
- 输入进程也称为预输入进程,用于模拟脱机输入时的外围控制机,将用户要求的数据从输入设备传送到输入缓冲区,再存放到输入井。
- 当CPU需要输入设备时,直接从输入井读入内存。
- 输出进程也称为缓输出进程,用于模拟脱机输出时的外围控制机,把用户要求输入的数据从内存传送并存放到输出井,待输出设备空闲时,再将输出井中的数据经过输出缓冲区输出至输出设备上。
井管理程序
- 用于控制作业与磁盘井之间信息的交换。
- 当作业执行过程中向某台设备发出启动输入或输出操作请求时,由操作系统调用井管理程序,由其控制从输入井读取信息或将信息输出至输出井。
SPOOLing系统的特点
- (1)提高了I/O的速度。这里,对数据所执行的I/O操作,已从对低速I/O设备执行的I/O操作演变为对磁盘缓冲区中数据的存取,如同脱机输入输出一样,提高了I/O速度,缓和了CPU与低速I/O设备之间速度不匹配的矛盾。
- (2)将独占设备改造为共享设备。因为在假脱机打印机系统中,实际上并没为任何进程分配设备,而只是在磁盘缓冲区中为进程分配一个空闲盘块和建立一张I/O请求表。这样,便把独占设备改造为共享设备。
- (3)实现了虚拟设备功能。宏观上,虽然是多个进程在同时使用一台独占设备,而对于每一个进程而言,它们都会认为自己是独占了一个设备。当然,该设备只是逻辑上的设备。
- 假脱机打印机系统实现了将独占设备变换为若干台对应的逻辑设备的功能。
假脱机打印机系统
-
打印机是经常用到的输出设备,属于独占设备。利用假脱机技术可将它改造为一台可供多个用户共享的打印设备,从而提高设备的利用率,也方便了用户。 -
共享打印机技术已被广泛地用于多用户系统和局域网络中。 -
假脱机打印系统主要有以下三部分: -
(1)磁盘缓冲区。它是在磁盘上开辟的一个存储空间,用于暂存用户程序的输出数据,在该缓冲区中可以设置几个盘块队列,如空盘块队列、满盘块队列等。 -
(2)打印缓冲区。用于缓和CPU和磁盘之间速度不匹配的矛盾,设置在内存中,暂存从磁盘缓冲区送来的数据,以后再传送给打印设备进行打印。 -
(3)假脱机管理进程和假脱机打印进程。
- 由假脱机管理进程为每个要求打印的用户数据建立一个假脱机文件,并把它放入假脱机文件队列中,由假脱机打印进程依次对队列中的文件进行打印。
- 每当用户进程发出打印输出请求时,假脱机打印机系统并不是立即把打印机分配给该用户进程,而是由假脱机管理进程完成两项工作:
- ①在磁盘缓冲区中为之申请一个空闲盘块,并将要打印的数据送入其中暂存;
- ②为用户进程申请一张空白的用户请求打印表,并将用户的打印要求填入其中,再将该表挂到假脱机文件队列上。在这两项工作完成后,虽然还没有进行任何实际的打印输出,但对于用户进程而言,其打印请求已经得到满足,打印输出任务已经完成。
- 真正的打印输出是假脱机打印进程负责的,当打印机空闲时,该进程首先从假脱机文件队列的队首摘取一张请求打印表,然后根据表中的要求将要打印的数据由输出井传送到内存缓冲区,再交付打印机进行打印。
- 一个打印任务完成后,假脱机打印进程将再次查看假脱机文件队列,若队列非空,则重复上述的工作,直至队列为空。
- 此后,假脱机打印进程将自己阻塞起来,仅当再次有打印请求时,才被重新唤醒运行。
- 利用假脱机系统向用户提供共享打印机的概念是:
- 对每个用户而言,系统并非即时执行其程序输出数据的真实打印操作,而只是即时将数据输出到缓冲区,这时的数据并未真正被打印,只是让用户感觉系统已为他打印:
- 真正的打印操作,是在打印机空闲且该打印任务在等待队列中已排到队首时进行的;
- 而且,打印操作本身也是利用CPU的一个时间片,没有使用专门的外围机:以上的过程是对用户屏蔽的,用户是不可见的。
守护进程(daemon)
- 前面是利用假脱机系统来实现打印机共享的一种方案,人们对该方案进行了某些修改,如取消该方案中的假脱机管理进程,为打印机建立一个守护进程,由它执行一部分原来由假脱机管理进程实现的功能,如为用户在磁盘缓冲区中申请一个空闲盘块,并将要打印的数据送入其中,将该盘块的首址返回给请求进程。
- 另一部分由请求进程自己完成,每个要求打印的进程首先生成一份要求打印的文件,其中包含对打印的要求和指向装有打印输出数据盘块的指针等信息,然后将用户请求打印文件放入假脱机文件队列(目录)中。
- 守护进程是允许使用打印机的唯一进程。
- 所有需要使用打印机进行打印的进程都需将一份要求打印的文件放在假脱机文件队列(目录)中。
- 如果守护进程正在睡眠,便将它唤醒,由它按照目录中第一个文件中的说明进行打印,打印完成后,再按照目录中第二个文件中的说明进行打印,如此逐份文件地进行打印,直到目录中的全部文件打印完毕,守护进程无事可做,又去睡眠。
- 等待用户进程再次发来打印请求。
- 除了打印机守护进程之外,还可能有许多其它的守护进程,如服务器守护进程和网络守护进程等。
- 事实上,凡是需要将独占设备改造为可供多个进程共享的设备时,都要为该设备配置一个守护进程和一个假脱机文件队列(目录)。
- 同样,守护进程是允许使用该独占设备的唯一进程,所有其它进程都不能直接使用该设备,只能将对该设备的使用要求写入一份文件中,放在假脱机目录中。
- 由守护进程按照目录中的文件依次来完成诸进程对该设备的请求,这样就把一台独占设备改造为可为多个进程共享的设备。
缓冲&缓存
缓冲区
缓存
- 缓存(cache)是保存数据副本的高速内存区域。
- 访问缓存副本比访问原版更加有效。
- 例如,正在运行进程的指令保存在磁盘上,缓存在物理内存上,并再次复制到CPU的次缓存和主缓存。
- 缓冲和缓存的区别是,缓冲可以保存数据项的唯一的现有副本,而根据定义缓存只是提供了一个位于其他地方的数据项的更快存储副本。
- 缓存和缓冲的功能不同,但是有时一个内存区域可以用于两个目的。
- 例如,为了保留复制语义和有效调度磁盘I/O,操作系统采用内存中的缓冲区来保存磁盘数据、这些缓冲区也用作缓存,以便提高文件的I/O效率;
- 这些文件可被多个程序共享,或者快速地写入和重读。
- 当内核收到文件I/O请求时,内核首先访问缓冲区缓存,以便查看文件区域是否已经在内存中可用。
- 如果是,可以避免或延退物理磁盘I/O。
- 此外,磁盘写入在数秒内会累积到缓冲缓存,以汇集大量传输来允许高效写入调度。
缓冲区的结构
- 在现代操作系统中,几乎所有的I/O设备在与处理机交换数据时都用了缓冲区。
- 缓冲区是一个存储区域,它可以由专门的硬件寄存器组成,但由于硬件的成本较高,容量也较小,一般仅用在对速度要求非常高的场合,如存储器管理中所用的联想存储器;设备控制器中用的数据缓冲区等。
- 在一般情况下,更多的是利用内存作为缓冲区。
由内存组成的缓冲区
- 缓冲区管理的主要功能是组织好这些缓冲区,并提供获得和释放缓冲区的手段。
缓冲的引入
- 引入缓冲区的原因有很多,可归结为以下几点:
- (1)缓和CPU与I/O设备间速度不匹配的矛盾。
- 事实上,凡在数据到达速率与其离去速率不同的地方,都可设置缓冲区,以缓和它们之间速率不匹配的矛盾。众所周知,CPU的运算速率远远高于I/O设备的速率,如果没有缓冲区,在输出数据时,必然会由于打印机的速度跟不上,而使CPU停下来等待:然而在计算阶段,打印机又空闲无事。
- 如果在打印机或控制器中设置一缓冲区,用于快速暂存程序的输出数据,以后由打印机“慢慢地”从中取出数据打印,这样,就可提高CPU的工作效率。
- 类似地,在输入设备与CPU之间设置缓冲区,也可使CPU的工作效率得以提高。
- (2)减少对CPU的中断频率,放宽对CPU中断响应时间的限制。
- 在远程通信系统中,如果从远地终端发来的数据仅用一位缓冲来接收,则必须在每收到一位数据时便中断一次CPU
- 这样,对于速率为9.6kb/s的数据通信
9.6
k
b
/
s
≈
10
k
b
/
s
=
1
0
4
b
/
(
1
0
3
m
s
)
=
10
b
/
m
s
=
10
b
/
1000
u
s
=
1
b
/
100
u
s
9.6kb/s\approx10kb/s=10^4b/(10^3ms)=10b/ms=10b/1000us=1b/100us
9.6kb/s≈10kb/s=104b/(103ms)=10b/ms=10b/1000us=1b/100us来说,就意味着其中断CPU的频率也为9.6kb/s,
- 即每100us就要中断CPU一次,而且CPU必须在100us内予以响应,否则缓冲区内的数据将被冲掉。
- 倘若设置一个具有8位的缓冲(移位)寄存器,则可使CPU被中断的频率降低为原来的1/8;
- 缓冲所有位填满的时候发出中断,让cpu取走数据
- 而cpu必须在下一个数据填充进来之前,完成响应,否则会丢失掉一个bit
- 而使用第三种形态(两个8位缓冲寄存器,可以放宽中断响应时限的要求值8倍:
- 当第一个缓冲寄存器满,发送一个中断请求,如果在下一个数据进入缓冲前,cpu未能完成响应,那么第二个8bit寄存器就排上用场,防止数据丢失,如果第二个寄存器的8位都用上可以放宽8倍的cpu中断响应时限)
- 若再设置一个8位寄存器,则又可把CPU对中断的响应时间从100us放宽到800us。
- 类似地,在磁盘控制器和磁带控制器中,都需要配置缓冲寄存器,以减少对CPU的中断频率,放宽对CPU中断响应时间的限制。随着传输速率的提高,需要配置位数更多的寄存器进行缓冲。
- (3)解决数据粒度不匹配的问题。
- 缓冲区可用于解决在生产者和消费者之间交换的数据粒度(数据单元大小)不匹配的问题。
- 例如,生产者所生产的数据粒度比消费者消费的数据粒度小时,生产者进程可以一连生产好几个数据单元的数据,当其总和己达到消费者进程所要求的数据单元大小时,消费者便可从缓冲区中取出消费。反之,如果生产者所生产的数据粒度比消费者消费的数据粒度大时,生产者每次生产的数据消费者可以分几次从缓冲区中取出消费。
- (4)提高CPU和I/O设备之间的并行性。
- 缓冲区的引入可显著地提高CPU和I/O设备间的并行操作程度,提高系统的吞吐量和设备的利用率。
- 例如,在CPU(生产者)和打印机(消费者)之间设置了缓冲区后,生产者在生产了一批数据并将它放入缓冲区后,便可立即去进行下一次的生产。
- 与此同时,消费者可以从缓冲区中取出数据消费,这样便可使CPU与打印机处于并行工作状态。
单缓冲区和双缓冲区
- 如果在生产者与消费者之间未设置任何缓冲,生产者与消费者之间在时间上会相互限制。
- 例如,生产者已经完成了数据的生产,但消费者尚未准备好接收,生产者无法把所生产的数据交付给消费者,此时生产者必须暂停等待,直到消费者就绪。
- 如果在生产者与消费者之间设置了一个缓冲区,则生产者无需等待消费者就绪,便可把数据输出到缓冲区。
单缓冲区(SingleBuffer)
- 在单缓冲情况下,每当用户进程发出一I/O请求时,操作系统便在主存中为之分配一缓冲区,
-
- 在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为T(transform),
- OS将该缓冲区中的数据传送到用户区的时间为M,
- 而CPU对这一块数据处理(计算)的时间为C(calculation)。
- 由于T和C是可以并行的,(但是M和C&T中的任何一方都不可以并行,否则引起混乱)
- 当T>C时,系统对每一块数据的处理时间为M+T;
- 反之(T<C)则为M+C,
- 故可把系统对每一块数据的处理时间表示为Max(C,T)+M。
- 在字符设备输入时,缓冲区用于暂存用户输入的一行数据,在输入期间,用户进程被挂起以等待数据输入完毕:在输出时,用户进程将一行数据输入到缓冲区后继续进行处理。
- 当用户进程已有第二行数据输出时,如果第一行数据尚未被提取完毕,则此时用户进程应阻塞。
双缓冲区(DoubleBuffer)
-
由于缓冲区是共享资源,生产者与消费者在使用缓冲区时必须互斥。 -
如果消费者尚未取走缓冲区中的数据,即使生产者又生产出新的数据,也无法将它送入缓冲区,生产者等待。 -
如果为生产者与消费者设置了两个缓冲区,便能解决这一问题。
- (使得M操作和T操作可以并行执行)
- 但是M操作和C操作还是不可以并行
-
为了加快输入和输出速度,提高设备利用率,人们又引入了双缓冲区机制,也称为缓冲对换(BufferSwapping) -
在设备输入时,先将数据送入第一缓冲区,装满后便转向第二缓冲区。 -
此时操作系统可以从第一缓冲区中移出数据,并送入用户进程 -
接着由CPU对数据进行计算。 -
在双缓冲时,系统处理一块数据的时间可以粗略地认为是Max(C+M,T).
-
如果C+M<T,可使块设备连续输入(处理速度高于数据输入的速度); -
如果C+M>T,则可使CPU不必等待设备输入。(比如数据处理比较复杂,是耗时的密集计算,cpu对材料的消耗速度慢于供应速度) -
总结:那个慢,那个就不需要等待对方
快的一方则要等待慢的一方
-
对于字符设备,若采用行输入方式,则采用双缓冲通常能消除用户的等待时间(用户输入慢),即用户在输入完第一行后,在CPU执行第一行中的命令时,用户可继续向第二缓冲区输入下一行数据。
单工/双工通信
- 如果在实现两台机器之间的通信时仅为它们配置了单缓冲
- 那么,它们之间在任一时刻都只能实现单方向的数据传输。
- 例如,只允许把数据从A传送到B,或者从B传送到A,而绝不允许双方同时向对方发送数据。
- 为了实现双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区,如图
非阻塞与异步I/O
阻塞I/O
- 系统调用接口的另一方面涉及选择阻塞I/O与非阻塞I/O。
- 当应用程序执行阻塞(blocking)系统调用时应用程序的执行就被挂起。
- 应用程序会从操作系统的运行队列移到等待队列。
- 当系统调用完成后,应用程序被移回到运行队列,符合恢复执行。
- 当它恢复执行时,它会收到系统调用的返回值。
- I/O设备执行的物理动作常常是异步的,执行时间也是可变的或不可预计的。
- 然而,大多数操作系统为应用程序接口采用阻塞系统调用,因为阻塞应用代码比非阻塞应用代码更加容易理解。
非阻塞I/O
- 有些用户级进程需要使用非阻塞(nonblocking)I/O。
- 一个例子是用户接口,用来接收键盘和鼠标输入,同时处理数据并显示到屏幕。
- 另一个例子是视频应用程序,用来从磁盘文件上读取帧,同时解压并显示输出到显示器。
- 应用程序开发人员可以交叉I/O与执行的一种方法是,编写多线程应用程序。
- 有些线程可以执行阻塞系统调用,而其他线程继续执行。
- 有的操作系统提供非阻塞I/O系统调用。
- 非阻塞调用不会很长时间停止应用程序的执行。
- 相反,它会很快返回,其返回值表示已经传输了多少字节。
异步系统调用
-
非阻塞系统调用的一种替代方法是异步系统调用。 -
异步调用立即返回,无需等待I/O完成,应用程序继续执行代码。 -
在将来I/O完成时,有以下方式来通知应用程序
- 通过设置应用程序地址空间内的某个变址,
- 或通过触发信号或软件中断
- 或在线性控制流之外执行的回调函数,。
-
非阻塞与异步的系统调用的区别是,
- 非阻塞调用read()立即返回任何可用的数据,读取的数据等于或少于请求的字节数,或为零。
- 异步调用read()要求的传输会完整执行,但是完成是在将来的某个特定时间。
-
One way an application writer can overlap execution with I/O is to writea multithreaded application. -
Some threads can perform blocking system calls,while others continue executing. -
Some operating systems provide nonblocking I/O system calls. -
A nonblocking call does not halt the execution of the application for an extended time.
- Instead, it returns quickly, with a return value thatindicates how many bytes were transferred.
-
An alternative to a nonblocking system call is an asynchronous systemcall.
- An asynchronous call returns immediately, without waiting for the I/O to complete.
- The application continues to execute its code.
- The completion of the I/O at some future time is communicated to the application,
- either through the setting of some variable in the address space of the application
- or through the triggering of a signal
- or software interrupt
- or a call-back routine that is executed outside the linear control ?ow of the application.
- Thedifference between nonblocking and asynchronous system calls is that a nonblocking read() returns immediately with whatever data are available—the full number of bytes requested, fewer, or none at all.
- An asynchronous read() call requests a transfer that will be performed in its entirety but will complete
at some future time. -
] -
-
在现代操作系统中,经常发生异步活动。
- 通常,它们不会暴露给用户或应用程序,而是包含在操作系统操作中。
- 在默认情况下,当应用程序发出网络发送请求或磁盘写入请求时,操作系统记住请求,缓冲I/O,并返回到应用程序。如有可能,为了优化整体系统性能,操作系统完成请求。
- 如果临时发生系统故障,则应用程序会丢失任何途中请求。
- 因此,操作系统通常限制缓冲请求的时间。
- 例如,有些版本的UNIX每隔30秒刷新磁盘缓冲区,每个请求在30秒内会被刷新。
- 应用程序内的数据一致性由内核维护,内核在发出I/O请求到设备之前读取数据,确保尚未写入数据返回给请求读者。
- 注意,多个线程对同一文件执行I/O可能不会收到一致的数据,它取决于内核如何实现I/O。在这种情况下,线程可能需要使用加锁协议。
- 有些I/O请求需要立即执行,这样I/O系统调用通常提供方法,以便指定特定设备的给定请求或I/O应当同步执行。
-
非阻塞行为的一个很好的例子是,用于网络套接字的系统调用select。
-
这个系统调用需要一个参数来指定最大等待时间。 -
通过设置为0,应用程序可以轮流检测网络活动而无需阻塞。 -
但是采用select引入额外的开销,因为调用select只检查是否可能进行I/O. -
对于数据传输,在select()之后,还需要采用某种类型的命令read或write。 -
在Mach中,有这种方法的变种,即阻塞多读调用。 -
通过这一系统调用可以对多个设备指定所需的读取,而且只要一个完成就可返回。
|