- I/O 系统
- ">中断处理程序
- ">设备驱动程序
- ">设备独立性软件
- ">用户层的 I/O 软件
I/O 系统
I/O 系统是 OS 的重要组成部分,I/O 系统管理的主要对象是 I/O 设备和相应的设备控制器。其最主要的任务是,完成用户提出的 I/O 请求,提高 I/O 速率,以及提高设备的利用率,并能为更高层的进程方便地使用这些设备提供手段。
I/O 系统的基本功能
为了满足系统和用户的要求,I/O 系统应具有下述几方面的基本功能。
功能 | 说明 |
---|---|
隐藏物理设备的细节 | I/O 设备的类型非常多,I/O 系统通过对设备加以适当的抽象,以隐藏掉物理设备的实现细节,仅向上层进程提供少量的、抽象的读/写命令 |
与设备的无关性 | 用户不仅可以使用抽象的I/O命令,还可使用抽象的逻辑设备名来使用设备 |
提高处理机和 I/O 设备的利用率 | 尽可能地让处理机和 I/O 设备并行操作,处理机能快速响应用户的 I/O 请求,并尽量减少在 I/O 设备运行时处理机的干预时间 |
对 I/O设备进行控制 | 目前对 I/O 设备有四种控制方式:采用轮询的可编程 I/O 方式、采用中断的可编程 I/O 方式、直接存储器访问方式、I/O 通道方式 |
确保对设备的正确共享 | 进程应互斥地访问独占设备,共享设备可以在一段时间内允许多个进程同时访问 |
错误处理 | 低层软件能够解决的错误就不向上层报告,只有低层软件解决不了的错误才向上层报告,请求高层软件解决 |
I/O 软件的层次结构
层次 | 说明 |
---|---|
用户层 I/O 软件 | 实现与用户交互的接口,用户可以直接调用该层提供的库函数对设备进行操作 |
设备独立性软件 | 实现用户程序与设备驱动器的统一接口、设备命名、设备的保护以及设备的分配与释放等,为设备管理和数据传送提供必要的存储空间 |
设备驱动程序 | 用于具体实现系统对设备发出的操作指令,驱动 I/O 设备工作的驱动程序 |
中断处理程序 | 用于保存被中断进程的 CPU 环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场后,返回到被中断的进程 |
I/O 系统模型
与前面所述的 I/O 软件组织的层次结构相对应,I/O 系统本身也可分为三个层次。
层次 | 说明 |
---|---|
中断处理程序 | 处于 I/O 系统的底层,直接与硬件进行交互。当有 I/O 设备发来中断请求信号时,中断处理程序首先保存被中断进程的 CPU 环境,然后转入相应设备的中断处理程序进行处理,在处理完成后又恢复被中断进程的 CPU 环境,返回断点继续运行 |
设备驱动程序 | 处于 I/O 系统的次底层,是进程和设备控制器之间的通信程序,将上层发来的抽象 I/O 请求转换为对 I/O 设备的具体命令和参数,并把它装入到设备控制器中的命令和参数寄存器中 |
设备独立性软件 | 实现了与设备无关性,内容包括设备命名、设备分配、数据缓冲和数据高速缓冲一类软件等 |
由于设备之间的差异很大,每类设备的驱动程序都不相同,故必须由设备制造厂商提供。每当在系统中增加一个新设备时,都需要由安装厂商提供新的驱动程序。这些层次之间有 I/O 系统接口和软件/硬件接口。
接口 | 说明 |
---|---|
I/O 系统接口 | I/O 系统与上层系统之间的接口,向上层提供对设备进行操作的抽象 I/O 命令,一些 OS 在用户层提供了与 I/O 操作有关的库函数 |
软件/硬件(RW/HW)接口 | 在它的上面是中断处理程序和用于不同设备的设备驱动程序,在它的下面是各种设备的控制器 |
I/O 系统接口
在 I/O 系统与高层之间的接口中,根据设备类型的不同,又进一步分为若干个接口,例如块设备接口、流设备接口和网络接口。
块设备接口
块设备接口是块设备管理程序与高层之间的接口,用于控制该类设备的输入或输出。块设备是指数据的存取和传输都是以数据块为单位的设备,典型的块设备是磁盘。该设备的基本特征是传输速率较高,并且可寻址。块设备接口将磁盘上的所有扇区从 0 到 n-1 依次编号,n 是磁盘中的扇区总数。这样编号后把磁盘的二维结构改变为一种线性序列,使块设备接口隐藏了磁盘地址是二维结构的情况。块设备接口支持上层发来的对文件或设备的打开、读、写和关闭等抽象命令,将上述命令映射为设备能识别的较低层具体操作。
虚拟存储器系统也需要使用块设备接口,因为在进程运行期间若所访问的页面不在内存时会发生缺页中断,此时就需要利用 I/O 系统,通过块设备接口从磁盘存储器中将所缺之页面调入内存。
流设备接口
流设备接口是流设备管理程序与高层之间的接口,用于控制字符设备的输入或输出。字符设备指数据的存取和传输是以字符为单位的设备,如键盘、打印机等,基本特征是传输速率较低,并且不可寻址,因而对它只能采取顺序存取方式,用户程序获取或输出字符的方法是采用 get 和 put 操作。由于大多数流设备都属于独占设备,必须采取互斥方式实现共享,为此流设备接口提供了打开和关闭操作。
网络通信接口
在现代 OS 中都提供了面向网络的功能,首先需要通过某种方式把计算机连接到网络上,同时操作系统也必须提供相应的网络软件和网络通信接口,使计算机能通过网络与网络上的其它计算机进行通信或上网浏览。
中断处理程序
中断在操作系统是多道程序得以实现的基础,,因为进程之间的切换是通过中断来完成的。中断也是设备管理的基础,为了提高处理机的利用率和实现 CPU 与 I/O 设备并行执行,也必需有中断的支持。
中断和陷入
中断是指 CPU 对 I/O 设备发来的中断信号的一种响应,CPU 暂停正在执行的程序,保留 CPU 环境后,自动地转去执行该 I/O 设备的中断处理程序。执行完后再回到断点,继续执行原来的程序。I/O 设备可以是字符设备,也可以是块设备、通信设备等。由于中断是由外部设备引起的,故又称外中断。
另外还有一种由 CPU 内部事件所引起的中断,通常把这类中断称为内中断或陷入(trap)。若系统发现了有陷入事件,CPU 也将暂停正在执行的程序,转去执行该陷入事件的处理程序。中断和陷入的主要区别是信号的来源,即是来自 CPU 外部还是 CPU 内部。
中断向量表
为了处理上的方便,通常是为每种设备配以相应的中断处理程序,并把该程序的入口地址放在中断向量表的一个表项中。每一个设备的中断请求规定一个中断号,它直接对应于中断向量表的一个表项中。当 I/O 设备发来中断请求信号时,由中断控制器确定该请求的中断号,根据中断号去查找中断向量表取得中断处理程序的入口地址。经常会有多个中断信号源,每个中断源对服务要求的紧急程度并不相同,为此系统就需要为它们分别规定不同的优先级。
对多中断源的处理方式
当处理机正在处理一个中断时,如果又来了一个新的中断请求,可有两种处理方式:屏蔽(禁止)中断与嵌套中断。屏蔽(禁止)中断当处理机正在处理一个中断时,将屏蔽掉所有的中断,即处理机对任何新到的中断请求,都暂时不予理睬,而让它们等待。其优点是简单,但不能用于对实时性要求较高的中断请求。
嵌套中断是在设置了中断优先级的系统中,通常按这样的规则来进行优先级控制:
- 当同时有多个不同优先级的中断请求时,CPU 优先响应最高优先级的中断请求;
-
中断处理程序
当一个进程请求 I/O 操作时,该进程将被挂起,直到 I/O 设备完成 I/O 操作后,设备控制器便向 CPU 发送一个中断请求,CPU 响应后便转向中断处理程序执行相应的处理,处理完后解除相应进程的阻塞状态。中断处理程序的处理过程可分成以下几个步骤:
测定是否有未响应的中断信号:若没有继续执行下一条指令,若有则停止原有进程的执行,准备转去执行中断处理程序;
- 保护被中断进程的 CPU 环境:先保护被中断进程的 CPU 环境,以便以后能恢复运行;
- 转入相应的设备处理程序:确定引起本次中断的 I/O 设备,并向提供中断信号的设备发送确认信号;
- 中断处理:对不同的设备,有不同的中断处理程序;
- 恢复 CPU 的现场并退出中断:当中断处理完成以后,需要恢复 CPU 的现场,退出中断。
I/O 操作完成后,驱动程序必须检查本次 I/O 操作中是否发生了错误,最终向调用者报告本次 I/O 的执行情况。
设备驱动程序
设备处理程序通常又称为设备驱动程序,它是 I/O 系统的高层与设备控制器之间的通信程序。其主要任务是接收上层软件发来的抽象 I/O 要求,再把它转换为具体要求后,发送给设备控制器启动设备执行。同时它也将由设备控制器发来的信号传送给上层软件。
设备驱动程序的功能
为了实现 I/O 系统的高层与设备控制器之间的通信,设备驱动程序应具有以下功能:
- 接收由与设备无关的软件发来的命令和参数,并将命令中的抽象要求转换为与设备相关的低层操作序列。
- 检查用户 I/O 请求的合法性,了解 I/O 设备的工作状态,传递与 I/O 设备操作有关的参数,设置设备的工作方式。
- 发出 I/O 命令,如果设备空闲便立即启动 I/O 设备并执行,如果设备忙碌则将请求者的请求块挂在设备队列上等待。
及时响应由设备控制器发来的中断请求,并根据其中断类型,调用相应的中断处理程序进行处理。
设备驱动程序的特点
设备驱动程序属于低级的系统例程,它与一般的应用程序及系统程序之间有下述明显差异:
实现在与设备无关的软件和设备控制器之间通信和转换的程序;
- 对于不同类型的设备,应配置不同的驱动程序,但可以为相同的多个终端设置终端驱动程序。
- 驱动程序与 I/O 设备所采用的 I/O 控制方式紧密相关;
- 其中的一部分必须用汇编语言书写,目前很多驱动程序的基本部分固化在 ROM 中;
-
设备处理方式
在不同的操作系统中,所采用的设备处理方式并不完全相同。设备处理方式分成以下三类,目前来说第三类用的比较多。
为每一类设备设置一个进程,专门用于执行这类设备的 I/O 操作;
- 在整个系统中设置一个 I/O 进程,专门用于执行系统中所有各类设备的 I/O 操作;
不设置专门的设备处理进程,而只为各类设备设置相应的设备驱动程序,供用户或系统进程调用。
设备驱动程序的处理过程
设备驱动程序的主要任务是启动指定设备,完成上层指定的 I/O 工作。以下是设备驱动程序的处理过程:
将抽象要求转换为具体要求;
- 对服务请求进行校验:驱动程序在启动 I/O 设备之前,必须先检查该用户的I/O请求是不是该设备能够执行的;
- 检查设备的状态:启动某个设备进行 I/O 操作,其前提条件应是该设备正处于就绪状态;
- 传送必要的参数:可向控制器的相应寄存器传送数据及与控制本次数据传输有关的参数;
- 启动 I/O 设备:在完成上述各项准备工作后,驱动程序便可以向控制器中的命令寄存器传送相应的控制命令。
在多道程序系统中,驱动程序一旦发出 I/O 命令,启动了一个 I/O 操作后,驱动程序便把控制返回给 I/O 系统把自己阻塞起来,直到中断到来时再被唤醒。具体的 I/O 操作是在设备控制器的控制下进行的,因此在设备忙于传送数据时,处理机又可以去干其它的事情。
设备独立性软件
为了方便用户和提高 OS 的可适应性与可扩展性,在现代 OS 的 I/O 系统中都增加了与设备无关的 I/O 软件,以实现设备独立性(设备无关性)。其基本含义是:应用程序中所用的设备,不局限于使用某个具体的物理设备。为了实现设备独立性,必须再在设备驱动程序之上设置一层软件,称为与设备无关的 I/O 软件(设备独立性软件)。
引入设备独立性软件的动机
在早期 OS 中,应用程序在使用 I/O 设备时都使用设备的物理名称,这使应用程序与系统中的物理设备直接相关。当应用进程运行时,如果所请求的物理设备(独占设备类型)已分配给其它进程,系统无法将另外相同的设备(物理设备名不同)分配给它,致使该应用进程请求 I/O 失败而被阻塞。当应用程序所需要的设备在系统中已经被更新时,该应用程序将再也无法在该系统上运行。可见应用程序直接与物理设备相关是不灵活的,I/O 设备的利用率低。
为了实现与设备的无关性而引入了逻辑设备和物理设备两个概念,逻辑设备是抽象的设备名,并没有指定具体的设备。只要系统中有一台该类设备未被分配,进程就不会被阻塞。与设备的无关软件还可实现 I/O 重定向,是指用于 I/O 操作的设备可以更换,而不必改变应用程序。
与设备无关的软件实现
在与设备无关的软件中,包括了执行所有设备公有操作的软件,具体有如下几项。
功能 | 说明 |
---|---|
设备驱动程序的统一接口 | 要求每个设备驱动程序与 OS 之间都有着相同或者相近的接口,使添加一个新的设备驱动程序变得很容易 |
缓冲管理 | 为了缓和 CPU 和 I/O 设备之间的速率矛盾,需要为设备配置相应的缓冲区 |
差错控制 | 设备中的机械和电气部分比主机更容易出现故障,因此需要对差错进行处理 |
对独立设备的分配与回收 | 为了避免诸进程对独占设备的争夺,必须由系统来统一分配,不允许进程自行使用 |
独立于设备的逻辑数据块 | 不同类型的设备的数据交换单位和读取、传输速率相同,设备独立性软件应能够隐藏这些差异 |
其中设备的错误可分为如下两类:
设备错误 | 说明 |
---|---|
暂时性错误 | 因发生暂时性事件引起的,如电源的波动,可以通过重试操作来纠正 |
持久性错误 | 由持久性故障引起的,如电源掉电、磁盘上有划痕或者在计算中发生除以零的情况等 |
设备名映射
当应用程序请求使用 I/O 设备时应当用逻辑设备名。但系统只识别物理设备名,因此在系统中需要配置一张逻辑设备表,用于将逻辑设备名映射为物理设备名。逻辑设备表 LUT(Logical Unit Table)的每个表目中包含了三项:逻辑设备名、物理设备名和设备驱动程序的入口地址。当进程用逻辑设备名请求分配 I/O 设备时,系统为它分配一台相应的物理设备,并在逻辑设备表上建立一个表目。当以后进程再利用该逻辑设备名请求 I/O 操作时,系统通过查找 LUT 可找到该逻辑设备所对应的物理设备和该设备的驱动程序。
在系统中可采取两种方式设置逻辑设备表,第一种方式是在整个系统中只设置一张 LUT。由于系统中所有进程的设备分配情况都记录在同一张 LUT 中,因而不允许在 LUT 中具有相同的逻辑设备名,在多用户环境下这通常是难以做到的。第二种方式是为每个用户设置一张 LUT,每当用户登录时,系统便为该用户建立一个进程,同时也为之建立一张 LUT 放入进程的 PCB 中。
用户层的 I/O 软件
大部分的 I/O 软件都放在操作系统内部,但仍有一小部分在用户层,其中包括与用户程序链接在一起的库函数和假脱机系统。
系统调用
为使诸进程能有条不紊地使用 I/O 设备,且能保护设备的安全性,不允许运行在用户态的应用进程去直接调用运行在核心态(系统态)的 OS 过程。但另一方面,应用进程在运行时,又必须取得 OS 所提供的服务。为了解决此矛盾,OS 在用户层中引入了系统调用,应用程序可以通过它间接调用 OS 中的 I/O 过程。
当应用程序需要执行某种 I/O 操作时,在应用程序中必须使用相应的系统调用。当 OS 捕获到应用程序中的该系统调用后,便将 CPU 的状态从用户态转换到核心态,然后转向操作系统中相应过程,由该过程完成所需的 I/O 操作。执行完成后,系统又将 CPU 状态从核心态转换到用户态,返回到应用程序继续执行。
在早期的操作中,系统调用是以汇编语言形式提供的,所以只有在用汇编语言编写的程序中,才能直接使用系统调用。后来在 C 语言中,首先提供了与系统调用相对应的库函数。库函数对于 I/O 方面,主要是对文件和设备进行读/写的库函数,以及控制/检查设备状态的库函数。
假脱机系统
假脱机(SPOOLing)技术,则可将一台物理 I/O 设备虚拟为多台逻辑 I/O 设备,这样就允许多个用户共享一台物理 I/O 设备。SPOOLing 的系统组成如下:
组成部分 | 说明 |
---|---|
输入井 | 在磁盘上开辟出来的存储区域,输入井模拟脱机输入时的磁盘,用于收容 I/O 设备输入的数据 |
输出井 | 在磁盘上开辟出来的存储区域,输出井模拟脱机输出时的磁盘,用于收容用户程序的输出数据 |
输入缓冲区 | 在内存上开辟出来的存储区域,用于暂存由输入设备传送的数据,之后再传送到输入井 |
输出缓冲区 | 在内存上开辟出来的存储区域,用于暂存从输出井传送的数据,之后再传送到输出设备 |
输入进程 | 用于模拟脱机输入时的外围控制机,将用户要求的数据从输入设备传送到输入缓冲区 |
输出进程 | 用于模拟脱机输出时的外围控制机,将输出井中的数据经过输出缓冲区输出至输出设备上 |
井管理程序 | 用于控制作业与磁盘井之间信息的交换 |
SPOOLing 系统有以下特点:
- 提高了 I/O 的速度:从对低速 I/O 设备执行的 I/O 操作演变为对磁盘缓冲区中数据的存取;
- 将独占设备改造为共享设备;
- 实现了虚拟设备功能:宏观上虽然是多个进程在同时使用一台独占设备,而对于每一个进程而言,它们都会认为自己是独占了一个设备。
假脱机打印机
打印机是经常用到的输出设备,属于独占设备,利用假脱机技术可将它改造为一台可供多个用户共享的打印设备。假脱机打印系统主要有以下三部分:
部分 | 说明 |
---|---|
磁盘缓冲区 | 在磁盘上开辟的一个存储空间,用于暂存用户程序的输出数据 |
打印缓冲区 | 设置在内存中,暂存从磁盘缓冲区送来的数据,以后再传送给打印设备进行打印 |
假脱机管理进程 | 为每个要求打印的用户数据建立一个假脱机文件,并把它放入假脱机文件队列中 |
假脱机打印进程 | 依次对队列中的文件进行打印 |
当多个用户进程提出输出打印的请求时,系统会答应它们的请求,但是并不是真正把打印机分配给他们,而是由假脱机管理进程为每个进程做两件事:
- 在磁盘输出井中为进程申请一个空闲缓冲区,并将要打印的数据送入其中;
- 为用户进程申请一张空白的打印请求表,并将用户的打印请求填入表中,再将该表挂到假脱机文件队列上。
由此可见,利用假脱机系统向用户提供共享打印机的概念是:对每个用户而言,系统并非即时执行其程序输出数据的真实打印操作,而只是即时将数据输出到缓冲区,这时的数据并未真正被打印,只是让用户感觉系统已为他打印。真正的打印操作,是在打印机空闲且该打印任务在等待队列中已排到队首时进行的,而且打印操作本身也是利用 CPU 的一个时间片,没有使用专门的外围机。以上的过程是对用户屏蔽的,用户是不可见的。