6.1 I/O系统的功能、模型和接口
I/O系统管理的主要对象是I/O设备和相应的设备控制器。其最主要的任务是,完成用户提出的I/O请求,提高I/O速率,以及提高设备的利用率,并能为更高层的进程方便地使用这些设备提供手段。
6.1.1 I/O系统的基本功能
1. 隐藏物理设备的细节
I/O设备的类型非常多,且彼此间在多方面都有差异,诸如它们接收和产生数据的速度,传输方向、粒度、数据的表示形式及可靠性等方面。
2. 与设备的无关性
隐藏物理设备的细节,在早期的OS中就已实现,它可方便用户对设备的使用。与设备的无关性是在较晚时才实现的,这是在隐藏物理设备细节的基础上实现的。
3. 提高处理机和I/O设备的利用率
在一般的系统中,许多I/O设备间是相互独立的,能够并行操作,在处理机与设备之间也能并行操作。因此,I/O系统的第三个功能是要尽可能地让处理机和I/O设备并行操作,以提高它们的利用率。为此,一方面要求处理机能快速响应用户的I/O请求,使I/O设备尽快地运行起来;另一方面也应尽量减少在每个I/O设备运行时处理机的干预时间。
4. 对I/O设备进行控制
对I/O设备进行控制是驱动程序的功能。目前对I/O设备有四种控制方式:① 采用轮询的可编程I/O方式;② 采用中断的可编程I/O方式;③ 直接存储器访问方式;④ I/O通道方式。
5. 确保对设备的正确共享
从设备的共享属性上,可将系统中的设备分为如下两类: (1) 独占设备,进程应互斥地访问这类设备,即系统一旦把这类设备分配给了某进程后,便由该进程独占,直至用完释放。典型的独占设备有打印机、磁带机等。系统在对独占设备进行分配时,还应考虑到分配的安全性。 (2) 共享设备,是指在一段时间内允许多个进程同时访问的设备。典型的共享设备是磁盘,当有多个进程需对磁盘执行读、写操作时,可以交叉进行,不会影响到读、写的正确性。
6. 错误处理
大多数的设备都包括了较多的机械和电气部分,运行时容易出现错误和故障。从处理的角度,可将错误分为临时性错误和持久性错误。对于临时性错误,可通过重试操作来纠正,只有在发生了持久性错误时,才需要向上层报告。
6.1.2 I/O系统的层次结构和模型
1. I/O软件的层次结构
通常把I/O 软件组织成四个层次
2. I/O系统中各种模块之间的层次视图
为了能更清晰地描述I/O系统中主要模块之间的关系,我们进一步介绍I/O系统中各种I/O模块之间的层次视图。
1)I/O系统的上、下接口
1. I/O系统接口 2.软件/硬件(RW/HW)接口。
2) I/O系统的分层
与前面所述的I/O软件组织的层次结构相对应,I/O系统本身也可分为如下三个层次: (1) 中断处理程序。 (2) 设备驱动程序。 (3) 设备独立性软件。
6.1.3 I/O系统接口
在I/O系统与高层之间的接口中,根据设备类型的不同,又进一步分为若干个接口。在图6-2中示出了块设备接口、流设备接口和网络接口。
1. 块设备接口
(1) 块设备。 (2) 隐藏了磁盘的二维结构。 (3) 将抽象命令映射为低层操作。
2. 流设备接口
流设备接口是流设备管理程序与高层之间的接口。该接口又称为字符设备接口,它反映了大部分字符设备的本质特征,用于控制字符设备的输入或输出。 (1) 字符设备。 (2) get和put操作。 (3) in-control指令。
3. 网络通信接口
在现代OS中,都提供了面向网络的功能。但首先还需要通过某种方式把计算机连接到网络上。同时操作系统也必须提供相应的网络软件和网络通信接口,使计算机能通过网络与网络上的其它计算机进行通信或上网浏览。
6.2 I/O设备和设备控制器
I/O设备一般是由执行I/O操作的机械部分和执行控制I/O的电子部件组成。通常将这两部分分开,执行I/O操作的机械部分就是一般的I/O设备,而执行控制I/O的电子部件则称为设备控制器或适配器(adapter)。在微型机和小型机中的控制器常做成印刷电路卡形式,因而也常称为控制卡、接口卡或网卡,可将它插入计算机的扩展槽中。在有的大、中型计算机系统中,还配置了I/O通道或I/O处理机。
6.2.1 I/O设备
1. I/O设备的类型
1) 按使用特性分类
第一类是存储设备,也称外存或后备存储器、辅助存储器,是计算机系统用以存储信息的主要设备。该类设备存取速度较内存慢,但容量比内存大得多,相对价格也便宜。
第二类就是输入/输出设备,又具体可分为输入设备、输出设备和交互式设备。输入设备用来接收外部信息,如键盘、鼠标、扫描仪、视频摄像、各类传感器等。输出设备是用于将计算机加工处理后的信息送向外部的设备,如打印机、绘图仪、显示器、数字视频显示设备、音响输出设备等。交互式设备则是集成上述两类设备,利用输入设备接收用户命令信息,并通过输出设备(主要是显示器)同步显示用户命令以及命令执行的结果。
2) 按传输速率分类
按传输速度的高低,可将I/O设备分为三类。
第一类是低速设备,这是指其传输速率仅为每秒钟几个字节至数百个字节的一类设备。属于低速设备的典型设备有键盘、鼠标器、语音的输入和输出等设备。
第二类是中速设备,这是指其传输速率在每秒钟数千个字节至数十万个字节的一类设备。典型的中速设备有行式打印机、 激光打印机等。
第三类是高速设备,这是指其传输速率在数百个千字节至千兆字节的一类设备。典型的高速设备有磁带机、磁盘机、光盘机等。
3) 按信息交换的单位分类
按信息交换的单位,可将I/O设备分成两类。
第一类是块设备(Block Device),这类设备用于存储信息。由于信息的存取总是以数据块为单位,故而得名。它属于有结构设备。典型的块设备是磁盘,每个盘块的大小为512 B~4 KB。磁盘设备的基本特征是其传输速率较高,通常每秒钟为几兆位;另一特征是可寻址,即对它可随机地读/写任一块;此外,磁盘设备的I/O常采用DMA方式。
第二类是字符设备(Character Device),用于数据的输入和输出。其基本单位是字符,故称为字符设备。它属于无结构类型。字符设备的种类繁多,如交互式终端、打印机等。字符设备的基本特征是其传输速率较低,通常为几个字节至数千字节;另一特征是不可寻址,即输入/输出时不能指定数据的输入源地址及输出的目标地址;此外,字符设备在输入/输出时,常采用中断驱动方式。
4) 按设备的共享属性分类
这种分类方式可将I/O设备分为如下三类:
(1) 独占设备。
这是指在一段时间内只允许一个用户(进程)访问的设备,即临界资源。因而,对多个并发进程而言,应互斥地访问这类设备。系统一旦把这类设备分配给了某进程后,便由该进程独占,直至用完释放。应当注意,独占设备的分配有可能引起进程死锁。
(2) 共享设备。
这是指在一段时间内允许多个进程同时访问的设备。当然,对于每一时刻而言,该类设备仍然只允许一个进程访问。 显然,共享设备必须是可寻址的和可随机访问的设备。典型的共享设备是磁盘。对共享设备不仅可获得良好的设备利用率,而且它也是实现文件系统和数据库系统的物质基础。
(3) 虚拟设备。
这是指通过虚拟技术将一台独占设备变换为若干台逻辑设备,供若干个用户(进程)同时使用。
2. 设备与控制器之间的接口
通常,设备并不是直接与CPU进行通信,而是与设备控制器通信,因此,在I/O设备中应含有与设备控制器间的接口,在该接口中有三种类型的信号,各对应一条信号线。
1) 数据信号线
这类信号线用于在设备和设备控制器之间传送数据信号。
对输入设备而言,由外界输入的信号经转换器转换后所形成的数据,通常先送入缓冲器中,当数据量达到一定的比特(字符)数后,再从缓冲器通过一组数据信号线传送给设备控制器。
对输出设备而言,则是将从设备控制器经过数据信号线传送来的一批数据先暂存于缓冲器中,经转换器作适当转换后,再逐个字符地输出
2) 控制信号线
这是作为由设备控制器向I/O设备发送控制信号时的通路。该信号规定了设备将要执行的操作,如读操作(指由设备向控制器传送数据)或写操作(从控制器接收数据),或执行磁头移动等操作。
3) 状态信号线
这类信号线用于传送指示设备当前状态的信号。设备的当前状态有正在读(或写);设备已读(写)完成,并准备好新的数据传送。
6.2.2 设备控制器
1. 设备控制器的基本功能
1) 接收和识别命令
CPU可以向控制器发送多种不同的命令,设备控制器应能接收并识别这些命令。为此,在控制器中应具有相应的控制寄存器,用来存放接收的命令和参数,并对所接收的命令进行译码。 例如,磁盘控制器可以接收CPU发来的Read、Write、Format等15条不同的命令,而且有些命令还带有参数;相应地,在磁盘控制器中有多个寄存器和命令译码器等。
2) 数据交换
这是指实现CPU与控制器之间、控制器与设备之间的数据交换。
对于前者,是通过数据总线,由CPU并行地把数据写入控制器,或从控制器中并行地读出数据;对于后者,是设备将数据输入到控制器,或从控制器传送给设备。为此,在控制器中须设置数据寄存器。
3) 标识和报告设备的状态
控制器应记下设备的状态供CPU了解。例如,仅当该设备处于发送就绪状态时,CPU才能启动控制器从设备中读出数据。
为此,在控制器中应设置一状态寄存器,用其中的每一位来反映设备的某一种状态。当CPU将该寄存器的内容读入后,便可了解该设备的状态。
4) 地址识别
就像内存中的每一个单元都有一个地址一样,系统中的每一个设备也都有一个地址,而设备控制器又必须能够识别它所控制的每个设备的地址。 此外,为使CPU能向(或从)寄存器中写入(或读出)数据,这些寄存器都应具有唯一的地址。 例如,在IBM PC机中规定,硬盘控制器中各寄存器的地址分别为320~32F之一。控制器应能正确识别这些地址,为此,在控制器中应配置地址译码器。
5) 数据缓冲
由于I/O设备的速率较低而CPU和内存的速率却很高,故在控制器中必须设置一缓冲器。
在输出时,用此缓冲器暂存由主机高速传来的数据,然后才以I/O设备所具有的速率将缓冲器中的数据传送给I/O设备;
在输入时,缓冲器则用于暂存从I/O设备送来的数据,待接收到一批数据后,再将缓冲器中的数据高速地传送给主机。
6) 差错控制
设备控制器还兼管对由I/O设备传送来的数据进行差错检测。若发现传送中出现了错误,通常是将差错检测码置位,并向CPU报告,于是CPU将本次传送来的数据作废,并重新进行一次传送。这样便可保证数据输入的正确性。
2. 设备控制器的组成
由于设备控制器位于CPU与设备之间,它既要与CPU通信,又要与设备通信,还应具有按照CPU所发来的命令去控制设备工作的功能,因此,现有的大多数控制器都是由以下三部分组成: (1) 设备控制器与处理机的接口。 (2) 设备控制器与设备的接口。 (3) I/O逻辑。
1) 设备控制器与处理机的接口
该接口用于实现CPU与设备控制器之间的通信。共有三类信号线: 数据线、地址线和控制线。数据线通常与两类寄存器相连接,
第一类是数据寄存器(在控制器中可以有一个或多个数据寄存器,用于存放从设备送来的数据(输入)或从CPU送来的数据(输出));
第二类是控制/状态寄存器(在控制器中可以有一个或多个这类寄存器,用于存放从CPU送来的控制信息或设备的状态信息)。
2) 设备控制器与设备的接口
在一个设备控制器上,可以连接一个或多个设备。相应地,在控制器中便有一个或多个设备接口,一个接口连接一台设备。在每个接口中都存在数据、控制和状态三种类型的信号。控制器中的I/O逻辑根据处理机发来的地址信号去选择一个设备接口。
3) I/O逻辑
在设备控制器中的I/O逻辑用于实现对设备的控制。它通过一组控制线与处理机交互,处理机利用该逻辑向控制器发送I/O命令;I/O逻辑对收到的命令进行译码。
每当CPU要启动一个设备时,一方面将启动命令发送给控制器;另一方面又同时通过地址线把地址发送给控制器,由控制器的I/O逻辑对收到的地址进行译码,再根据所译出的命令对所选设备进行控制。
6.2.3 内存映像I/O
1. 利用特定的I/O指令
在早期的计算机中,包括大型计算机,为实现CPU和设备控制器之间的通信,为每个控制寄存器分配一个I/O端口,这是一个8位或16位的整数,如图6-5(a)所示。另外还设置了一些特定的I/O指令。
2. 内存映像I/O
在这种方式中,在编址上不再区分内存单元地址和设备控制器中的寄存器地址,都采用k。当k值处于0~n-1范围时,被认为是内存地址,若k大于等于n时,被认为是某个控制器的寄存器地址。
6.2.4 I/O通道
1.I/O通道设备的引入
虽然在CPU与I/O设备之间增加了设备控制器后,已能大大减少CPU对I/O的干预,但当主机所配置的外设很多时,CPU的负担仍然很重。
为此,在CPU和设备控制器之间又增设了通道。其主要目的是为了建立独立的I/O操作,不仅使数据的传送能独立于CPU,而且也希望有关对I/O操作的组织、 管理及其结束处理尽量独立,以保证CPU有更多的时间去进行数据处理;
或者说,其目的是使一些原来由CPU处理的I/O任务转由通道来承担,从而把CPU从繁杂的I/O任务中解脱出来。
在设置了通道后,CPU只需向通道发送一条I/O指令。通道在收到该指令后,便从内存中取出本次要执行的通道程序,然后执行该通道程序,仅当通道完成了规定的I/O任务后,才向CPU发中断信号。 实际上,I/O通道是一种特殊的处理机,它具有执行I/O指令的能力,并通过执行通道(I/O)程序来控制I/O操作。但I/O通道又与一般的处理机不同,主要表现在以下两个方面: 一是其指令类型单一,这是由于通道硬件比较简单,其所能执行的命令主要局限于与I/O操作有关的指令;二是通道没有自己的内存,通道所执行的通道程序是放在主机的内存中的,换言之,是通道与CPU共享内存。
2.通道类型
1) 字节多路通道
这是一种按字节交叉方式工作的通道。它通常都含有许多非分配型子通道,其数量可从几十到数百个,每一个子通道连接一台I/O设备,并控制该设备的I/O操作。
这些子通道按时间片轮转方式共享主通道。当第一个子通道控制其I/O设备完成一个字节的交换后,便立即腾出主通道,让给第二个子通道使用;当第二个子通道也完成一个字节的交换后,同样也把主通道让给第三个子通道;依此类推。当所有子通道轮转一周后,重又返回来由第一个子通道去使用字节多路主通道。
这样,只要字节多路通道扫描每个子通道的速率足够快,而连接到子通道上的设备的速率不是太高时,便不致丢失信息。
上图示出了字节多路通道的工作原理。它所含有的多个子通道A,B,C,D,E,…,N,…分别通过控制器各与一台设备相连。假定这些设备的速率相近,且都同时向主机传送数据。设备A所传送的数据流为A1A2A3…;设备B所传送的数据流为B1B2B3…把这些数据流合成后(通过主通道)送往主机的数据流为A1B1C1D1 …A2B2C2D2 … A3B3C3D3 …。
2) 数组选择通道
字节多路通道不适于连接高速设备,这推动了按数组方式进行数据传送的数组选择通道的形成。
数组选择通道虽然可以连接多台高速设备,但由于它只含有一个分配型子通道,在一段时间内只能执行一道通道程序,控制一台设备进行数据传送,致使当某台设备占用了该通道后,便一直由它独占,即使是它无数据传送,通道被闲置,也不允许其它设备使用该通道,直至该设备传送完毕释放该通道。可见,这种通道的利用率很低。
3) 数组多路通道
数组选择通道虽有很高的传输速率,但它却每次只允许一个设备传输数据。 数组多路通道是将数组选择通道传输速率高和字节多路通道能使各子通道(设备)分时并行操作的优点相结合而形成的一种新通道。
它含有多个非分配型子通道,因而这种通道既具有很高的数据传输速率,又能获得令人满意的通道利用率。也正因此,才使该通道能被广泛地用于连接多台高、中速的外围设备,其数据传送是按数组方式进行的。
3.”瓶颈”问题
由于通道价格昂贵,致使机器中所设置的通道数量势必较少,这往往又使它成了I/O的瓶颈,进而造成整个系统吞吐量的下降。
解决“瓶颈”问题的最有效的方法,便是增加设备到主机间的通路而不增加通道,换言之,就是把一个设备连接到多个控制器上,而一个控制器又连接到多个通道上。
6.3 中断机构和中断处理程序
对于操作系统中的I/O系统,本文采取从低层向高层的介绍方法。中断在操作系统中有着特殊重要的地位,它是多道程序得以实现的基础,没有中断,就不可能实现多道程序,因为进程之间的切换是通过中断来完成的。另一方面,中断也是设备管理的基础,为了提高处理机的利用率和实现CPU与I/O设备并行执行,也必需有中断的支持。中断处理程序是I/O系统中最低的一层,它是整个I/O系统的基础。
6.3.1 程序I/O方式
1. 中断和陷入
1) 中断
中断是指CPU对I/O设备发来的中断信号的一种响应。CPU暂停正在执行的程序,保留CPU环境后,自动转去执行该I/O设备的中断处理程序。执行完后,再回到断点,继续执行原来的程序。I/O设备可以是字符设备,也可以是块设备、通信设备等。由于中断是由外部设备引起的,故又称为外中断。
2) 陷入
另外还有一种由CPU内部事件所引起的中断,例如进程在运算中发生了上溢或下溢,又如程序出错,如非法指令、地址越界,以及电源故障灯。通常把这类中断称为内中断或陷入(trap)。中断和陷入的主要区别是信号的来源,即来自于CPU外部还是CPU内部。
2. 中断向量表和中断优先级
1) 中断向量表
为了处理上的方便,通常是为每种设备配以响应的中断处理程序,并把程序的入口放在中断向量表的一个表项中,并未每一个设备的中断请求规定一个中断号,它直接对应于中断向量表的一个表项中。
2) 中断优先级
经常会有多个中断信号源,每个中断信号源对服务要求的紧急程度并不相同,例如,键盘终端的中断请求的紧急程度不如打印机,而打印机中断请求的紧急程度又不如磁盘等。为此,系统需要为他们分别规定不同的优先级。
3. 对多中断源的处理方式
1) 屏蔽(禁止)中断 2) 嵌套中断
6.3.2 中断处理程序
当一个进程请求I/O 操作时,该进程将被挂起,直到I/O设备完成I/O操作后,设备控制器便向CPU发送一个中断请求,CPU响应后便转向中断处理程序,中断处理程序执行相应的处理,处理完后解除相应进程的阻塞状态。
中断处理程序的处理过程可分成以下几个步骤:
1)测定是否有未响应的中断信号
每当设备完成一个字符(字或者数据块)的读入(或输出),设备控制器便向处理机发送一个中断请求信号。请求处理机将设备已读入的数据传送到内存的缓冲区中(读入),或者请求处理机将要输出的数据(输出)传送给设备控制器。
2)保护被中断进程的CPU环境
通常由硬件自动将处理机状态字PSW和程序计数器(PC)中的内容,保存在中断保留区(栈)中,然后把被中断进程的CPU现场信息(即包括所有的CPU寄存器,如通用寄存器、段寄存器等内容)都压入中断栈中,因为在中断处理时可能会用到这些寄存器。
3)转入相应的设备处理程序
由处理机对各个中断源进行测试,以确定引起本次中断的I/O设备,并发送一应答信号给发出中断请求的进程,使之消除该中断请求信号,然后将相应的设备中断处理程序的入口地址装入到程序计数器中,使处理机转向中断处理程序。
4)中断处理
对于不同的设备,有不同的中断处理程序。该程序首先从设备控制器中读出设备状态,以判别本次中断是正常完成中断,还是异常结束中断。若是前者,中断程序便进行结束处理;若还有命令,可再向控制器发送新的命令,进行新一轮的数据传送。若是异常结束中断,则根据发生异常的原因做相应的处理。
5)恢复被中断进程的现场
当中断处理完成以后,便可将保存在中断栈中的被中断进程的现场信息取出,并装入到相应的寄存器中,其中包括该程序下一次要执行的指令的地址N+1、处理机状态字PSW,以及各通用寄存器和段寄存器的内容。这样,当处理机再执行本程序时,便从N+1处开始,最终返回到被中断的程序。
6.4 设备驱动程序
设备处理程序通常又称为设备驱动程序,它是I/O系统的高层与设备控制器之间的通信程序,其主要任务是接收上层软件发来的抽象I/O要求,如read或write命令,再把它转换为具体要求后,发送给设备控制器,启动设备去执行;反之,它也将由设备控制器发来的信号传送给上层软件。由于驱动程序与硬件密切相关,故通常应为每一类设备配置一种驱动程序。例如,打印机和显示器需要不同的驱动程序。
1. 设备驱动程序的功能
(1) 接收由与设备无关的软件发来的命令和参数,并将命令中的抽象要求转换为与设备相关的低层操作序列。
(2) 检查用户I/O请求的合法性,了解I/O设备的工作状态,传递与I/O设备操作有关的参数,设置设备的工作方式。
(3) 发出I/O命令,如果设备空闲,便立即启动I/O设备,完成指定的I/O操作;如果设备忙碌,则将请求者的请求块挂在设备队列上等待。
(4) 及时响应由设备控制器发来的中断请求,并根据其中断类型,调用相应的中断处理程序进行处理。
2. 设备驱动程序的特点
设备驱动程序属于低级的系统例程,它与一般的应用程序及系统程序之间有下述明显差异:
(1) 驱动程序是实现在与设备无关的软件和设备控制器之间通信和转换的程序,具体说,它将抽象的I/O请求转换成具体的I/O操作后传送给控制器。又把控制器中所记录的设备状态和I/O操作完成情况,及时地反映给请求I/O的进程。
(2) 驱动程序与设备控制器以及I/O设备的硬件特性紧密相关,对于不同类型的设备,应配置不同的驱动程序。但可以为相同的多个终端设置一个终端驱动程序。
(3) 驱动程序与I/O设备所采用的I/O控制方式紧密相关,常用的I/O控制方式是中断驱动和DMA方式。
(4) 由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言书写。目前有很多驱动程序的基本部分已经固化在ROM中。
(5) 驱动程序应允许可重入。一个正在运行的驱动程序常会在一次调用完成前被再次调用。
3. 设备处理方式
在不同的操作系统中,所采用的设备处理方式并不完全相同。
(1) 为每一类设备设置一个进程,专门用于执行这类设备的I/O操作。比如,为所有的交互式终端设置一个交互式终端进程;又如,为同一类型的打印机设置一个打印进程。
(2) 在整个系统中设置一个I/O进程,专门用于执行系统中所有各类设备的I/O操作。也可以设置一个输入进程和一个输出进程,分别处理系统中所有各类设备的输入或输出操作。
(3) 不设置专门的设备处理进程,而只为各类设备设置相应的设备处理程序(模块),供用户进程或系统进程调用。
6.4.2 设备驱动程序的处理过程
设备驱动程序的主要任务是启动指定设备,完成上层指定的I/O工作。但在启动之前,应先完成必要的准备工作,如检测设备状态是否为“忙”等。在完成所有的准备工作后,才向设备控制器发送一条启动命令。
6.4.3 对I/O设备的控制方式
对设备的控制,早期是使用轮询的可编程I/O方式,后来发展为使用中断的可编程I/O方式。
1. 使用轮询的可编程I/O方式
处理机对I/O设备的控制采取轮询的可编程I/O方式,即在处理机向控制器发出一条I/O指令,启动输入设备输入数据时,要同时把状态寄存器中的忙/闲标志busy置为1,然后便不断地循环测试busy(称为轮询)。当busy=1时,表示输入机尚未输完一个字(符),处理机应继续对该标志进行测试,直至busy=0,表明输入机已将输入数据送入控制器的数据寄存器中。于是处理机将数据寄存器中的数据取出,送入内存指定单元中,这样便完成了一个字(符)的I/O。接着再去启动读下一个数据,并置busy=1。
2. 使用中断的可编程I/O方式
当前,对I/O设备的控制,广泛采用中断的可编程I/O方式,即当某进程要启动某个I/O设备工作时,便由CPU向相应的设备控制器发出一条I/O命令,然后立即返回继续执行原来的任务。设备控制器于是按照该命令的要求去控制指定I/O设备。此时,CPU与I/O设备并行操作。
3. 直接存储器访问方式
1) 接存储器访问方式的引入
虽然中断驱动I/O比程序I/O方式更有效,但它仍是以字(节)为单位进行I/O的。每当完成一个字(节)的I/O时,控制器便要向CPU请求一次中断。
该方式的特点是: (1) 数据传输的基本单位是数据块,即在CPU与I/O设备之间,每次传送至少一个数据块。 (2) 所传送的数据是从设备直接送入内存的,或者相反。 (3) 仅在传送一个或多个数据块的开始和结束时,才需CPU干预,整块数据的传送是在控制器的控制下完成的。可见,DMA方式较之中断驱动方式又进一步提高了CPU与I/O设备的并行操作程度。
2) DMA控制器的组成
DMA控制器由三部分组成:主机与DMA控制器的接口;DMA控制器与块设备的接口;I/O控制逻辑。下图示出了DMA控制器的组成。这里主要介绍主机与控制器之间的接口。
3) DMA工作过程
我们以从磁盘读入数据为例,来说明DMA方式的工作流程。 当CPU要从磁盘读入一数据块时,便向磁盘控制器发送一条读命令。该命令被送到其中的命令寄存器(CR)中。
同时,还须发送本次要将数据读入的内存起始目标地址,该地址被送入内存地址寄存器(MAR)中;
本次要读数据的字(节)数则送入数据计数器(DC)中,还须将磁盘中的源地址直接送至DMA控制器的I/O控制逻辑上。
然后,启动DMA控制器进行数据传送,以后,CPU便可去处理其它任务。此后,整个数据传送过程便由DMA控制器进行控制。
当DMA控制器已从磁盘中读入一个字(节)的数据并送入数据寄存器(DR)后,再挪用一个存储器周期,将该字(节)传送到MAR所指示的内存单元中。
接着便对MAR内容加1,将DC内容减1。若减1后DC内容不为0,表示传送未完,便继续传送下一个字(节);否则,由DMA控制器发出中断请求。
4.I/O通道控制方式
1) I/O通道控制方式的引入
虽然DMA方式比起中断方式来已经显著地减少了CPU的干预,即已由以字(节)为单位的干预减少到以数据块为单位的干预,但CPU每发出一条I/O指令,也只能去读(或写)一个连续的数据块。而当我们需要一次去读多个数据块且将它们分别传送到不同的内存区域,或者相反时,则须由CPU分别发出多条I/O指令及进行多次中断处理才能完成。
I/O通道方式是DMA方式的发展,它可进一步减少CPU的干预,即把对一个数据块的读(或写)为单位的干预减少为对一组数据块的读(或写)及有关的控制和管理为单位的干预。同时,又可实现CPU、通道和I/O设备三者的并行操作,从而更有效地提高整个系统的资源利用率。 例如,当CPU要完成一组相关的读(或写)操作及有关控制时,只需向I/O通道发送一条I/O指令,以给出其所要执行的通道程序的首址和要访问的I/O设备,通道接到该指令后,通过执行通道程序便可完成CPU指定的I/O任务。
2) 通道程序
通道是通过执行通道程序,并与设备控制器共同实现对I/O设备的控制的。通道程序是由一系列通道指令(或称为通道命令)所构成的。通道指令与一般的机器指令不同,在它的每条指令中都包含下列诸信息: (1) 操作码。操作码规定了指令所执行的操作,如读、写、控制等操作。 (2) 内存地址。内存地址标明字符送入内存(读操作)和从内存取出(写操作)时的内存首址。 (3) 计数。该信息表示本条指令所要读(或写)数据的字节数。 (4) 通道程序结束位P。该位用于表示通道程序是否结束。P=1表示本条指令是通道程序的最后一条指令。 (5) 记录结束标志R。R=0表示本通道指令与下一条指令所处理的数据是同属于一个记录;R=1表示这是处理某记录的最后一条指令。
下面示出了一个由六条通道指令所构成的简单的通道程序。该程序的功能是将内存中不同地址的数据写成多个记录。其中,前三条指令是分别将813~892单元中的80个字符和1034~1173单元中的140个字符及5830~5889单元中的60个字符写成一个记录;第4条指令是单独写一个具有300个字符的记录;第5、6条指令共写含500个字符的记录。
6.5 与设备无关的I/O软件
为了方便用户和提高OS的可适应性与可扩展性,在现代OS的I/O系统中,都无一例外地增加了与设备无关的I/O软件,以实现设备独立性,也称为设备无关性。其基本含义是:应用程序中所用的设备,不局限于使用某个具体的物理设备。为每个设备所配置的设备驱动程序是与硬件紧密相关的软件。
6.5.1 与设备无关
软件的基本概念
1. 以物理设备名使用设备
在早期OS中,应用程序在使用I/O设备时,都使用设备的物理名称,这使应用程序与系统中的物理设备直接相关。
2. 引入了逻辑设备名
为了实现与设备的无关性而引入了逻辑设备和物理设备两个概念。逻辑设备是抽象的设备名。
3. 逻辑设备名称到物理设备名称的转换
在应用程序中,用逻辑设备名称使用设备虽然方便了用户,但系统却只识别物理设备名称,因此在实际执行时,还必须使用物理名称。为此,在系统中,必须具有将逻辑设备名称转换为某物理设备名称的功能。
6.5.2 与设备无关的软件
1. 设备驱动程序的统一接口
为了使所有的设备驱动程序有着统一的接口,一方面,要求每个设备驱动程序与OS之间都有着相同的接口,或者相近的接口,这样会使添加一个新的设备驱动程序变得很容易,同时在很大程度上方便了开发人员对设备驱动程序的编制。另一方面,要将抽象的设备名映射到适当的驱动程序上,或者说,将抽象的设备名转换为具体的物理设备名,并进一步可以找到相应物理设备的驱动程序入口。此外,还应对设备进行保护,禁止用户直接访问设备,以防止无权访问的用户使用。
2. 缓冲管理
无论是字符设备还是块设备,它们的运行速度都远低于CPU的速度。为了缓和CPU和I/O设备之间的矛盾、提高CPU的利用率,在现代OS中都无一例外地分别为字符设备和块设备配置了相应的缓冲区。缓冲区有着多种形式,如单缓冲区、双缓冲区、循环缓冲区、公用缓冲池等,以满足不同情况的需要。
3. 差错控制
由于设备中有着许多的机械和电气部分,因此,它们比主机更容易出现故障,这就导致I/O操作中的绝大多数错误都与设备有关。错误可分为如下两类: (1) 暂时性错误。 (2) 持久性错误。
4. 对独立设备的分配与回收
在系统中有两类设备:独占设备和共享设备。对于独占设备,为了避免诸进程对独占设备的争夺,必须由系统来统一分配,不允许进程自行使用。每当进程需要使用某(独占)设备时,必须先提出申请。OS接到对设备的请求后,先对进程所请求的独占设备进行检查,看该设备是否空闲。若空闲,才把该设备分配给请求进程。否则,进程将被阻塞,放入该设备的请求队列中等待。等到其它进程释放该设备时,再将队列中的第一个进程唤醒,该进程得到设备后继续运行。
5. 独立于设备的逻辑数据块
不同类型的设备,其数据交换单位是不同的,读取和传输速率也各不相同,如字符型设备以单个字符(字)为单位,块设备是以一个数据块为单位。即使同一类型的设备,其数据交换单位的大小也是有差异的,如不同磁盘由于扇区大小的不同,可能造成数据块大小的不一致。设备独立性软件应能够隐藏这些差异而被逻辑设备使用,并向高层软件提供大小统一的逻辑数据块。
6.5.3 设备分配
系统为实现对独占设备的分配,必须在系统中配置相应的数据结构。
1. 设备分配中的数据结构
在用于设备分配的数据结构中,记录了对设备或控制器进行控制所需的信息。在进行设备分配时需要如下的数据结构。
1) 设备控制表DCT
系统为每一个设备都配置了一张设备控制表,用于记录设备的情况。
`
2) 控制器控制表、通道控制表和系统设备表
(1) 控制器控制表(COCT)。系统为每一个控制器都设置了用于记录控制器情况的控制器控制表,如图6-18(a)所示。
(2) 通道控制表(CHCT)。每个通道都有一张通道控制表,如图6-18(b)所示。
(3) 系统设备表(SDT)。这是系统范围的数据结构,记录了系统中全部设备的情况,每个设备占一个表目,其中包括有设备类型、设备标识符、设备控制表及设备驱动程序的入口等项。
2. 设备分配时应考虑的因素
系统在分配设备时,应考虑如下几个因素:
1) 设备的固有属性
设备的固有属性可分成三种,对它们应采取不同的分配策略:
(1) 独占设备的分配策略。
(2) 共享设备的分配策略。
(3) 虚拟设备的分配策略,虚拟设备属于可共享的设备,可以将它同时分配给多个进程使用。
2) 设备分配算法
对设备分配的算法,通常只采用以下两种分配算法:
(1) 先来先服务。当有多个进程对同一设备提出I/O请求时,该算法是根据诸进程对某设备提出请求的先后次序,将这些进程排成一个设备请求队列,设备分配程序总是把设备首先分配给队首进程。
(2) 优先级高者优先。在进程调度中的这种策略,是优先权高的进程优先获得处理机。如果对这种高优先权进程所提出的I/O请求也赋予高优先权,显然有助于这种进程尽快完成。
在利用该算法形成设备队列时,将优先权高的进程排在设备队列前面,而对于优先级相同的I/O请求,则按先来先服务原则排队。
3) 设备分配中的安全性
从进程运行的安全性上考虑,设备分配有以下两种方式:
(1) 安全分配方式
在这种分配方式中,每当进程发出I/O请求后,便进入阻塞状态,直到其I/O操作完成时才被唤醒。在采用这种分配策略时,一旦进程已经获得某种设备(资源)后便阻塞,使该进程不可能再请求任何资源,而在它运行时又不保持任何资源。 因此,这种分配方式已经摒弃了造成死锁的四个必要条件之一的“请求和保持”条件,从而使设备分配是安全的。其缺点是进程进展缓慢,即CPU与I/O设备是串行工作的。
(2) 不安全分配方式
在这种分配方式中,进程在发出I/O请求后仍继续运行,需要时又发出第二个I/O请求、 第三个I/O请求等。仅当进程所请求的设备已被另一进程占用时,请求进程才进入阻塞状态。 这种分配方式的优点是,一个进程可同时操作多个设备,使进程推进迅速。其缺点是分配不安全,因为它可能具备“请求和保持”条件,从而可能造成死锁。因此,在设备分配程序中,还应再增加一个功能,以用于对本次的设备分配是否会发生死锁进行安全性计算,仅当计算结果说明分配是安全的情况下才进行设备分配。
3. 独占设备的分配程序
1) 基本的设备分配程序
我们通过一个例子来介绍设备分配过程。当某进程提出I/O请求后,系统的设备分配程序可按下述步骤进行设备分配:
(1) 分配设备。
首先根据I/O请求中的物理设备名,查找系统设备表(SDT),从中找出该设备的DCT,再根据DCT中的设备状态字段,可知该设备是否正忙。若忙,便将请求I/O进程的PCB挂在设备队列上;否则,便按照一定的算法来计算本次设备分配的安全性。如果不会导致系统进入不安全状态,便将设备分配给请求进程;否则,仍将其PCB插入设备等待队列。
(2) 分配控制器
在系统把设备分配给请求I/O的进程后,再到其DCT中找出与该设备连接的控制器的COCT,从COCT的状态字段中可知该控制器是否忙碌。若忙,便将请求I/O进程的PCB挂在该控制器的等待队列上;否则,便将该控制器分配给进程。
(3) 分配通道
在该COCT中又可找到与该控制器连接的通道的CHCT,再根据CHCT内的状态信息,可知该通道是否忙碌。若忙,便将请求I/O的进程挂在该通道的等待队列上;否则,将该通道分配给进程。
只有在设备、 控制器和通道三者都分配成功时,这次的设备分配才算成功。然后,便可启动该I/O设备进行数据传送。
2) 设备分配程序的改进
在上面的例子中,进程是以物理设备名提出I/O请求的。如果所指定的设备已分配给其它进程,则分配失败。或者说上面的设备分配程序不具有与设备无关性。为获得设备的独立性,进程应使用逻辑设备名请求I/O。 增加设备的独立性 为了获得设备的独立性,进程应使用逻辑设备名请求I/O。 考虑多通路情况 为了防止在I/O系统中出现“瓶颈”现象,通常都采用多通路的I/O系统结构。
6.5.4 逻辑设备名到物理设备名映射的实现
1. 逻辑设备表LUT
在逻辑设备表的每个表目中包含了三项:逻辑设备名、物理设备名和设备驱动程序的入口地址。
2. 逻辑设备表的设置问题
在系统中可采取两种方式设置逻辑设备表: 第一种方式,是在整个系统中只设置一张LUT。 第二种方式,是为每个用户设置一张LUT
6.6 用户层的I/O软件
6.6.1 系统调用与库函数
1. 系统调用
一方面,为使诸进程能有条不紊地使用I/O设备,且能保护设备的安全性,不允许运行在用户态的应用进程去直接调用运行在核心态(系统态)的OS过程。但另一方面,应用进程在运行时,又必须取得OS所提供的服务,否则,应用程序几乎无法运行。为了解决此矛盾,OS在用户层中引入了一个中介过程——系统调用,应用程序可以通过它间接调用OS中的I/O过程,对I/O设备进行操作。
2. 库函数
在C语言以及UNIX系统中,系统调用(如read)与各系统调用所使用的库函数(如read)之间几乎是一一对应的。而微软定义了一套过程,称为Win32 API的应用程序接口(Application Program Interface),程序员利用它们取得OS服务,该接口与实际的系统调用并不一一对应。用户程序通过调用对应的库函数使用系统调用,这些库函数与调用程序连接在一起,被嵌入在运行时装入内存的二进制程序中。
6.6.2 假脱机(Spooling)系统
1. 假脱机技术
在20世纪50年代,为了缓和CPU的高速性与I/O设备低速性间的矛盾,而引入了脱机输入、脱机输出技术。该技术是利用专门的外围控制机,先将低速I/O设备上的数据传送到高速磁盘上,或者相反。这样当处理机需要输入数据时,便可以直接从磁盘中读取数据,极大地提高了输入速度。反之,在处理机需要输出数据时,也可以很快的速度把数据先输出到磁盘上,处理机便可去做自己的事情。
定义:为了缓和CPU的高速性与I/O设备的低速性间的矛盾引入的脱机输入、脱机输出技术。该技术利用专门的外围控制机,实现数据在低速I/O设备和高速磁盘之间的数据传送,此时外围操作可以与CPU对数据的处理同时进行,这种联机情况下的同时外围操作称作SPOOLING(Simultaneous Periphernal Operating On Line),或称为假脱机操作。
2.SPOOLing的组成
如前所述,SPOOLing技术是对脱机输入/输出系统的模拟,SPOOLing系统建立在通道技术和多道程序技术的基础上,以高速随机外存(通常为磁盘)为后援存储器。
SPOOLing系统主要由以下四部分构成:
(1) 输入井和输出井。
(2) 输入缓冲区和输出缓冲区。
(3) 输入进程和输出进程。
(4) 井管理程序。
3.SPOOLing系统的特点
SPOOLing系统具有如下主要特点:
(1) 提高了I/O的速度。这里,对数据所进行的I/O操作,已从对低速I/O设备进行的I/O操作,演变为对输入井或输出井中数据的存取,如同脱机输入输出一样,提高了I/O速度,缓和了CPU与低速I/O设备之间速度不匹配的矛盾。
(2) 将独占设备改造为共享设备。因为在SPOOLing系统中,实际上并没为任何进程分配设备,而只是在输入井或输出井中为进程分配一个存储区和建立一张I/O请求表。这样,便把独占设备改造为共享设备。
(3) 实现了虚拟设备功能。宏观上,虽然是多个进程在同时使用一台独占设备,而对于每一个进程而言,他们都会认为自己是独占了一个设备。当然,该设备只是逻辑上的设备。SPOOLing系统实现了将独占设备变换为若干台对应的逻辑设备的功能。
4. 假脱机打印机系统
打印机是经常用到的输出设备,属于独占设备。利用假脱机技术可将它改造为一台可供多个用户共享的打印设备,从而提高设备的利用率,也方便了用户。共享打印机技术已被广泛地用于多用户系统和局域网络中。假脱机打印系统主要有以下三部分: (1) 磁盘缓冲区。 (2) 打印缓冲区。 (3) 假脱机管理进程和假脱机打印进程。
5. 守护进程
前面是利用假脱机系统来实现打印机共享的一种方案,人们对该方案进行了某些修改,如取消该方案中的假脱机管理进程,为打印机建立一个守护进程,由它执行一部分原来由假脱机管理进程实现的功能,如为用户在磁盘缓冲区中申请一个空闲盘块,并将要打印的数据送入其中,将该盘块的首址返回给请求进程。另一部分由请求进程自己完成,每个要求打印的进程首先生成一份要求打印的文件,其中包含对打印的要求和指向装有打印输出数据盘块的指针等信息,然后将用户请求打印文件放入假脱机文件队列(目录)中。
6.7 缓冲区管理
在现代操作系统中,几乎所有的I/O设备在与处理机交换数据时都用了缓冲区。缓冲区是一个存储区域,它可以由专门的硬件寄存器组成,但由于硬件的成本较高,容量也较小,一般仅用在对速度要求非常高的场合,如存储器管理中所用的联想存储器;设备控制器中用的数据缓冲区等。
6.7.1 缓冲的引入
引入缓冲区的原因有很多,可归结为以下几点:
(1) 缓和CPU与I/O设备间速度不匹配的矛盾。
(2) 减少对CPU的中断频率,放宽对CPU中断响应时间的限制。
(3) 解决数据粒度不匹配的问题。
(4) 提高CPU和I/O设备之间的并行性。
6.7.2 单缓冲和双缓冲
1. 单缓冲区(Single Buffer)
在单缓冲情况下,每当用户进程发出一I/O请求时,操作系统便在主存中为之分配一缓冲区。在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为T,操作系统将该缓冲区中的数据传送到用户区的时间为M,而CPU对这一块数据处理(计算)的时间为C。由于T和C是可以并行的,当T > C时,系统对每一块数据的处理时间为M+T,反之则为M+C,故可把系统对每一块数据的处理时间表示为Max(C,T)+M。
2. 双缓冲区
为了加快输入和输出速度,提高设备利用率,人们又引入了双缓冲区机制,也称为缓冲对换(Buffer Swapping)。在设备输入时,先将数据送入第一缓冲区,装满后便转向第二缓冲区。此时操作系统可以从第一缓冲区中移出数据,并送入用户进程(见图6-24)。接着由CPU对数据进行计算。 在双缓冲时,系统处理一块数据的时间可以粗略地认为是Max(C,T)。如果C<T,可使块设备连续输入;如果C>T,则可使CPU不必等待设备输入。对于字符设备,若采用行输入方式,则采用双缓冲通常能消除用户的等待时间,即用户在输入完第一行之后,在CPU执行第一行中的命令时,用户可继续向第二缓冲区输入下一行数据。
如果在实现两台机器之间的通信时仅为它们配置了单缓冲,如图(a)所示,那么,它们之间在任一时刻都只能实现单方向的数据传输。例如,只允许把数据从A传送到B,或者从B传送到A,而绝不允许双方同时向对方发送数据。为了实现双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区,如图(b)所示。
6.7.3 环形缓冲区
1. 环形缓冲区的组成
(1) 多个缓冲区。
在循环缓冲中包括多个缓冲区,其每个缓冲区的大小相同。作为输入的多缓冲区可分为三种类型:用于装输入数据的空缓冲区R、已装满数据的缓冲区G以及计算进程正在使用的现行工作缓冲区C,如图6-26所示。
(2) 多个指针。
作为输入的缓冲区可设置三个指针:用于指示计算进程下一个可用缓冲区G的指针Nextg、指示输入进程下次可用的空缓冲区R的指针Nexti,以及用于指示计算进程正在使用的缓冲区C的指针Current。
R:用于装输入数据的空缓冲区 G:已装满数据的缓冲区 C:计算进程正在使用的现行工作缓冲区
2. 环形缓冲区的使用
计算进程和输入进程可利用下述两个过程来使用循环缓冲区。
(1) Getbuf过程。
当计算进程要使用缓冲区中的数据时,可调用Getbuf过程。该过程将由指针Nextg所指示的缓冲区提供给进程使用,相应地,须把它改为现行工作缓冲区,并令Current指针指向该缓冲区的第一个单元,同时将Nextg移向下一个G缓冲区。
类似地,每当输入进程要使用空缓冲区来装入数据时,也调用Getbuf过程,由该过程将指针Nexti所指示的缓冲区提供给输入进程使用,同时将Nexti指针移向下一个R缓冲区。
计算进程和输入进程可利用下述两个过程来使用循环缓冲区。
(2) Releasebuf过程。
当计算进程把C缓冲区中的数据提取完毕时,便调用Releasebuf过程,将缓冲区C释放。此时,把该缓冲区由当前(现行)工作缓冲区C改为空缓冲区R。
类似地,当输入进程把缓冲区装满时,也应调用Releasebuf过程,将该缓冲区释放,并改为G缓冲区。
3. 进程之间的同步问题
使用输入循环缓冲,可使输入进程和计算进程并行执行。相应地,指针Nexti和指针Nextg将不断地沿着顺时针方向移动,这样就可能出现下述两种情况:
(1) Nexti指针追赶上Nextg指针。这意味着输入进程输入数据的速度大于计算进程处理数据的速度,已把全部可用的空缓冲区装满,再无缓冲区可用。此时,输入进程应阻塞,直到计算进程把某个缓冲区中的数据全部提取完,使之成为空缓冲区R,并调用Releasebuf过程将它释放时,才将输入进程唤醒。这种情况被称为系统受计算限制。
(2) Nextg指针追赶上Nexti指针。这意味着输入数据的速度低于计算进程处理数据的速度,使全部装有输入数据的缓冲区都被抽空,再无装有数据的缓冲区供计算进程提取数据。这时,计算进程只能阻塞,直至输入进程又装满某个缓冲区,并调用Releasebuf过程将它释放时,才去唤醒计算进程。这种情况被称为系统受I/O限制。
6.7.4 缓冲池(Buffer Pool)
1. 缓冲池的组成
对于既可用于输入又可用于输出的公用缓冲池,其中至少应含有以下三种类型的缓冲区: ① 空(闲)缓冲区; ② 装满输入数据的缓冲区; ③ 装满输出数据的缓冲区。
为了管理上的方便,可将相同类型的缓冲区链成一个队列,于是可形成以下三个队列:
(1) 空缓冲队列emq。这是由空缓冲区所链成的队列。其队首指针F(emq)和队尾指针L(emq)分别指向该队列的首缓冲区和尾缓冲区。
(2) 输入队列inq。这是由装满输入数据的缓冲区所链成的队列。其队首指针F(inq)和队尾指针L(inq)分别指向该队列的首缓冲区和尾缓冲区。
(3) 输出队列outq。这是由装满输出数据的缓冲区所链成的队列。其队首指针F(outq)和队尾指针L(outq)分别指向该队列的首缓冲区和尾缓冲区。 除了上述三个队列外,还应具有四种工作缓冲区: ① 用于收容输入数据的工作缓冲区; ② 用于提取输入数据的工作缓冲区; ③ 用于收容输出数据的工作缓冲区; ④ 用于提取输出数据的工作缓冲区。
2.Getbuf过程和Putbuf过程
在“数据结构”课程中,曾介绍过队列和对队列进行操作的两个过程,它们是:
(1) Addbuf(type,number)过程。该过程用于将由参数number所指示的缓冲区B挂在type队列上。
(2) Takebuf(type)过程。该过程用于从type所指示的队列的队首摘下一个缓冲区。
为使诸进程能互斥地访问缓冲池队列,可为每一队列设置一个互斥信号量MS(type)。此外,为了保证诸进程同步地使用缓冲区,又为每个缓冲队列设置了一个资源信号量RS(type)。既可实现互斥又可保证同步的Getbuf过程和Putbuf过程描述如下:
Procedure Getbuf(type)
begin
Wait(RS(type));
Wait(MS(type));
B(number):=Takebuf(type);
Signal(MS(type));
end
Procedure Putbuf(type,number)
begin
Wait(MS(type));
Addbuf(type,number);
Signal(MS(type));
Signal(RS(type));
end
3. 缓冲区的工作方式
缓冲区可以工作在收容输入、提取输入、收容输出和提取输出四种工作方式下。
、(1) 收容输入。在输入进程需要输入数据时,便调用Getbuf(emq)过程,从空缓冲队列emq的队首摘下一空缓冲区,把它作为收容输入工作缓冲区hin。然后,把数据输入其中,装满后再调用Putbuf(inq,hin)过程,将该缓冲区挂在输入队列inq上。
(2) 提取输入。当计算进程需要输入数据时,调用Getbuf(inq)过程,从输入队列inq的队首取得一个缓冲区,作为提取输入工作缓冲区(sin),计算进程从中提取数据。计算进程用完该数据后,再调用Putbuf(emq,sin)过程,将该缓冲区挂到空缓冲队列emq上。
(3) 收容输出。当计算进程需要输出时,调用Getbuf(emq)过程从空缓冲队列emq的队首取得一个空缓冲区,作为收容输出工作缓冲区hout。当其中装满输出数据后,又调用Putbuf(outq,hout)过程,将该缓冲区挂在outq末尾。
(4) 提取输出。由输出进程调用Getbuf(outq)过程,从输出队列的队首取得一装满输出数据的缓冲区,作为提取输出工作缓冲区sout。在数据提取完后,再调用Putbuf(emq,sout)过程,将该缓冲区挂在空缓冲队列末尾。
6.8 磁盘存储器的性能和调度
6.8.1 磁盘性能简述
磁盘设备是一种相当复杂的机电设备,在此仅对磁盘的某些性能,如数据的组织、磁盘的类型和访问时间等方面做扼要的阐述。
1. 数据的组织和格式
磁盘设备可包括一或多个物理盘片; 每个盘片分一个或两个存储面; 每个存储面分成若干个磁道; 每条磁道被划分成若干个扇区。
一个物理记录存储在一个扇区上,磁盘上存储的物理记录块数目是由扇区数、磁道数以及磁盘面数所决定的。例如,一个10 GB容量的磁盘,有8个双面可存储盘片,共16个存储面(盘面),每面有16 383个磁道(也称柱面),63个扇区。 为了提高磁盘的存储容量,充分利用磁盘外面磁道的存储能力,现代磁盘不再把内外磁道划分为相同数目的扇区,而是利用外层磁道容量较内层磁道大的特点,将盘面划分成若干条环带,使得同一环带内的所有磁道具有相同的扇区数。显然,外层环带的磁道拥有较内层环带的磁道更多的扇区。
为了减少这种磁道和扇区在盘面分布的几何形式变化对驱动程序的影响,大多数现代磁盘都隐藏了这些细节,向操作系统提供虚拟几何的磁盘规格,而不是实际的物理几何规格。
为了在磁盘上存储数据,必须先将磁盘低级格式化。示出了一种温盘(温切斯特盘)中一条磁道格式化的情况。其中每条磁道含有30个固定大小的扇区,每个扇区容量为600个字节,其中512个字节存放数据,其余的用于存放控制信息。每个扇区包括两个字段: (1) 标识符字段,其中一个字节的SYNCH具有特定的位图像,作为该字段的定界符,利用磁道号、 磁头号及扇区号三者来标识一个扇区;CRC字段用于段校验。 (2) 数据字段,其中可存放512个字节的数据。
2. 磁盘的类型
对磁盘,可以从不同的角度进行分类。最常见的有:将磁盘分成硬盘和软盘、单片盘和多片盘、固定头磁盘和活动头(移动头)磁盘等。
1) 固定头磁盘
这种磁盘在每条磁道上都有一读/写磁头,所有的磁头都被装在一刚性磁臂中。通过这些磁头可访问所有各磁道,并进行并行读/写,有效地提高了磁盘的I/O速度。这种结构的磁盘主要用于大容量磁盘上。
2) 移动头磁盘
每一个盘面仅配有一个磁头,也被装入磁臂中。为能访问该盘面上的所有磁道,该磁头必须能移动以进行寻道。可见,移动磁头仅能以串行方式读/写,致使其I/O速度较慢;但由于其结构简单,故仍广泛应用于中小型磁盘设备中。在微型机上配置的温盘和软盘都采用移动磁头结构,故本节主要针对这类磁盘的I/O进行讨论。
3. 磁盘访问时间
1) 寻道时间
这是指把磁臂(磁头)移动到指定磁道上所经历的时间。该时间是启动磁臂的时间s与磁头移动n条磁道所花费的时间之和,即
其中,m是一常数,与磁盘驱动器的速度有关。对于一般磁盘,m=0.2;对于高速磁盘,m≤0.1,磁臂的启动时间约为2 ms。这样,对于一般的温盘,其寻道时间将随寻道距离的增加而增大,大体上是5~30 ms。
2) 旋转延迟时间
这是指定扇区移动到磁头下面所经历的时间。不同的磁盘类型中,旋转速度至少相差一个数量级,如软盘为300 r/min,硬盘一般为7200~15000 r/min,甚至更高。
对于磁盘旋转延迟时间而言,如硬盘,旋转速度为15000 r/min,每转需时4 ms,平均旋转延迟时间Tr为4ms/2 = 2 ms;而软盘,其旋转速度为 300 r/min或600 r/min,这样,平均Tr为50~100 ms。
3) 传输时间
这是指把数据从磁盘读出或向磁盘写入数据所经历的时间。Tt的大小与每次所读/写的字节数b和旋转速度有关:
其中,r为磁盘每秒钟的转数;N为一条磁道上的字节数,当一次读/写的字节数相当于半条磁道上的字节数时,Tt与Tr相同。因此,可将访问时间Ta表示为
由上式可以看出,在访问时间中,寻道时间和旋转延迟时间基本上都与所读/写数据的多少无关,而且它通常占据了访问时间中的大头。例如,我们假定寻道时间和旋转延迟时间平均为20 ms,而磁盘的传输速率为10 MB/s,如果要传输10 KB的数据,此时总的访问时间为21 ms,可见传输时间所占比例是非常小的。当传输100 KB数据时,其访问时间也只是30 ms,即当传输的数据量增大10倍时,访问时间只增加约50%。目前磁盘的传输速率已达80 MB/s以上,数据传输时间所占的比例更低。可见,适当地集中数据(不要太零散)传输,将有利于提高传输效率。
6.8.2 早期的磁盘调度算法
1. 先来先服务
这是一种最简单的磁盘调度算法。它根据进程请求访问磁盘的先后次序进行调度。
此算法的优点是公平、简单,且每个进程的请求都能依次地得到处理,不会出现某一进程的请求长期得不到满足的情况。但此算法由于未对寻道进行优化,致使平均寻道时间可能较长。 图给出了有9个进程先后提出磁盘I/O请求时,按FCFS算法进行调度的情况。这里将进程号(请求者)按他们发出请求的先后次序排队。这样,平均寻道距离为55.3条磁道,与后面即将讲到的几种调度算法相比,其平均寻道距离较大,故FCFS算法仅适用于请求磁盘I/O的进程数目较少的场合。
2. 最短寻道时间优先
该算法选择这样的进程:其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短。但这种算法不能保证平均寻道时间最短。
图给出了按SSTF算法进行调度时,各进程被调度的次序、每次磁头移动的距离,以及9次调度磁头平均移动的距离。
比较两个图可以看出,SSTF算法的平均每次磁头移动距离明显低于FCFS的距离,因而SSTF较之FCFS有更好的寻道性能,故过去曾一度被广泛采用。
6.8.3 基于扫描的磁盘调度算法
1) 扫描(SCAN)算法
SSTF算法虽然能获得较好的寻道性能,但却可能导致某个进程发生“饥饿”(Starvation)现象。 因为只要不断有新进程的请求到达,且其所要访问的磁道与磁头当前所在磁道的距离较近,这种新进程的I/O请求必然优先满足.对SSTF算法略加修改后所形成的SCAN算法,即可防止老进程出现“饥饿”现象。
该算法不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑的是磁头当前的移动方向。例如,当磁头正在自里向外移动时,SCAN算法所考虑的下一个访问对象,应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直至再无更外的磁道需要访问时,才将磁臂换向为自外向里移动。这时,同样也是每次选择这样的进程来调度,即要访问的磁道在当前位置内距离最近者,这样,磁头又逐步地从外向里移动,直至再无更里面的磁道要访问,从而避免了出现“饥饿”现象。
由于在这种算法中磁头移动的规律颇似电梯的运行,因而又常称之为电梯调度算法。下图给出了按SCAN算法对9个进程进行调度及磁头移动的情况。
SCAN算法既能获得较好的寻道性能,又能防止“饥饿”现象,故被广泛用于大、中、小型机器和网络中的磁盘调度。
但SCAN也存在这样的问题:当磁头刚从里向外移动而越过了某一磁道时,恰好又有一进程请求访问此磁道,这时,该进程必须等待,待磁头继续从里向外,然后再从外向里扫描完所有要访问的磁道后,才处理该进程的请求,致使该进程的请求被大大地推迟。
为了减少这种延迟,CSCAN算法规定磁头单向移动,例如,只是自里向外移动,当磁头移到最外的磁道并访问后,磁头立即返回到最里的欲访问的磁道,亦即将最小磁道号紧接着最大磁道号构成循环,进行循环扫描。
采用循环扫描方式后,上述请求进程的请求延迟将从原来的2T减为T + Smax,其中,T为由里向外或由外向里单向扫描完要访问的磁道所需的寻道时间,而Smax是将磁头从最外面被访问的磁道直接移到最里面欲访问的磁道(或相反)的寻道时间。下图给出了CSCAN算法对9个进程调度的次序及每次磁头移动的距离。
2) NStepSCAN算法
在SSTF、 SCAN及CSCAN几种调度算法中,都可能会出现磁臂停留在某处不动的情况,例如,有一个或几个进程对某一磁道有较高的访问频率,即这个(些)进程反复请求对某一磁道的I/O操作,从而垄断了整个磁盘设备。我们把这一现象称为“磁臂粘着”(Armstickiness)。在高密度磁盘上容易出现此情况。 N步SCAN算法是将磁盘请求队列分成若干个长度为N的子队列,磁盘调度将按FCFS算法依次处理这些子队列。而每处理一个队列时又是按SCAN算法,对一个队列处理完后,再处理其他队列。当正在处理某子队列时,如果又出现新的磁盘I/O请求,便将新请求进程放入其他队列,这样就可避免出现粘着现象。当N值取得很大时,会使N步扫描法的性能接近于SCAN算法的性能;当N=1时,N步SCAN算法便蜕化为FCFS算法
3) FSCAN算法
FSCAN算法实质上是N步SCAN算法的简化,即FSCAN只将磁盘请求队列分成两个子队列。 一个是由当前所有请求磁盘I/O的进程形成的队列,由磁盘调度按SCAN算法进行处理。 在扫描期间,将新出现的所有请求磁盘I/O的进程,放入另一个等待处理的请求队列。 这样,所有的新请求都将被推迟到下一次扫描时处理。