I/O软件的设计目标是将软件组织成一种层次结构,底层的软件用来屏蔽I/O硬件的细节,从而实现上层的设备无关性(即设备独立性),高层的软件主要为用户提供一个统一、规范和方便的接口。
为了实现设备无关性的目标,操作系统把I/O软件组织由下至上分成4个层次:中断处理程序、设备驱动程序、与设备无关软件、用户级的I/O软件。
当用户进程欲从文件中读取一个数据块时,就需要通过操作系统来完成此操作。与设备无关软件首先在内存的数据块缓冲区查找此数据块。若找到,则直接完成读取工作;若未找到,则系统调用设备驱动程序向硬件提出相应的请求,用户进程随即阻塞直到该数据块读出。当设备(如磁盘)读取数据块操作结束时(数据块已放入内存的数据缓冲区),由硬件发出一个中断来激活中断处理程序,中断处理程序则从设备获得返回状态值并唤醒被阻塞的用户进程,当用户进程被调度执行时则完成读取该文件在内存中数据块的工作。
下面对这四个层次自下向上分别进行讨论。
1.中断处理程序
在设备控制器的控制下,I/O设备完成I/O操作后,设备控制器就向CPU发出一个中断请求,CPU响应后便转去执行中断处理程序。无论是哪种I/O设备,其中断处理程序的处理过程都大体相同,主要有以下7个阶段。
(1)检查CPU响应中断的条件是否满足。如果有来自中断源的中断请求且CPU允许中断,则CPU响应中断的条件满足;否则中断处理无法进行。
(2)CPU响应中断后立即关中断。CPU响应中断后则立即关中断,使其不能再次响应其他中断。
(3)保存被中断进程的CPU现场信息。为了方便中断处理,以及在中断处理结束后能正确地返回到被中断进程的断点处继续执行,系统把被中断进程的程序状态字PSW和程序计数器PC等内容保存在核心栈中(因PSW中含有中断信息,而PC则给出返回的断点信息)。对被中断进程的CPU现场信息也要进行保留(放入该进程的PCB中),包括程序状态字PSW和程序计数器以及所有的CPU寄存器,如段寄存器、通用寄存器等,因为在中断处理时,可能用到这些寄存器。
(4)分析中断原因,转入相应的设备中断处理程序。由CPU对各个中断源进行测试,识别中断类型(是磁盘中断还是时钟中断)和中断的设备号(哪个磁盘引起的中断),处理优先级最高的中断源发出的中断请求,并发送一个应答信号给发出中断请求的进程,使其消除这个中断请求信号,然后将该中断处理程序的入口地址装入程序计数器中,使CPU转向中断处理程序执行。
(5)执行中断处理程序。对不同的设备执行不同的中断处理程序,中断处理程序从设备控制器中读出设备状态。如果是正常完成,则设备驱动程序就可做结束处理;如果还有数据要传送,则继续进行传送;如果是异常结束,则根据异常发生的原因进行相应的处理。
(6)退出中断处理,恢复被中断进程的CPU现场或调度新的进程执行。当中断处理程序完成中断处理后,通过中断返回指令将保存在核心栈中被中断进程的程序状态字PSW和程序计数器内容弹出,送入到PSW寄存器和程序计数器,并从被中断进程的PCB中取出CPU现场信息装入相应的寄存器中。即当被中断进程(程序)是执行第n条指令时被中断的(第n条指令执行结束后才响应中断),则中断结束后CPU将继续执行被中断进程(程序)第n+1条指令,这样就返回到被中断进程(程序)的断点处恢复运行。另一种方法是在中断处理结束时进行一次进程调度,以便在当前情况下使更适合运行的进程投入运行。这是因为在本次中断处理过程中,被中断的进程可能因某些事件没有发生,而不再具备运行条件,或者已降低了运行的优先权。也有可能在本次中断处理过程中有其他某个进程获得了更高的优先权,因此有必要进行一次进程调度,但无论怎样都必须为选中准备执行的进程恢复CPU现场信息。
(7)开中断,CPU继续执行。I/O操作完成后,设备驱动程序必须检查本次I/O操作中是否发生了错误,以便向上层软件报告,最终是向调用者报告本次执行的情况。然后CPU继续执行被中断进程或者执行由进程调度程序选中的某就绪进程。
2.设备驱动程序
设备驱动程序是I/O系统中与物理设备密切相关的软件,是指驱动物理设备和设备控制器或I/O控制等直接进行I/O操作的子程序集合。所有与物理设备细节有关的代码都集中在设备驱动程序中,不同类型的设备有不同的设备驱动程序。设备驱动程序主要负责启动指定设备,即负责设置与相关设备有关的寄存器的值,启动该设备进行I/O操作并指定操作的类型和数据流向等。当然,在启动指定设备之前,还必须完成一些必要的准备工作,如检查设备是否空闲等,在完成所有准备工作后才向设备控制器发送一条启动命令。
系统完成I/O请求的具体处理过程是:用户进程发出I/O请求⇒系统接受这个I/O请求⇒设备驱动程序具体完成I/O操作⇒I/O操作完成后用户进程继续执行。
下面简要说明I/O请求的处理过程,重点叙述设备驱动程序所做的工作。
(1)将抽象要求转换为具体要求。每个设备控制器中通常都有若干个寄存器,它们分别用于暂存命令、数据和参数等。由于用户及上层软件对设备控制器的具体情况并不了解,因此只能向它发出抽象的命令(要求),但这些命令无法直接传给设备控制器,因此就需要将这些抽象的命令转换为具体的要求。如将抽象命令中的盘块号转换为磁盘的柱面号、磁道号及扇区号。这一转换工作只能由设备驱动程序来完成,因为在操作系统中只有设备驱动程序才同时了解抽象命令和设备控制器中的寄存器情况,也只有它才知道命令、数据和参数应分别送往哪个寄存器。
(2)检查I/O请求的合法性。任何输入设备都只能完成一组特定的功能,若该设备不支持这次I/O请求,则认为该请求非法。如用户试图请求从打印机输入数据,显然系统应拒绝该请求。
(3)读出和检查设备状态。在启动某个设备进行I/O操作时,其前提条件是该设备正处于空闲状态。因此在启动设备之前,要从设备控制器的状态寄存器中读出该设备的状态。如为了向某设备写入数据,就要先检查该设备是否处于接收就绪状态,仅当它处于接收就绪状态时才能启动设备控制器;否则只能等待。
(4)传送必要的参数。对许多设备特别是块设备来说,除必须向控制器发出启动命令外,还需要传送必要的参数。如在启动磁盘进行读/写之前,应先将本次要传送的字节数和数据所应到达的内存、外存起始地址送入控制器的相应寄存器中。
(5)启动I/O设备。在完成上述准备工作后,设备驱动程序可以向控制器中的命令寄存器传送相应的控制命令。对于字符设备,若发出的是写命令,则设备驱动程序将把一个数据传送给控制器;若发出的是读命令,则设备驱动程序等待接收数据,并通过从控制器中的状态寄存器读入状态字的方法来确定数据是否到达。
(6)I/O完成。I/O完成后由通道(或设备)产生一个中断请求信号。CPU接到中断请求后,如果条件符合则响应中断转去执行相应的中断处理程序,唤醒因等待此次I/O完成而阻塞的进程,然后调度用户进程继续执行。
综上所述,设备驱动程序具有以下4种功能。
(1)将接收的抽象命令(要求)转换为具体要求。
(2)接受用户的I/O请求。设备驱动程序将用户的I/O请求排在请求队列的队尾,检查I/O请求的合法性,了解I/O设备的状态,并传送有关参数等。(www.xing528.com)
(3)取出请求队列中的队首请求并将相应设备分配给它,然后启动该设备工作完成指定的I/O操作。
(4)处理来自设备的中断,及时响应由控制器或通道发来的中断请求,并根据其中断类型调用相应的中断处理程序进行处理。
3.与设备无关软件
(1)设备无关性概念
设备无关性(又称设备独立性)是指用户程序独立于所使用的具体物理设备。即用户通过使用逻辑设备名来访问设备,而并不直接和具体设备打交道。当用户程序需要使用设备时,则通过逻辑设备名向操作系统申请设备,而该逻辑设备名到底对应哪台物理设备,则由操作系统根据实际情况决定。设备无关性体现在以下两个方面。
①从程序设计的角度看,各种设备所体现的接口都是一致的。即在程序中可以使用同样的命令去读不同设备上的数据,也可以用同样的命令将输出的数据送到不同的设备上。而这些不同设备之间的差异则由操作系统来处理,即呈现在用户程序中的设备都是相同的。
②操作系统对所有的设备及设备操作都采取统一方式进行管理。由于不同设备之间的差异,用软件实现时很难达到真正的一致。一般采用层次和模块化思想来实现设备管理子系统,低层的程序用来屏蔽设备的具体细节,而高层软件则将各类不同设备的操作都以相同的界面提供给用户。与设备无关性紧密相关的是统一以逻辑名来命名设备。
设备无关性提高了操作系统的适应性和可扩展性,用户编写的应用程序与具体使用的物理设备无关,因此即使更换了物理设备也无须改变应用程序。设备无关性所引入的逻辑设备和物理设备概念,使得逻辑设备只是实际物理设备属性的抽象,它并不局限于某个具体设备。如一台名为LST的具有打印机属性的逻辑设备,它可能是0号或1号打印机,在某些情况下也可能是显示终端,甚至是一台磁盘的某部分空间(作为虚拟打印机使用)。逻辑设备究竟与哪一个具体的物理设备相对应,要由系统根据当前的设备使用情况来决定或由用户指定。在应用程序编写中使用逻辑设备名来请求使用某类设备,而应用程序执行中则使用真实物理设备名。当然系统必须具有将逻辑设备名转换成物理设备名的功能,这类似于存储器管理中所介绍的逻辑地址和物理地址的概念,在用户程序中使用的是逻辑地址,而系统在分配和使用内存时则必须使用物理地址。
引入设备无关性这一概念后,使得用户程序可以使用逻辑设备名而不必使用物理设备名,这种做法有以下两方面优点。
①设备分配更加灵活。当多个用户的不同进程请求分配设备时,系统可以根据当前设备的忙闲状况,合理地调整逻辑设备名与物理设备名之间的对应情况,以保证设备的无关性。
②可以实现I/O重定向。所谓I/O重定向是指更换I/O设备时,无须更改用户程序。如在调试一个用户程序时,可以将程序的结果送到屏幕上显示,而当程序调试完成后,如果需要将程序的运行结果正式打印出来,则可更换输出设备,这只需将I/O重定向的数据结构,即逻辑设备表中的显示终端改为打印机即可,而无须修改用户程序。
(2)与设备无关软件
设备驱动程序是一个与硬件(或设备)紧密相关的软件,为了实现设备无关性,就必须在设备驱动程序之上设置一层与设备无关的软件,它提供适用于所有设备的常用I/O功能,并向用户级I/O软件提供一个统一的接口,与设备无关软件的功能主要有以下7种。
①向用户级I/O软件提供统一接口。所有设备向用户提供的接口都相同,如对各种设备的读操作在用户程序中都用read,而写操作都用write。
②设备命名。系统设计中的一个主要问题是对文件和I/O设备实体的命名方法。与设备无关软件负责将设备名映射到相应的设备驱动程序。一个设备名表示一个设备文件中唯一指定的一个i节点,i节点包含主设备号和次设备号,由主设备号可以找到相应的设备驱动程序,由次设备号提供参数给设备驱动程序来指定具体的物理设备。
③设备保护。操作系统应给各个用户赋予不同的设备访问权限以实现对设备的保护。
④提供与设备无关的数据块大小。不同磁盘类型其扇区的大小可能不同,与设备无关软件屏蔽掉在不同设备中使用的数据块大小可能不同的现实,向用户级I/O软件提供了统一的逻辑块大小。如可以把几个扇区作为一个逻辑块来处理,这样用户级I/O软件仅处理大小相同的逻辑块,而不必去考虑实际磁盘物理扇区的大小。
⑤对独占设备的分配与回收。一些设备(如打印机、光盘刻录机等)在同一时刻只能由一个进程使用,这就要求系统检查对该设备的使用请求,并根据该设备的忙闲情况来决定是否接受或拒绝此请求。对独占设备的分配与回收实际上属于临界资源的管理。
⑥缓冲管理。无论字符设备还是块设备都使用缓冲技术。对于块设备,硬件以块为单位进行读写,但用户进程却是按任意大小的数据长度来读、写。如果一个用户进程此时只写了半个数据块,系统则利用缓冲技术把这些数据保存在内存缓冲区中,等待后续写入的数据装满一个数据块时,才将其由内存缓冲区写到指定的块设备上。对于字符设备,用户进程向内存写数据的速度可能比由内存取出数据向设备输出的速度快,所以也需要缓冲。
⑦差错控制。由于I/O操作中出现的绝大多数错误都与设备有关,因此与设备有关的错误主要由设备驱动程序来处理,而与设备无关软件只处理设备驱动程序无法处理的那些错误。如一种典型的错误是磁盘块受损而导致不能读、写,设备驱动程序在尝试若干次读、写操作失败后,就会向与设备无关软件报错。
4.用户级I/O软件
用户级I/O软件是I/O系统的最上层软件,负责用户和与设备无关软件通信,即它面向用户。当接收到用户的I/O指令后,用户级I/O软件把具体的请求发送到与设备无关软件去做进一步的处理。用户级I/O软件主要包含I/O操作的库例程和SPOOLing系统。
虽然大多数I/O软件属于操作系统,但也有一小部分是与用户程序连接的库例程,它们不属于操作系统,甚至整个程序都在用户态下运行。系统调用包括I/O系统调用通常由库例程组成,如C语言程序的语句
库例程(函数)printf将与用户程序链接在一起放入可执行程序中,所有这些库例程显然是I/O系统的一部分。标准I/O库包含一些解决I/O事务的库例程,它们作为用户程序的一部分运行。
SPOOLing系统是用户级I/O软件的另一个重要类别。在多道程序设计中,SPOOLing是将一台独立设备改造成共享设备的一种行之有效的技术。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。