[操作系统] I/O软件原理

来源:互联网 发布:sql去除查询结果重复行 编辑:程序博客网 时间:2024/06/16 05:11

I/O软件原理


  • IO软件原理
    • IO软件的目标
    • IO实现方式
    • IO软件层次
      • 1 中断处理程序
      • 2 设备驱动程序
      • 3 与设备无关的IO软件
      • 4 用户空间的IO软件


1. I/O软件的目标

  1. 设备独立性
    I/O软件的目标是实现设备独立性,即可以访问任意I/O设备而无需为每一种设备修改程序。

  2. 统一命名
    与设备独立性相关的是被称为统一命名的目标,即一个文件或一个设备的名字应该是一个简单的字符串或整数,而不依赖于设备。使用这种方法,所有文件和设备都可以采用路径名进行寻址。

  3. 错误处理
    一般来说,错误尽可能的在接近硬件的低级层面进行处理,只有当低层解决不了时,才上交高层处理。

  4. 同步和异步
    同步即阻塞,异步即中断驱动。大部分I/O是异步的,CPU启动传输后便转去做其他工作,直到中断发生。

  5. 缓冲
    数据离开一个设备之后通常不能直接被存放到最终目的地。因为有些数据需要被检查,有些设备对数据有实时约束。

  6. 共享设备和独占设备
    有些设备可以同时被多个用户使用,而有些设备只能被一个用户单独使用。

2. I/O实现方式

I/O可以用三种方式实现:程序控制I/O,中断驱动I/O,DMA实现I/O。

  1. 程序控制I/O

    I/O最简单的形式,即让CPU做全部工作,这一方法称为程序控制I/O。

    例如,一个用户进程想要在打印机上打印字符串“ABCD”。首先,该进程将字符串添加到用户空间的一个缓冲区中。然后发出系统调用获得打印机。如果当前打印机正在被使用,该系统调用将被阻塞,或返回一个错误码。当获得打印机后,用户进程发出另一个系统调用通知操作系统打印字符串。

    操作系统需要将字符串从缓冲区中复制到内核,然后检查打印机是否可用。如果不可用就需要等待直到可用,操作系统激活打印机,并将第一个字符“A”复制到打印机寄存器,然后打印机将A打印,并且系统将“B”标记为下一个待打印字符。这时,操作系统需要查看打印机是否就绪接收下一个字符。如果已就绪,就接着打印“B”,如果未就绪,就需要等待直到打印机就绪。重复上述过程,直到打印完整个字符串,然后返回用户进程。

    在该方法中,CPU在输出一个字符后,需要不断地查询打印机以了解是否就绪接收下一个字符,这一行为称为忙等待。所以这个方法的缺点很明显,必须等到全部I/O完成后,CPU才可以做别的事。

  2. 中断驱动I/O

    允许CPU在等待设备变为就绪的同时做其他事情的方式即为使用中断。

    例如,当打印字符串的系统调用发生时,字符串缓冲区被复制到内核,当打印机准备好接收第一个字符”A“时,将“A”复制到打印机中。

    这一方法的缺点是中断发生在每个字符上,中断本身也会花费时间,这一方法CPU将浪费处理这些中断所花费的时间。

  3. 使用DMA的I/O

    让DMA控制器一次给打印机提供一个字符,而不再是CPU提供。这一方法与程序控制I/O本质是一样的,只不过使用DMA控制器替代了CPU而已,从而CPU在I/O期间可以做其他的工作。DMA将打断CPU的次数从每个字符一次减少到打印每个缓冲区一次。

    这个方法的缺点是DMA本身运行的速度要比CPU慢,而且需要DMA控制器这一硬件的支持。

3. I/O软件层次

I/O软件通常分为4个层次,从上往下依次是:用户级I/O软件、与设备无关的I/O软件、设备驱动程序、中断处理程序。

        I/O软件层次

3.1 中断处理程序

为了避免一个I/O的中断对其他部分造成影响,需要将中断隐藏在操作系统内部。最好的方法是将启动一个I/O操作的驱动程序阻塞起来,直到I/O操作完成并且产生一个中断时,中断处理程序对其进行处理,然后为驱动程序解除阻塞。大致的步骤如下:

  1. 保存没有被中断硬件保存的所有寄存器。
  2. 为中断服务过程设置上下文,可能包括设置TLB、MMU和页表。
  3. 为中断服务过程设置堆栈。
  4. 应答中断控制器,如果不存在集中的中断控制器,则再次开放中断。
  5. 将寄存器从它们被保存的地方复制到进程表中。
  6. 运行中断服务过程,从发出中断的设备控制器的寄存器提取信息。
  7. 选择下一次运行哪一个进程,如果中断导致某个被阻塞的高优先级进程变为就绪,可能选择它现在就运行。
  8. 为下一次要运行的进程设置上下文。
  9. 装入新进程的寄存器。
  10. 开始运行新进程。

3.2 设备驱动程序

