I/O 系统的功能、模型和接口
I/O系统管理的主要对象是 I/O设备和相应的设备控制器,其主要任务是完成用户提出的I/O请求,提高I/O速率以及设备的利用率,并能为更高层的进程方便地使用这些设备提供手段。
I/O系统的基本功能
- 隐藏物理设备的细节。不同 IO设备在接收和产生数据的速度,传输方向、粒度、数据的表示形式及可靠性等方面存在差异,控制外部设备执行操作需要向相应的设备控制器发送不同的命令和参数,程序员编写直接面向设备的程序是极端困难的,IO 系统必须对不同的设备加以适当的抽象,隐藏掉物理设备的实现细节,仅向上层进程提供少量的抽象的读写命令。
- 保证与设备的无关性。一方面要使用户不仅可以使用抽象的 IO 命令,还可以使用抽象的逻辑设备名来使用设备。另一方面要提高 OS 的可移植性和易适应性,允许不需重新编译将整个操作系统而增添新的设备驱动程序,以方便新的 I/O 设备的安装。
- 提高处理机和 I/O 设备的利用率。尽可能让处理器和 I/O设备并行操作,这一方面要求处理机能快速响应用户的 IO 请求,使 IO 设备尽快运行起来,另一方面应尽量减少在每个 IO设备运行时处理机的干预时间。
- 对设备进行控制(驱动程序的功能)。采用何种方式控制与 IO 设备的传输速率、传输的数据单位的因素有关。为方便高层软件和用户 IO软件也应屏蔽掉这种差异,向高层软件提供统一的操作接口。
- 确保对设备的正确共享。系统在对打印机、磁带机等独占设备(一旦分配给某进程便被独占,直至用完释放)进行分配时,应考虑到分配的安全性;多个进程在对磁盘等共享设备执行读写操作时可以交叉进行,应确保不会影响到读写的正确性。
- 处理错误。设备由于包含了较多的机械和电机部分,运行时容易出现错误和故障。临时性错误应通过重试操作来纠正,持久性错误应向上层报告。对错误的处理,应尽可能在接近硬件的层面上进行,只有低层软件解决不了的错误,才向上层报告。
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命令,不少 OS 在用户层提供了与 I/O 操作有关的库函数供用户使用。在上层系统中有文件系统、虚拟存储器系统,以及用户进程等。根据设备类型的不同,又可进一步分为若块设备接口、流设备接口和网络通信接口。
下接口——软件/硬件接口(RW/HW接口)
软件/硬件接口的下面是各种设备的控制器,如 CD-ROM 控制器、硬盘控制器、键盘控制器、打印机控制器、网络控制器等。他们都属于硬件。由于设备种类繁多。故该接口相当复杂。
I/O 系统的接口
块设备接口
块设备接口是块设备管理程序与上层之间的接口。该接口反映了大部分磁盘存储器、光盘存储器、闪存的本质特征。用于控制该类设备的输入和输出:
- 隐藏了磁盘的二维结构。在二维结构中,每个扇区的地址需要用磁道号和扇区号来表示。块设备接口将磁盘上的所有扇区从零到 n-1 依次编号。这样就把磁盘的二维结构改变为1种线性序列。
- 将抽象命令映射为低层操作:支持将上层发来的对文件或设备的打开独显和关闭的抽象命令映射为设备能识别的较低层具体操作。例如读磁盘命令时:先将抽象命令中的逻辑块号转换为磁盘的盘面、磁道、扇区等。
虚拟存储器系统也需要使用块设备接口。进程运行期间。每当它所访问的页面不在内存时,便会发生缺页中断,此时就需要利用I/O系统,通过块设备接口从磁盘存储器中将所缺的页面调入内存。
流设备接口
流设备接口是流设备管理程序与上层之间的接口,又称为字符设备接口,它反映了字符设备的本质特征,用于控制字符设备的输入或输出。
- get 和 put 操作:字符设备不可寻址,只能采取顺序存取方式,通常是为字符设备建立一个字符缓冲队列。设备的 I/O 字符流顺序的进入字符缓冲队列,或顺序送出到设备。 Get操作用于从字符缓冲区取得一个字符,返回给调用者。而put操作则用于把一个新字符输出到字符缓冲区中。以待送出到设备。
- In-control 指令。为了以统一的方式来处理不同字符类型,通常在流设备接口中提供了一种通用的 in-control指令。在该指令中包含了许多参数。每个参数表示一个与具体设备相关的特定功能。
- 打开和关闭操作:大多流设备都属于独占设备,必须采用互斥方式实现共享。为此,接口提供了打开和关闭操作。使用时必须先用打开操作来打开设备,设备已打开则表示它正在被其他进程使用。
网络通信接口
操作系统也必须提供相应的网络软件和网络通信接口
I/O 设备和设备控制器
I/O 系统是用于实现数据输入、输出及数据存储的系统,除了需要直接用于 I/O 和存储信息的设备外,还需要有相应的设备控制器和高速总线,有的大、中型计算机系统中,还配置了 I/O 通道或 I/O 处理机。
I/O 设备
I/O 设备的类型
按使用特性分类
存储设备 | 输入/输出设备 |
---|---|
也称外存或 后备存储器、 辅助存储器。 | • 输入设备用来接收外部信息,如键盘、鼠标、扫描仪、视频摄像、各类传感器等。 • 输出设备是用于将计算机加工处理后的信息送向外部的设备,如打印机、绘图仪、显示器、数字视频显示设备、音响输出设备等。 • 交互式设备则是集成上述两类设备,利用输入设备接收用户命令信息,并通过输出设备(主要是显示器)同步显示用户命令以及命令执行的结果。 |
按传输速率分类
设备类型 | 传输速率 | 举例设备 |
---|---|---|
低速设备 | 每秒钟几个字节至数百个字节 | 键盘、鼠标器、语音的输入和输出等设备 |
中速设备 | 每秒钟数千个字节至数十万个字节 | 行式打印机、激光打印机等 |
高速设备 | 数百个千字节至千兆字节 | 磁带机、磁盘机、光盘机等 |
按信息交换的单位分类
设备类型 | 块设备 | 字符设备 |
---|---|---|
描述 | 用于存储信息,数据的存取和传输都是以数据块为单位 | 用于数据的输入和输出,基本单位为字符 |
传输速率 | 较高,每秒钟为几兆位 | 较低,通常为几个字节至数千字节 |
是否可寻址 | 能指定数据的输入源地址及输出的目标地址,可随机地读/写任一块 | 不可寻址,不能指定数据的地址 |
典型设备 | 磁盘 | 交互式终端、打印机 |
I/O 方式 | 通常采用 DMA | 通常采用中断驱动 |
设备与控制器之间的接口
设备并不是直接与 CPU 进行通信,而是与设备控制器通信,因此,在 I/O 设备中应含有与设备控制器间的接口,在该接口中有三种类型的信号,各对应一条信号线。
- 数据信号线:用于在设备和设备控制器之间传送数据信号。对输入设备而言,由外界输入的信号经转换器转换后所形成的数据,通常先送入缓冲器中,当数据量达到一定的比特数后,再从缓冲器通过一组数据信号线传送给设备控制器,对输出设备而言,则是将从设备控制器经过数据信号线传送来的一批数据先暂存于缓冲器中,经转换器作适当转换后,再逐个字符地输出。
- 控制信号线:作为由设备控制器向 I/O 设备发送控制信号时的通路。该信号规定了设备将要执行的操作,如读操作(指由设备向控制器传送数据)或写操作(从控制器接收数据),或执行磁头移动等操作。
- 状态信号线:用于传送指示设备当前状态的信号。设备的当前状态有正在读(或写);设备已读(写)完成,并准备好新的数据传送。
设备控制器
设备控制器是 CPU 与 I/O 设备之间的硬件接口,其主要职责是控制一个或多个 I/O 设备,以实现 I/O 设备和计算机之间的数据交换,它接收从 CPU 发来的命令,并去控制 I/O 设备工作,以使处理机从繁杂的设备控制事务中解脱出来。控制器完成与设备间的数据交换后将产生中断。在微型机和小型机中的控制器,常做成印刷电路卡形式,因而也常称为接口卡,可将它插入计算机。
设备控制器是一个可编址的设备:
- 当它仅控制一个设备时,它只有一个唯一的设备地址。
- 若其可连接多个设备时,则应含有多个设备地址,并使每一个设备地址对应一个设备。(有些控制器可以处理两个、四个或八个同类设备。)
设备控制器可以是:集成在设备内部:例如,硬盘驱动器、打印机等都有自己的控制器。作为计算机主板的一部分:一些基本的设备控制器,如键盘和鼠标控制器,可能集成在计算机的主板上。作为扩展卡:对于更高级或专用的设备,设备控制器可能作为扩展卡安装在计算机内部。
设备控制器的基本功能
- 接收和识别命令: 设备控制器应能接收并识别CPU发送的不同命令。其中应具有相应的控制寄存器,用来存放接收的命令和参数,并对所接收的命令进行译码。例如,磁盘控制器可以接收 CPU 发来的 Read、Write、Format 等 15 条不同的命令;相应地,在磁盘控制器中有多个寄存器和命令译码器等。
- 数据交换:为此,在控制器中须设置数据寄存器。 CPU 与控制器之间通过数据总线交换, 由 CPU 并行读取或写入数据; 控制器与设备之间,设备将数据输入到控制器,或从控制器传送给设备。
- 标识和报告设备的状态:控制器中应设置一状态寄存器记下设备的状态供 CPU 了解。例如,仅当该设备处于发送就绪状态时,CPU才能启动控制器从设备中读出数据。
- 地址识别:系统中的每一个设备也都有一个地址,而设备控制器又必须能够识别它所控制的每个设备的地址。此外,寄存器都应具有唯一的地址。例如,在 IB-MPC 机中规定,硬盘控制器中各寄存器的地址分别为 320~32F 之一。为此,在控制器中应配置地址译码器。
- 数据缓冲:控制器中必须设置一缓冲器。输出时暂存由主机高速传来的数据,然后才 I/O 设备所具有的速率传送给 I/O 设备;在输入时暂存从 I/O 设备送来的数据,待接收到一批数据后,再将缓冲器中的数据高速地传送给主机。
- 差错控制:兼管对由 I/O 设备传送来的数据进行差错检测。若发现传送中出现了错误,通常是将差错检测码置位,并向 CPU 报告使数据作废,并重传,保证数据输入的正确性。
设备控制器的组成
大多数控制器都是由以下三部分组成:
- 设备控制器与处理机的接口:用于实现 CPU 与设备控制器之间的通信。共有三类信号线: 数据线、地址线和 控制线。数据线通常与数据寄存器(用于存放从设备或 CPU 送来的数据)、控制/状态寄存器(用于存放从 CPU 送来的控制信息或设备的状态信息) 相连。
- 设备控制器与设备的接口:控制器有一个或多个设备接口,在每个接口中都存在数据、控制和状态三种类型的信号。控制器中的 I/O 逻辑根据处理机发来的地址信号去选择一个设备接口。
- I/O 逻辑:用于实现对设备的控制。它通过一组控制线与处理机交互,处理机利用该逻辑向控制器发送 I/O 命令;I/O 逻辑对收到的命令进行译码。CPU 启动设备时,需要将启动命令发送给控制器;同时通过地址线把地址发送给控制器,由 I/O 逻辑对收到的地址进行译码,再根据所译出的命令对所选设备进行控制。
内存映像 I/O
驱动程序将抽象 IO 命令转换成一系列具体的命令、参数等数据装入设备控制器的相应寄存器,这一工作可用两种方法完成
方式一:利用特定的 IO 指令。主要缺点是访问内存和访问设备需要两种不同的命令。早期的计算机中,为实现cpu和设备控制器之间的通信,为每个控制寄存器分配一个 IO 端口,这是一个8位或16位的整数,另外还设置了一些特定的io指令,例如将 CPU 寄存器中的内容复制到控制器寄存器,需用特定 io-store
指令
访问内存 | 访问设备控制器 |
---|---|
Store cpu-reg, k | io-store cpu-reg, dev-no, dev-reg |
方式二:内存映像 I/O,此方式中在编址上不再区分内存单元地址和设备控制器中的寄存器体系地址,统一了对内存和对控制器的访问方法,简化了IO的编程。
当地址大于某个范围时,被认为是某个控制器的寄存器地址。
对 I/O 设备的控制方式
I在 I/O 控制方式的整个发展过程中,始终以尽量减少主机对 I/O 控制的干预 为宗旨,力求把主机从繁杂的 I/O 控制事务中解脱出来,以便更多地去完成数据处理任务。
- 在早期的计算机系统中,是采用程序 I/O 方式;
- 当在系统中引入中断机制后,I/O 方式便发展为中断驱动方式;
- 随着 DMA 控制器的出现,又使 I/O 方式在传输单位上从以字节为单位的传输扩大到以数据块为单位进行转输,大大地改善了块设备的 I/O 性能;
- 而通道的引入,又使对 I/O 操作的组织和数据的传送都能独立地进行而无需 CPU 干预。
程序 I/O 方式
早期的计算机系统中,由于在 CPU 中无中断机构,使 I/O 设备无法向 CPU 报告它已完成了一个字符的输入操作。处理机对 I/O 设备的控制采取程序 I/O(Programmed I/O)方式,或称为忙—等待方式。完成一个字(符)的 I/O 的过程:
- 处理机向控制器发出一条 I/O 指令启动输入设备输入数据时,同时把状态寄存器中的忙/闲标志 busy 置为 1,
- 不断地循环测试 busy。当 busy=1 时,表示输入机尚未输完一个字(符),处理机应继续测试,直至 busy=0,表明输入机已将输入数据送入控制器的数据寄存器中。
- 处理机将数据寄存器中的数据取出,送入内存指定单元中
由于 CPU 的高速性和 I/O 设备的低速性,致使 CPU 的绝大部分时间都处于等待 I/O 设备完成数据 I/O 的循环测试中,造成对 CPU 的极大浪费。
中断驱动
现代计算机系统中,都引入了中断机构,中断驱动(Interrupt Driven)方式的 I/O 设备控制被广泛采用:即当某进程要启动某个 I/O 设备工作时,便由 CPU 向相应的设备控制器发出一条 I/O 命令,然后立即返回继续执行原来的任务。设备控制器于是按照该命令的要求去控制指定 I/O 设备。此时,CPU 与 I/O 设备并行操作,直到设备控制器通过控制线向 CPU 发送一中断信号,由 CPU 检查输入过程中是否出错,若无错,便向控制器发送取走数据的信号,然后再通过控制器及数据线将数据写入内存指定单元中。
中断驱动方式可以极大提高 CPU 的利用率,例如:从终端输入一个字符的时间约为 100 ms,而将字符送入终端缓冲区的时间小于 0.1 ms。若采用程序 I/O 方式,CPU 约有 99.9 ms 的时间处于忙—等待的过程中。但采用中断驱动方式后,CPU 可利用这 99.9 ms 的时间去做其它的事情,而仅用 0.1 ms 的时间来处理由控制器发来的中断请求。
直接存储器访问
中断驱动 I/O 仍是以字(节)为单位进行 I/O的,每当完成一个字(节)的 I/O 时,控制器便要向 CPU 请求一次中断。 CPU 是以字(节)为单位进行干预的方式用于块设备的 I/O是极其低效的。例如,为了从磁盘中读出 1 KB 的数据块,需要中断 CPU 1K 次。为了 进一步减少 CPU 对 I/O 的干预而引入了直接存储器访问方式,该方式的特点是:
- 数据传输的基本单位是数据块,即在 CPU 与 I/O 设备之间,每次传送至少一个数据块;
- 所传送的数据是从设备直接送入内存的,或者相反;
- 仅在传送一个或多个数据块的开始和结束时,才需 CPU 干预,整块数据的传送是在控制器的控制下完成的。
DMA 控制器的组成
DMA 控制器由三部分组成:
- 主机与 DMA 控制器的接口: 为了实现在主机与控制器之间成块数据的直接交换,必须在 DMA 控制器中设置:
- 命令/状态寄存器(CR)。用于接收从 CPU 发来的 I/O 命令,或有关控制信息,或设备的状态。
- 内存地址寄存器(MAR)。在输入时,它存放把数据从设备传送到内存的起始目标地址;在输出时,它存放由内存到设备的内存源地址
- 数据寄存器(DR)。用于暂存从设备到内存,或从内存到设备的数据。
- 数据计数器(DC)。存放本次 CPU 要读或写的字(节)数。
- DMA 控制器与块设备的接口
- I/O 控制逻辑
DMA 工作过程
以从磁盘读入数据为例:
- CPU 向 DMA 控制器发送指令预置信息:
- 命令被送到其中的命令寄存器(CR)中
- 内存起始目标地址被送入内存地址寄存器(MAR)中
- 本次要读数据的字(节)数送入数据计数器(DC)中
- 磁盘中的源地址直接送至DMA 控制器的 I/O 控制逻辑上
- 启动 DMA 控制器进行数据传送,以后,CPU 便可去处理其它任务。当 DMA 控制器已从磁盘中读入一个字(节)的数据并送入数据寄存器(DR)后,再挪用一个存储器周期,将该字(节)传送到 MAR 所指示的内存单元中。接着便对 MAR 内容加 1,将 DC 内容减 1。若减 1 后 DC 内容不为 0,表示传送未完,便继续传送下一个字(节);否则,DMA 控制器发出中断请求。
“挪用一个存储器周期”指的是 DMA 控制器在将数据从 DR 传送到内存单元的过程中,需要占用一个原本属于 CPU 的存储器周期。
I/O 通道控制方式
I/O 通道设备的引入
DMA 方式中 CPU 每发出一条 I/O 指令,也只能去读(或写)一个连续的数据块。而当需要一次去读多个数据块并分别传送到不同的内存区域,或者相反时,则须由 CPU 分别发出多条 I/O 指令及进行多次中断处理才能完成。
I/O 通道(I/O Channel)方式可把CPU 的干预由对一个数据块的读写为单位的干预减少为对一组数据块的读写及有关的控制和管理为单位的干预。同时,又可实现 CPU、通道和 I/O 设备三者的并行操作,从而更有效地提高整个系统的资源利用率。
在 CPU 和设备控制器之间又增设通道,不仅使数据的传送能独立于 CPU,而且也使有关对 I/O 操作的组织、 管理及其结束处理尽量独立。实际上,I/O 通道是一种特殊的处理机,它具有执行 I/O 指令的能力,与 CPU 共享内存,通过执行通道(I/O)程序来控制 I/O 操作。 但 I/O 通道所能执行的指令类型主要局限于与 I/O 操作有关的指令。
例如,当 CPU 要完成一组相关的读(或写)操作及有关控制时,只需向 I/O 通道发送一条指令,以给出其所要执行的通道程序的首址和要访问的 I/O 设备,通道便可执行通道程序完成 CPU 指定的 I/O 任务,仅当完成了规定的任务后,才向 CPU 发中断信号。
通道程序
通道程序是由一系列通道指令(或称为通道命令)所构成的。通道指令与一般的机器指令不同,每条指令中都包含下列诸信息:
- 操作码:规定了指令所执行的操作,如读、写、控制等操作。
- 内存地址:标明字符送入内存(读操作)和从内存取出(写操作)时的内存首址。
- 计数:表示本条指令所要读(或写)数据的字节数。
- 通道程序结束位 P。用于表示通道程序是否结束。P=1 表示本条指令是通道程序的最后一条指令。
- 记录结束标志 R。R=0 表示本通道指令与下一条指令所处理的数据是同属于一个记录;R=1 表示这是处理某记录的最后一条指令。
示例:由六条通道指令所构成的简单的通道程序,用于是将内存中不同地址的数据写成多个记录。其中,前三条指令是分别将 813~892 单元中的 80 个字符和 1034~1173 单元中的 140 个字符及 5830~5889 单元中的 60 个字符写成一个记录;第 4条指令是单独写一个具有 300 个字符的记录;第 5、6 条指令共写含 500 个字符的记录。
操作 | P | R | 计数 | 内存地址 |
---|---|---|---|---|
WRITE | 0 | 0 | 80 | 813 |
WRITE | 0 | 0 | 140 | 1034 |
WRITE | 0 | 1 | 60 | 5830 |
WRITE | 0 | 1 | 300 | 2000 |
WRITE | 0 | 0 | 250 | 1650 |
WRITE | 1 | 1 | 250 | 2720 |
中断和中断处理程序
中断在操作系统中是多道程序得以实现的基础:因为进程之间的切换是通过中断来完成的;也是设备管理的基础,实现CPU与I/O设备并行执行也必须有中断的支持。
中断简介
中断 是指CPU对io设备发来的中断信号的1种响应。 CPU暂停正在执行的程序。保留CPU环境后,自动的去执行该io设备的中断处理程序。执行完后,再回到断点继续执行原来的程序。由于中断是由外部设备引起的,故又称外中断。
陷入:还有1种由CPU内部事件引起的中断。例如在运算中发生的上溢或下溢。又如程序出错。如非法指令地址越界以及电源故障等。通常把这类中断称为内中断或陷入。
todo
中断向量表和中断优先级
- 中断向量表。通常会为每种设备配以相应的中断处理程序,并把入口地址放在中断向量表的一个表项中,为每个设备的中断请求规定一个中断号,它直接对应中断向量表的一个表项。当I/O设备发来中断请求信号时,由中断控制器确定该请求的中断号,并根据该中断号查找中断向量表,从中取得该设备相应的中断处理程序的入口地址,转入中断处理程序并执行。
- 中断优先级。多个中断信号源当中每一个对服务要求的紧急程度并不相同,例如,键盘的中断请求的紧急程度不如打印机,而打印机的中断请求的紧急程度又不如磁盘等。为此,系统就需要为它们分别规定不同的优先级。
处理多中断信号源的方式
当处理机正在处理一个中断时,又来了一个新的中断请求,这时应该如何处理?例如,当系统正在处理打印机中断时,又收到了优先级更高的磁盘中断信号。可采用以下两种处理方式。
屏蔽(禁止)中断
处理一个中断时,将“屏蔽”掉所有的中断,即处理机对任何新到的中断请求都暂时不予理睬,直到完成本次中断的处理后,才去检查是否有新的中断发生。若有,再去处理新的中断;若无,则返回被中断的程序。在该方法中,所有中断都将按顺序排队依次被处理。其优点是简单,但不能用于对实时性要求较高的中断请求。
嵌套中断
在设置了中断优先级的系统中,通常按以下规则来控制优先级:
- CPU优先响应最高优先级的中断请求;
- 高优先级的中断请求可以抢占正在运行的低优先级中断的处理机,类似于基于优先级的抢占式进程调度。例如,处理机正在处理打印机中断,当有磁盘中断到来时,可暂停对打印机中断的处理而转去处理磁盘中断。
中断处理程序
当一个进程请求I/O操作时,被挂起后,I/O设备完成I/O操作后,设备控制器会向CPU发送一中断请求,CPU响应后便转向中断处理程序,执行相应的处理后解除相应进程的阻塞状态。中断处理程序的处理过程可分成以下几个步骤:
1.测定是否有未响应的中断信号:每当设备完成一个字符(字或数据块)的读入(或输出),设备控制器便会向CPU发送一中断请求信号,请求CPU将设备已读入的数据传送到内存的缓冲区中(读入),或者请求CPU 将要输出的数据传送给设备控制器(输出)。程序每当执行完当前指令后,CPU都要测试是否有未响应的中断信号。若有,则停止原有进程的执行,准备转去执行中断处理程序。
2.保护被中断进程的 CPU 现场环境:在把控制权转交给中断处理程序之前,需要先保护被中断进程的CPU现场环境。
- 恢复进程运行所需要的信息通常由硬件自动将处理机状态字(processor status word,PSW)和保存在程序计数器(program counter,PC) 中下一条指令的地址,保存在中断保留区(中断栈)中。
- 被中断进程的CPU现场信息,即所有CPU寄存器(如通用寄存器、段寄存器等)的内容,都压入中断栈中,因为在处理中断时可能会用到这些寄存器。假如用户程序是指令在N位置时被中断的,程序计数器中的内容为N+1,所有寄存器的内容都被保留在中断栈中
3.转入相应设备的中断处理程序:CPU 对各个中断信号源进行测试以确定引起中断的设备,并向其发送确认信号。在设备收到确认信号后立即取消它所发出的中断请求信号,然后将相应设备的中断处理程序的入口地址装入程序计数器中。这样,当CPU运行时,便可自动转入相应设备的中断处理程序。
4.处理中断:中断处理程序首先会从设备控制器中读出设备状态,以 判别是正常完成中断还是异常结束中断。若是正常完成中断,便做结束处理:假如是字符设备的读操作,则表明设备已经读入了一个字节 (字)的数据,并已放入数据寄存器中。此时中断处理程序应将该数据传送给CPU,再将它存入缓冲区中,并修改相应的缓冲区指针,使其指向下一个内存单元。再向设备控制器发送新的命令,进行新一轮的数据传送。若是异常结束中断,则根据发生异常的原因做相应的处理
5.恢复 CPU 现场环境后退出中断:需要恢复CPU现场并退出中断。但是,此刻是否返回被中断的进 程,取决于两个因素:①本中断是否采用了屏蔽(禁止)中断驱动 I/O方式,若是,则返回被中断的进程;②针对中断处理方式为中断嵌套方式的情况,如果有优先级更高的中断来请求I/O, 系统将处理优先级更高的中断请求。 如果要返回到被中断的进程,则可将保存在中断栈中的被中断进程的CPU现场信息取出, 并装入相应的寄存器中,其中包括该程序下一次要执行的指令的地址N+1、处理机状态字以及各 通用寄存器和段寄存器的内容。这样,当CPU再执行本程序时,便会从N+1处开始,最终返回被中断的进程。 I/O操作完成后,驱动程序必须检查本次I/O操作中是否发生了错误,并向上层软件报告,最 终向调用者报告本次I/O的执行情况。
除了上述的第4步(处理中断)外,其他步骤对所有I/O设备都是相同的,因而对于某种OS,如UNIX系统,其会把这些共同的部分集中起来,形成中断总控程序。每当要进行中断处理时,都要首先进入中断总控程序。而对于第4步,则对不同设备须采用不同的中断处理程序继续执行。
设备驱动程序
设备驱动程序通常又称为设备处理程序,它是 I/O 进程与设备控制器之间的通信程序,其主要任务是接收上层 软件发来的抽象 I/O 要求,如 read 或 write 命令,在把它转换为具体要求后,发送给设备控制器,启动设备去执行它也将由设备控制器发来的信号传送给上层软件。
有时可为非常类似的两类设备配置一个驱动程序。例如,打印机和显示器需要不同的驱动程序,但 SCSI 磁盘驱动程序通常可以处理不同大小和不同速度的多个 SCSI 磁盘,甚至还可以处理 SCSI CD-ROM。
设备驱动程序概述
设备驱动程序的功能
- 接收由设备独立性软件发来的命令和参数,并将命令中的抽象要求转换为具体要求,例如,将磁盘块号转换为磁盘的盘面、磁道号及扇区号。
- 检查用户 I/O 请求的合法性,了解 I/O 设备的状态,传递有关参数,设置设备的工作方式。
- 发出 I/O 命令。如果设备空闲,便立即启动 I/O 设备去完成指定的 I/O 操作;如果设备处于忙碌状态,则将请求者的请求块挂在设备队列上等待。
- 及时响应由控制器发来的中断请求,并根据其中断类型调用相应的中断处理程序进行处理。
设备驱动程序的特点
设备驱动程序属于低级的系统例程,与一般的应用程序及系统程序之间的差异:
- 主要是指在请求 I/O 的进程与设备控制器之间的一个通信和转换程序。它将进程的 I/O 请求经过转换后,传送给控制器;又把设备状态和 I/O 操作完成情况及时地反映给进程。
- 与设备控制器和 I/O 设备的硬件特性紧密相关,因而对不同类型的设备应配置不同的驱动程序。例如,可以为相同的多个终端设置一个终端驱动程序。
- 与 I/O 设备所采用的 I/O 控制方式紧密相关。 例如DMA 方式驱动程序应按数组方式启动设备及进行中断处理。
- 由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言书写。目前有很多驱动程序的基本部分,已经固化在 ROM 中。
- 应允许可重入。正在运行的驱动程序常会在一次调用完成前被再次调用,例如,网络驱动程序正在处理一个到来的数据包时,另一个数据包可能到达。
设备处理方式
设备处理方式:在不同的操作系统中所采用的设备处理方式可以分成以下三类:
- 为每一类设备设置一个进程,专门用于执行这类设备的 I/O 操作。比如,为所有的交互式终端设置一个交互式终端进程;又如,为同一类型的打印机设置一个打印进程。
- 在整个系统中设置专门的 I/O 进程用于执行所有各类设备的 I/O 操作。 也可以设置一个输入进程和一个输出进程,分别处理输入或输出操作。
- 不设置专门的设备处理进程,而只为各类设备设置相应的设备处理程序(模块),供用户进程或系统进程调用。
设备驱动程序的处理过程
不同的设备驱动程序大体上都可以分成两部分,其中除了要有能够驱动 I/O 设备工作的驱动程序外,还需要有设备中断处理程序,以处理 I/O 完 成后的工作。
设备驱动程序的主要任务是启动指定设备。但在启动之前,还必须完成必要的准备工作,如检测设备状态是否为“忙”等。在完成所有的准备工作后,才最后向设备控制器发送一条启动命令。
- 将抽象要求转换为具体要求:通常在每个设备控制器中都含有若干个寄存器,分别用于暂存命令、数据和参数等。 用户及上层软件对设备控制器的具体情况毫无了解,因而只能向它发出抽象的要求(命 令),但这些命令无法传送给设备控制器。因此,就需要将这些抽象要求转换为具体要求。 因为在 OS 中只有驱动程序才同时了解抽象要求和设备控制器中的寄存器情况;也只有它才知道命令、 数据和参数应分别送往哪个寄存器。
- 检查 I/O 请求的合法性。若该设备不支持这次的 I/O 请求, 则认为这次 I/O 请求非法。例如,用户试图请求从打印机输入数据,显然系统应予以拒绝。 此外,还有些设备如磁盘和终端,它们虽然都是既可读又可写的,但若在打开这些设备时规定的是读,则用户的写请求必然被拒绝。
- 检查设备的状态:在启动设备之前,要从设备控制器的状态寄存器中,读出设备的状态。例如,为了向某设备写入 数据,此前应先检查该设备是否处于接收就绪状态,是则启动其设备控制器,否则等待。
- 传送必要的参数:例如在启动磁盘进行读/写之前,应先将本次要传送的字节数和数据应到达的主存始址,送入控制器的相应寄存器中,例如,典型情况是利用 RS-232 接口进行异步通信前,应先按通信规程设定参数:波特率、奇偶校验方式、停止位数目及数据字节长 度等
- 启动 I/O 设备。驱动程序可以向控制器中的命令寄存器传送相应的控 制命令。对于字符设备,若发出的是写命令,驱动程序将把一个数据传送给控制器;若发出的是读命令,则驱动程序等待接收数据,并通过从控制器中的状态寄存器读入状态字的方法,来确定数据是否到达。
驱动程序发出 I/O 命令后,基本的 I/O 操作是在设备控制器的控制下进行的。通常,I/O 操作所要完成的工作较多,需要一定的时间,如读/写一个盘块中的数据,此时驱动(程序) 进程把自己阻塞起来,直到中断到来时才将它唤醒。
设备独立性软件
设备分配
数据结构
- **设备控制表(DCT)**用于记录本设备的情况:
属性 | 描述 |
---|---|
设备类型 | type |
设备标识符 | deviceid |
设备状态 | 忙/闲。当设备自身正处于使用状态时,应将设备的忙/闲标志置“1”。若与该设备相连接的控制器或通道正忙,也不能启动该设备,此时则应将设备的等待标志置“1”。 |
指向控制器表的指针 | 在设备到主机之间具有多条通路的情况下,一个设备将与多个控制器相连接。此时,在 DCT 中还应设置多个控制器表指针。 |
重复执行次数或时间 | 由于外部设备在传送数据时,较易发生数据传送错误,如果发生传送错误,并不立即认为传送失败,而是令它重新传送:由系统规定重复执行次数,仅当屡次失败次数达到规定值而传送仍不成功时,才认为传送失败。 |
设备队列的队首指针 | 凡因请求本设备而未得到满足的进程,其 PCB 都应按照一定的策略排成一个队列,称该队列为设备请求队列或简称设备队列。在有的系统中还设置了队尾指针。 |
- 控制器控制表(COCT),和 通道控制表(CHCT)。
COCT | CHCT |
---|---|
标识符controllerid | 标识符 channelid |
状态忙/闲 | 状态忙/闲忙/闲 |
与控制器连接的通道表指针 | 与通道连接的控制器表首址 |
控制器队列的队首指针 | 通道队列的队首指针 |
控制器队列的队尾指针 | 通道队列的队尾指针 |
- 系统设备表(SDT),是系统范围的数据结构,其中记录了系统中全部设备的情况。每个设备占一个表目,字段有
设备类 |
---|
设备标识符 |
DCT |
驱动程序入口 |
应考虑因素
设备的固有属性
在分配设备时,首先应考虑与设备分配有关的设备属性,对独占、共享、可虚拟三种设备应采取不同的分配策略。。
- 独占性,是指这种设备在一段时间内只允许一个进程独占,应采用独享分配策略,即将一个设备分配给某进程后, 便由该进程独占,直至该进程完成或释放该设备,然后,系统才能再将该设备分配给其他 进程使用。这种分配策略的缺点是,设备得不到充分利用,而且还可能引起死锁。
- 共享性,指这种设备允许多个进程同时共享;可同时分配给多个进程使用,此时须注意对这些进程访 问该设备的先后次序进行合理的调度。
- 可虚拟设备,指设备本身虽是独占设备,但经过某种技术处理,可以把它改造成虚拟设备。由于可虚拟设备是指一台物理设备在采用虚拟技术后,可变成多台逻辑上的所谓虚拟设备,因而说,一台可虚拟设备是可共享的设备,可以将它同时分配给多 个进程使用,并对这些访问该(物理)设备的先后次序进行控制。
设备分配算法
对设备进行分配的算法,与进程调度的算法有些相似之处,但前者相对简单,通常只采用以下两种分配算法:
- 先来先服务。当有多个进程对同一设备提出 I/O 请求时,该算法是根据诸进程对某 设备提出请求的先后次序,将这些进程排成一个设备请求队列,设备分配程序总是把设备 首先分配给队首进程。
- 优先级高者优先。对这高优先权进程所提出的 I/O 请求也赋予高优先权,显然有助于这种进程尽快完 成。在利用该算法形成设备队列时,将优先权高的进程排在设备队列前面,而对于优先级相同,则按先来先服务原则排队。
设备分配中的安全性
从进程运行的安全性考虑,设备分配有以下两种方式:
- 安全分配方式:每当进程发出 I/O 请求后,便进入阻塞状态,直到其 I/O 操作完成时才被唤醒。在采用这种分配策略时,一旦进程已经获得某种设备(资源)后便阻塞,使该进程不可能再请求任何资源,而在它运行时又不保持任何资源。因此,这种分配方式已经摒弃了造成死锁的四个必要条件之一的“请求和保持”条件,从而使设备分配是安全的。其缺点是进程进展缓慢,即 CPU 与 I/O 设备是串行工作的。
- 不安全分配方式:进程在发出 I/O 请求后仍继续运行,需要时又发出第二个 I/O 请求、第三个 I/O 请求等。仅当进程所请求的设备已被另一进程占用时,请求进程才进入阻塞状态。这种分配方式的优点是,一个进程可同时操作多个设备,使进程推进迅速。其缺点是分配不安全,可能造成死锁。因此,在设备分配程序中,还应对本次的设备分配是否会发生死锁进行安全性计算,仅当计算结果说明分配是安全的情况下才进行设备分配。
独占设备的分配程序
基本的设备分配程序
一个具有 I/O 通道的系统案例:当某进程提出 I/O 请求后,只有在设备、 控制器和通道三者都分配成功时,设备分配才算成功。然后,便可启动该 I/O 设备进行数据传送。
- 分配设备:首先根据 I/O 请求中的物理设备名,查找系统设备表(SDT),从中找出该设备的 DCT, 再根据 DCT 中的设备状态字段,可知该设备是否正忙。若忙,便将请求 I/O 进程的 PCB 挂在设备队列上;否则,便按照一定的算法来计算本次设备分配的安全性。如果不会导致系统进入不安全状态,便将设备分配给请求进程;否则,仍将其 PCB 插入设备等待队列。
- 分配控制器:到设备 DCT 中找出与该设备连接的控制器的 COCT,判断控制器是否忙碌。若忙,便将请求 I/O 进程的 PCB 挂在该控制器的等待队列上;否则,便将该控制器分配给进程。
- 分配通道:在该 COCT 中又可找到与该控制器连接的通道的 CHCT,判断通道是否忙碌。若忙,便将请求 I/O 的进程挂在该通道的等待队列上;否则,将该通道分配给进程。
设备分配程序的改进
上述基本的设备分配程序可以从以下两方面加以改进,以使独占设备的分配程序具有更强的灵活性,并提高分配的成功率:
- 进程是以物理设备名来提出 I/O 请求的;为此需要增加设备的独立性,进程应使用逻辑设备名请求 I/O。这样,系统首先从 SDT 中找出第一个该类设备的 DCT。若该设备忙,又查找第二个该类设备的 DCT,仅当所有该类设备都忙时,才把进程挂在该类设备的等待队列上;而只要有一个该类设备可用,系统便进一步计算分配该设备的安全性。
- 采用的是单通路的 I/O 系统结构,容易产生“瓶颈”现象。为此,应采用多通路的 I/O 系统结构。此时对控制器和通道的分配同样要经过几次反复,即若设备(控制器)所连接的第一个控制器(通道)忙时,应查看其所连接的第二个控制器(通道),仅当所有的控制器(通道)都忙时,此次的控制器(通道)分配才算失败,才把进程挂在控制器(通道)的等待队列上。而只要有一个控制器(通道)可用,系统便可将它分配给进程。
用户层的 IO 软件
大部分的 IO 软件都放在操作系统内部,但仍有一小部分在用户层,运行在内核之外,们仍属于I/O系统。包括
- 与用户程序链接在一起的库函数
- 完全运行与内核之外的假脱机系统。
- 在网络传输文件时常使用的守护进程。
系统调用与库函数
系统调用
运行在用户端的应用进程不被允许直接调用运行在核心态的 OS 过程, 应用程序可以通过用户层中的中介过程——系统调用来间接调用 OS 中的 I/O 过程,对 I/O 设备进行操作。当 OS 捕获到应用程序中的该系统调用后,便将 CPU 的状态从用户态转换到核心态,然后转向操作系统中相应过程,由该过程完成所需的 I/O 操作,系统再将 CPU 状态从核心态转换到用户态,返回应用程序继续执行。
早期的操作中,系统调用是以汇编语言形式提供的,后来在 C 语言中首先提供了与系统调用相对应的库函数。
在许多现代OS中,系统调用本身已经采用C语言编写,并以函数形式提供,所以在使用C语言编写的用户程序中,可以直接使用这些系统调用。
库函数
在 C 语言以及 Unix 系统中系统调用与各系统调用所使用的库函数之间几乎是一一对应的。而微软定义的称为 Win32 API的应用程序接口(Application Program Interface),与实际的系统调用并不一一对应。
用户程序通过调用对应的库函数使用系统调用,库函数与调用程序链接在一起,被嵌入在运行时装入内存的二进制程序中。C 语言中提供了多种类型的库函数,I/O方面,主要是对文件和设备进行读写的库函数,以及控制/检查设备状态的库函数。这些库函数的集合也应是I/O系统的组成部分。
内核和库函数之间的关系:内核提供了OS的基本功能,而库函数扩展了OS内核,使用户能方便取得操作系统的服务。
假脱机系统
- 通过多道程序技术,可将一台物理 CPU 虚拟为多台 CPU,从而允许多个用户共享一台主机。
- 通过 SPOOLing 技术可将一台物理 I/O 设备虚拟为多台逻辑 I/O 设备,允许多个用户共享一台物理 I/O 设备。
20世纪50年代,为了缓和 CPU 的高速性与 I/O 设备低速性间的矛盾而引入了脱机输入、输出技术,利用专门的外围控制机,将低速 I/O 设备上的数据传送到高速磁盘上;或者相反。—— 用磁带机替换速度慢的卡片阅读器(输入设备)和行式打印机(输出设备)。
引入多道程序技术后,可以利用其中的两道程序,来分别模拟脱机输入和脱机输出时的外围控制机功能,实现主机的直接控制下的脱机输入、输出。此时的外围操作与 CPU 对数据的处理同时进行,这种在联机情况下实现的同时外围操作称为 SPOOLing(Simultaneaus Periphernal Operating On Line),或称为假脱机操作。SPOOLing 系统必须建立在具有多道程序功能的操作系统上,而且还应有高速随机外存的支持(通常采用磁盘存储技术)。
主要组成部分
- 输入井和输出井:在磁盘上开辟的两个大存储空间。分别模拟脱机输入和输出时的磁盘设备,用于暂存 I/O 设备输入的数据和用户程序的输出数据。
- 输入缓冲区和输出缓冲区。为了缓和 CPU 和磁盘之间速度不匹配的矛盾,在内存中要开辟输入缓冲区和输出缓冲区。用于暂存由输入设备到输入井,或输出井到输出设备的数据。
- 输入进程和输出进程 。这里利用两个进程来模拟脱机 I/O 时的外围控制机。输入进程将数据从输入机通过输入缓冲区再送到输入井,当 CPU 需要输入数据时,直接从输入井读入内存;输出进程把要输出的数据先从内存送到输出井,待输出设备空闲时,再将输出井中的数据经过输出缓冲区送到输出设备上。
优点
- 👍提高了 I/O 的速度。 从对低速设备进行的 I/O 操作,演变为对输入井或输出井中数据的存取,缓和了 CPU 与低速 I/O 设备之间速度不匹配的矛盾。
- 👍将独占设备改造为共享设备。实际上并没为任何进程分配设备,而只是在输入井或输出井中为进程分配一个存储区和建立一张 I/O 请求表。这样便把独占设备改造为共享设备。
- 👍实现了虚拟设备功能。宏观上多个进程在同时使用一台独占设备,而每一个进程会认为自己是独占了一个设备。实现了将独占设备变换为若干台对应的逻辑设备的功能。
tldr
spooling:为避免独占设备忙而设置的缓存。思路:CPU把活交给外围控制机(输出进程),先存磁带(磁盘)上。这样就不管卡带机(打印机)忙不忙, DMA 虽然也是相当于脱机,不用 CPU 管,但是当设备忙的时候就没办法了,于是需要一个更大层面的缓存,这个就是 Spool
共享打印机
打印机是独占设备输出设备。利用 SPOOLing 技术,可将之改造为一台可供多个用户共享的设备,从而提高设备的利用率,也方便了用户。共享打印机技术已被广泛地用于多用户系统和局域网络中。假脱机打印系统主要有以下三部分:磁盘缓冲区、打印缓冲区(内存中)假脱机管理进程和假脱机打印进程。
当用户进程请求打印输出时:
- SPOOLing 系统同意为它打印输出,但并不真正把打印机分配给用户进程,而只是由假脱机管理进程为它做两件事:
- 在输出井中为之申请一个空闲磁盘块区,并将要打印的数据送入其中;
- 申请空白的用户请求打印表,并将打印要求填入表中,挂到假脱机文件队列上。
- 打印机空闲时,从假脱机文件队列的队首取出一张请求打印表,从输出井传送到内存缓冲区,再由打印机进行打印。
- 一个打印任务完成后,假脱机打印进程再取出队列中的第一张表,进行打印,直至请求打印队列为空。
- 假脱机打印进程才将自己阻塞起来。仅当下次再有打印请求时,假脱机打印进程才被唤醒。
总结:系统并非即时执行真实打印操作,而只是即时将数据输出到缓冲区,让用户感觉系统已为他打印;真正的打印操作在打印机空闲且该打印任务在等待队列中已排到队首时进行;打印操作本身也是利用CPU的一个时间片(多道),没有使用专门的外围机;以上的过程是对用户屏蔽的。
守护进程
假脱机管理进程的部分功能可以改由守护进程执行:如在磁盘缓冲区中申请空闲盘块,并送入将要打印的数据,将该盘块的首址返回给请求进程。另一部分由请求进程自己完成:进程首先生成一份要求打印的文件,其中包含对打印的要求和指向装有打印输出数据盘块的指针等信息,然后将用户请求打印文件放入假脱机文件队列(目录)中。
守护进程是允许使用打印机的唯一进程。所有需要使用打印机进行打印的进程都需将一份要求打印的文件放在假脱机文件队列(目录)中。如果守护进程正在睡眠,便将它唤醒,由它按照目录中第一个文件中的说明进行打印,逐份文件地进行打印,直到全部文件打印完毕,守护进程无事可做,又去睡眠。等待用户进程再次发来打印请求。
除了打印机守护进程之外,还可能有许多其它的守护进程,如服务器守护进程和网络守护进程等。事实上,凡是需要将独占设备改造为可供多个进程共享的设备时,都要为该设备配置一个守护进程和一个假脱机文件队列(目录)。同样,守护进程是允许使用该独占设备的唯一进程,所有其它进程只能将对该设备的使用要求写入一份文件中,放在假脱机目录中。由守护进程按照目录中的文件依次来完成诸进程对该设备的请求。
缓冲区管理
单缓冲和双缓冲
单缓冲区
每当用户进程发出一 I/O 请求时,操作系统便在主存中为之分配一缓冲区。在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为 T,操作系统将该缓冲区中的数据传送到用户区的时间为 M,而 CPU 对这一块数据处理(计算)的时间为 C。由于 T 和 C 是可以并行的,系统对每一块数据的处理时间表示为 Max(C,T)+M。
双缓冲区
为加快 I/O 速度,提高设备利用率,又引入了双缓冲区机制,也称为缓冲对换(Buffer Swapping)。
缓冲区是临界资源,取和送必须互斥,若消费者尚未取走缓冲区中的数据,即使时生产者又生产出新的数据也无法送入,设置两个缓冲区就能解决这个问题。
设备输入时,先将数据送入第一缓冲区,装满后转向第二缓冲区,同时操作系统从第一缓冲区中移出数据送入用户进程。对于字符设备,用户在输入完第一行后,可继续向第二缓冲区输入下一行数据。
系统处理一块数据的时间可以粗略认为是 Max(C, T)
设备控制器可以存在于设备本身或计算机内部。在一些情况下,设备控制器是集成在设备内部的芯片或模块中,负责管理设备的操作和通信。这种设计通常适用于一些独立设备,如打印机、扫描仪等。 另一种情况是设备控制器位于主板上,作为主板的一部分,负责管理多个设备的控制和通信。这种设计常见于计算机系统中,主板上的控制器可以管理多个设备,如硬盘驱动器、光驱、网卡等。