每一个设备控制器都设有设备寄存器以此来向设备发出命令,或用来读出设备状态,或者两者都有。不同的设备寄存器所需要的命令在不同设备上有着根本的不同。

因此,每个I/O设备都需要它特定的代码对其进行控制,这样的代码就称为设备驱动程序。

为了访问设备的硬件(即设备控制器的寄存器),大部分操作系统将驱动程序作为内核的一部分。也有少部分系统将驱动程序运行在用户空间,通过使用程序调用与设备控制器进行通信,这一设计可以使内核与驱动程序、驱动程序与驱动程序相互隔离,已消除对内核的干扰。

通常,操作系统将驱动程序归类为块设备和字符设备,并为它们分别提供了标准的接口。通过这些接口,操作系统的其余部分可以调用设备驱动程序进行工作。

设备驱动程序具有的功能:

  1. 接收来自其上方的设备无关软件发出的抽象的读写请求。
  2. 检查输入参数是否有效。
  3. 将有效的抽象的请求转化为实际的具体事项,如查找扇区,磁道。
  4. 检查当前设备是否正在使用,以及请求是否能够得到处理。
  5. 控制设备,即通过检查设备控制器的寄存器是否就绪,并将命令写入设备控制器的寄存器,从而向设备发出一系列命令。
  6. 阻塞自身,等待控制器完成任务直到中断到来解除阻塞。或操作无延迟完成,不需要阻塞。
  7. 操作完成后,驱动程序检查错误。如果顺利,则将数据传送给设备无关软件。
  8. 向调用者返回一些用于错误报告的状态信息。
  9. 如果有其他未完成的请求在排队,则选择一个启动执行,否则驱动程序阻塞自身以等待下一个请求。

注意:

当一个驱动程序正在运行时,某个I/O设备可能会完成操作并中断驱动程序。中断可能会导致当前驱动程序运行,因此驱动程序必须是可重入的。

多数操作系统中,设备可以在运行时添加或删除。因此,当一个驱动程序正忙于从某个设备读数据时,可能该设备突然被移除了。这时,当前I/O传送必须中止并且不能破坏任何核心数据结构,而且任何对于这个消失设备的未完成的请求也必须被删除。

3.3 与设备无关的I/O软件

与设备无关的软件的基本功能是执行对所有设备公共的I/O功能,并且向用户层软件提供一个统一的接口。为了实现这个目标,与设备无关的I/O软件主要有5个作用。

  1. 设备驱动程序的统一接口

    为不同的驱动程序接口统一为一个统一的标准的接口。对于某一种设备类型,操作系统定义一组驱动程序必须支持的函数。驱动程序通常包含一张表格,这张表格具有针对这些函数指向驱动程序自身的指针。当操作系统需要调用一个函数时,它可以通过这张表间接调用,这张函数指针表定义了驱动程序与操作系统其余部分之间的接口。

    与设备无关的软件还要负责把符号化的设备名映射到适当的驱动程序上。例如,在UNIX中设备名/dev/disk0可以确定一个特殊文件的i节点,i节点包含了主设备号(用于定位相应的驱动程序)和次设备号(用来确定要读写的具体设备)。

  2. 缓冲

    当用户进程从设备读数据时,如果执行read调用并阻塞自己,那么每个字符的到来都会引起一次中断。为了减少中断次数,用户进程在用户空间提供一个包含n个字的缓冲区,并且执行读入n个字符的读操作。当缓冲区填满时才会引发中断,唤醒用户进程。

    这种方法的缺点是:为了避免在字符到来时将缓冲区换出。要使用一种方法将缓冲区锁定在内存中,但是如果许多进程都在内存中锁定页面或影响性能。

    另一种解决的方法是在内核空间中创建一个缓冲区并且让中断处理程序将字符放到缓冲区中,当缓冲区被填满时,将包含用户缓冲区的页面调入内存。但是同样的,有可能将缓冲区调入内存时又有新的字符到来。就需要用两个缓冲区交换使用,这种机制称为双缓冲。或者是使用循环缓冲区,它由一个内存区域和两个指针组成,一个指针指向下一个空闲区域,一个指针指向缓冲区第一个尚未被取走的字。

  3. 错误报告

    当错误发生时,操作系统必须尽最大努力对它们进行处理。与设备无关的软件要做的就是识别出错误的类型并作出反馈。

  4. 分配与释放专用设备

    有些设备在一个时刻只能被一个进程使用,这就要求操作系统对设备使用的请求进行检查。

  5. 与设备无关的块大小

    不同的磁盘可能具有不同的扇区大小,与设备无关软件应该负责隐藏这一事实,并向高层提供一个统一的块大小。这样高层只需要处理抽象的设备。例如,对于磁盘扇区使用逻辑块而不是物理块、通过以不同的单位向不同大小的设备传输数据,这些差异也可以被隐藏起来。

3.4 用户空间的I/O软件

假脱机系统,库过程等。


参考书目:现代操作系统第三版