操作系统哲学原理(19) I/O原理-输入输出

说明:该系类文章更多的是从从哲学视角看 操作系统 这门学科。同时也是 操作系统的学习笔记总结。因为博主 这些年主要是以研究安卓系统和 嵌入式Linux为主,因此这个系类文章也是这两个领域不可或缺的基石之一,尤其是对操作系统感兴趣的伙伴可特别关注。


19 输入输出

19.1 输入输出

计算机与人进行沟通的这种机制就是输入输出的机制。

  • 输入:人->计算机
  • 输出:计算机->人

对于操作系统而言,需要关注的问题是:

  • 输入输出的目的
  • 怎样实现输入输出的功能

19.2 输入输出的目的

简单来讲,就是人与计算机进行沟通,但是从更高的层次来看,输入输出设备的目的有两个:

  • 屏蔽输入输出设备的差异性
  • 在不同设计之间进行数据表示的转换

达到上述需要的机制,仿照我们前面的模式,是:设备独立与设备保护。

  • 设备独立:输入输出不以设备的不同为转移,即不管输人输出设备是否更好或更新,我们进行输人输出的模式和方法保持不变。
  • 设备保护:一个输入输出设备的操作不会影响另一个输入输出设备的操作。

那么要想实现设备独立和设备保护,我们需要从硬件和软件两个方面出发进行考虑:

  • 硬件层面的输入输出;
  • 软件层面的输入输出;

19.3 I/O硬件

从操作系统设计人员/程序员的角度来看输入输出设备,主要分为两类:块设备和字符设备;这种划分是以设备存储和传输数据的方式来决定。

  • 块设备:以数据块为单位进行存储和传输数据的输入输出设备。是可以寻址的。
  • 字符设备:以字符为单位进行存储和传输数据的输入输出设备。是不可以寻址的。

当然,这不是绝对的,因为网络设备既可以是块设备,也可以是字符设备;而时钟则不属于两者中的任何一个。

19.3.1 输入输出设备的差异性

输入输出设备由于种类不同,制造商不同,技术标准不同,其特性可以有巨大的不同。而这种不同越是明显,对操作系统的设计挑战就越大。因为屏蔽这些巨大的不同,使得不同的设备相互共存并转不是一件容易的事情。其中最为明显的一种差异是其数据传输的速度。输入输出设备的传输速度涵盖范围从每秒10个字节到几兆个字节。下表给出的是较为常见的一些设备的数据传输速率。

//表19-1    

19.3.2 设备控制器

一般来讲,输入输出设备至少分为两个部分:机械部分和电子部分。

  • 机械部分:物理硬件部分
  • 电子部分:设备的控制器,也叫适配器,通常是一张PCB板(通常情况下,同类设备可以共用一个控制器/适配器)。

设备控制器的任务可以简单地分为如下几项:

  • 控制设备的物理运行。
  • 将序列字位流转化为字节块流。
  • 进行纠错操作。

设备控制器与CPU之间的数据交互通过设备寄存器进行。设备寄存器附着在设备控制器通过向这些寄存器进行写入操作系统可以向设备发出输入输出命令,或把设备关闭/打开,通过读取这些寄存器的内容,操作系统可以获得设备的状态信息。为了提高与CPU交互数据的效率,输人输出设备通常还备有数据缓冲区。(例如,视频控制器通常带有自己的视频RAM。CPU通过与视频RAM进行数据交互,就可以传输巨大的数据量)

19.3.3 物理I/O模式

计算机在输人输出时可以选择的模式很多。这些选择的不同体现在CPU和内存的使用不同。通常来说,物理输入模式可以按照两种考虑进行分类:

  • 根据CPU访问I/O设备的方式进行分类
  • 根据CPU在I/O过程中的涉入程度进行分类。

根据CPU与设备控制器沟通方式以及与内存的不同关系,物理I/O模式可以分为三种:

@1 专有通道的I/O:I/O与内存是完全脱离的,这个I/O端口就是一个8位或者16位的一个整数。而正是由于1/0端口地址与内存地址没有任何关系,每个控制寄存器被赋予一个I/O端口,这个整数与内存地址没有任何关系;系统必须使用专门的输人输出,或者说I/O端口地址不是内存地址,操作特殊指令来进行数据的读写。

  • 优点:与内存分开,I/O操作不会影响内存操作;而且往往I/O软件的可靠性不如内存管理软件。
  • 缺点:I/O指令与内存访问指令不相同,而高级语言不支持I/O指令,对于设计而言,这加大了难度。

@2 内存映射的I/O:内存映射的I/O,就是将I/O映射到内存里面,从而使得I/O和内存管理得到统一。具体来说,就是将I/O设备的每个控制寄存器和设备缓冲区寄存器赋予一个唯一的内存地址。对这些地址的访问就是对输入输出设备的访问。对这些地址的访问从逻辑上看,就是内存访问。

  • 优点:与内存访问统一,便于控制。
  • 缺点:使用内存映射,I/O被当做内存中的内容来看待,可能被缓存起来:对于一般数据来讲,是优点,因为快,但对于I/O设备而言,操作系统往往需要的是最新的内容,而不是缓存中的内容,这个变化在寄存器你中体现,而不是缓存中,而这将直接影响到I/O操作的执行。当然,这可以使用缓存禁止位来避免。

总线竞争:在单总线系统里,内存和设备均需要对总线上的数据进行监听.以确认命令是否针对自己。这样将产生总线竞争而降低系统效率,如图所示:

如果是多总线系统,则I/O设备有可能看不到总线上的地址,如图所示:

对此,解决的方法有多个:

  • 失败与再试:如果一个请求没有得到内存响应,则将数据发到另外的总线。
  • 窃听:在总线上安装一个窃听装置,负责对数据进行分发。
  • 地址过滤:使用一个过滤装置把地址自动过滤到合适的地方。
  • 复合I/O:使用前两者的组合,即复合I/O模式,在这种复合模式下,数据缓冲区为内存映射,但是输入输出端口为分开的部分。即设备控制器寄存器需要使用特殊命令来访问。

3种模式的结构图如图所示:

19.3.4 根据CPU在I/O过程中的涉入程度进行分类

按照CPU在I/O过程中的涉入程度来分类,物理I/O模式分为:

@1 繁忙等待访问:不管是否使用内存映射的输入输出,处理器均需要与I/O控制器和数据缓冲区进行数据交换。而这种交换既可以按字节进行,也可以按数据块进行。如果按字符进行,CPU当然需要在整个过程中介人,即CPU在I/O过程中一直处于繁忙状态。但是让CPU在I/O过程中一直保持繁忙不是好事。解决方法就是采用DMA方式。

@2 直接内存(Direct Memory Access,DMA)访问:

  • DMA的工作原理是:如果按数据块进行I/O,即需要传输大量数据时,就无需CPU的介入。在这种情况下,我们可以让I/O设备与计算机内存进行直接数据交换。而CPU则可以去忙别的事情。这种将CPU的介入减少的输人输出模式称为直接内存访问。问题是,将CPU从繁忙等待中解脱出来,数据传输使用的CPU不是计算机里面所有进程共享的CPU,而是由另外一个CPU来负责数据传输。这个另外的CPU就是DMA控制器。
  • DMA控制器只用于读写数据,而其他的功能如算术运算、移位、逻辑运算等功能皆可以不要,因此价格很便宜。
  • DMA既可以构建在设备控制器里面;也可以作为独立的实体挂在计算机的主板上,后者较为常见。

使用DMA的工作流程如图所示:

详细描述如下:

  1. CPU对DMA进行设置,告诉其FO的起始地址和数据长度厂
  2. 启动DMA过程。
  3. DMA进行数据传输。
  4. DMA结束后发出中断。
  5. CPU响应中断并处理结束事宜。

DMA模式基础解读:

  • DMA控制器依不同生产厂商的不同而有很大的不同。最简单的DMA控制器在一个时间只能处理一个I/O,即不能并发;复杂的DMA控制器可以同时处理多个I/O,即它能够提供多个I/O通道,每个通道可以对付一个I/O设备。
  • DMA模式的考虑因素:使用DMA模式进行输入输出时有一些因素需要考虑:如何访问总线、数据存放何处、内存寻址模式。
  • 如何访问总线:由于DMA需要使用内存总线,而CPU也需要使用内存总线,这样将形成内存总线竞争。那么DMA使用总线的模式将依赖于CPU使用内存的模式。而根据这些模式的不同,我们可以选择周期盗用(cyclcstealing)或者爆发模式(burstmode)。
  • 数据存放何处:由于DMA数据传输的数据量通常较大,既可以将数据直接存入内存,也可以存入DMA缓冲区,然后通过中断让CPU一次性将DMA缓冲区的数据拷人内存。
  • 内存寻址模式:是使用虚拟地址还是使用物理地址?使用物理地址的好处是速度快,缺点是绕过MMU存在安全和可靠性风险。

DMA模式的优缺点:

  • 优点:将主CPU从I/O中解脱出来;
  • 缺点:增加了成本和复杂性。而且,由于DMA需要与CPU竞争内存总线,其效率的提高不如理论上的期望。

因此,并不是任何I/O都应该使用DMA。在以下情况,应该选择使用主CPU:

  • 设备输入输出速度非常高。
  • 主CPU没有其他事情可做。
  • 成本考虑。

19.4 输入输出软件

  • 操作系统的角色就是魔幻和管理。在这里也不例外。I/O软件的目的就是魔幻和管理。
  • 魔幻是将不同1/0设备的差异屏蔽,使它们看上去似乎是一样的东西,都具有令人爽心悦目的界面。
  • 管理是对这些设备进行管理,该独享的独享,该共用的共用.需要缓冲的缓冲,并对设备进行实际的驱动(发出读写命令)

19.4.1 I/O软件的目的

从高层来看,是魔术与管理;从具体来看,目标有如下几项:

  • 设备独立:程序对I/O设备的访问不依赖于设备的物理特征,即在输人输出程序的编写时无需事先指定I/O设备。
  • 统一命名:设备或文件的命名不依赖于具体的计算机,这样使用名字将使程序可以在任何机器上运行。
  • 错误处理:对输人输出过程中产生的数据错误进行侦测与纠正,而且纠错应该在最靠近硬件的层面上进行。
  • 数据传输:实际操控数据在主机和外设之间的传递。(例如支持同步(阻塞传输)和异步(中断驱动)数据传输)
  • 缓冲:为数据传输提供一个临时存放地,然后在方便的时候将数据拷贝到最后目的地。
  • 共用与独享:将设备尽量变为共享,以增大资源利用率和降低死锁发生的概率。(例如,将磁盘、打印机变为共享)

19.4.2 逻辑I/O模式

在从硬件角度讨论I/O时,我们说过可以有不同的I/O模式。那么从软件角度来看I/O,也存在不同的模式,而且这些模式与硬件I/O模式遥相呼应。从CPU的涉人程度来分,可以分为可编程I/O和中断驱动I/O,这两种分别对应硬件原理的繁忙等待和直接内存访问。

@1 可编程I/O原理:在可编程模式下,CPU等待等待I/O的完成;这种模式也叫轮询/繁忙等待。在此期间,CPU不能干其他任何事情,而最严重的缺陷是可能造成优先级倒挂,进而造成死锁。解决办法就是不繁忙等待,而是使用中断。

@2 中断驱动I/O原理:中断驱动就是将CPU从繁忙等待中解脱出来。在发送好一个或一批数据后,CPU就去忙别的事情。I/O设备处理完这批数据后,向CPU发出中断。CPU响应中断后再发送下一批数据。具体来说,中断驱动过程如下:

  1. CPU初始化I/O并启动第一次I/O操作。
  2. CPU去忙别的事情。
  3. 当I/O完成时,CPU将被中断。
  4. CPU处理中断。
  5. CPU恢复被中断的程序。

@3 直接内存访问I/O原理:中断驱动的I/O由于在I/O设备工作时无需繁忙等待,其效率比可编程I/O要高。但是它毕竟需要CPU周期性中断来发送或接收后续的数据。这种频繁中断对系统效率来说并不是什么好事。这需要改进,而改进的方法就是直接内存访问I/O。由于在硬件角度来看,已经有了DMA,那么就没有必要再让CPU中断,将其直接交给DMA就可以了。方法就是采用DMA的轮询方式来进行处理。

19.5 I/O软件分层

从前面所述可以看出,输人输出是一件颇为繁琐的事情。它牵涉到用户空间和内核空间的数据交换、I/O设备的设置与启动、中断响应与返回,而且整个I/O需要提供一个与I/O设备无关的统一界面。为了完成一个繁琐的工作,人们通常会将其分为更小的任务来处理。在I/O软件里自然不例外。

I/O软件通常按照I/O功能进行分层,每一层提供独特的功能,并与相邻的层面间设计有标准界面。当然,不同的操作系统这种分层也是不同的。但一般,都会有如下所示的几层:

  1. 用户层I/O软件
  2. 设备独立的操作系统软件
  3. 设备驱动程序
  4. 中断服务程序

19.5.1 中断服务程序

由于中断服务程序与硬件相关。针对不同的I/O硬件,中断响应的处理也不尽相同。为了降低操作系统的复杂性,中断服务程序的暴露窗口应该越小越好,即与其打交道的操作系统部分越小越好。降低暴露窗口最好的方法就是让设备驱动程序负责中断响应,即:

  1. 设备驱动程序启动I/O操作后阻塞(设备驱动程序可以通过操作信号量/睡觉),然后等待中断。
  2. 当收到中断请求后,中断服务程序先执行。中断处理的步骤如下:
  3. 保存没有被中断硬件保存的相关寄存器。
  4. 设置中断服务程序的上下文。
  5. 设置中断服务程序的栈。
  6. 回应中断控制器。
  7. 重开中断。
  8. 从保存处恢复寄存器。
  9. 执行服务程序。
  10. 设置MMU以执行下一个进程。
  11. 设置新进程的寄存器。
  12. 开始执行新进程。
  13. 再将处于阻塞状态的设备驱动解锁。(解锁可以通过发送信号/对信号量进行操作)    

19.5.2 设备驱动程序

设备驱动程序:直接驱动I/O设备进行输入输出操作的软件。它属于与设备控制器直接联系的I/O软件部分。它与具体的I/O设备直接相关,并针对每个特定的I/O设备进行过优化。设备控制程序通常由设备制造商提供,但归属于操作系统内核。正因如此,设备驱动程序是操作系统安全的一个巨大隐患。UNIX操作系统在前期不允许动态加载设备驱动程序;后期允许。windows(从NT开始)允许动态加载设备驱动程序。(因此安全性不如UNIX)。由于需要直接驱动设备的运行,设备驱动程序必须清楚设备的所有细节。

设备驱动需要完成的任务如下:

  • 从上层接收抽象的读写请求。
  • 确保读写操作被完成。
  • 初始化设备,开关设备。
  • 对设备的功能进行管理。

多数操作系统都定义一个标准的块设备界面和字符设备界面;每种界面由一组子程序组成;这组子程序可以由操作系统的其他部分调用。

19.5.3 设备驱动操作

在收到一个I/O请求后,设备驱动程序的操作如下:

  • 检查输入参数是否合法。
  • 如果不合法,则返回错误。
  • 如果参数正常,则将I/O请求的抽象表示转换为设备能够认识的具体表示,如将线性数据块号转换为磁头、磁道、扇面等。
  • 设备驱动程序检查设备状态以确认其是否处于闲置状态。
  • 如果设备繁忙,则将I/O请求送入该设备的等待队列里而以待处理。
  • 如果设备没有工作,则驱动设备运行并启动电机。
  • I/O操作:设备驱动程序通过发出一系列的输入输出命令到设备控制寄存器里而来进行真正的数据传输工作。
  • 如果需要,设备驱动程序需要阻塞并等待中断。而每次从中断醒过来,则需要检查I/O是否正确完成,再将数据传输到里面调用设备驱动程序的应用。
  • 在所有数据传输完毕后,设备驱动程序将返回到调用者那里。

19.5.4 设备独立的操作系统软件

一般来说,设备驱动程序并不直接从用户处接受I/O请求,而是通过另外一层中介获得用户请求。这层介于设备驱动程序与用户程序之间的中介就是设备独立的操作系统软件,操作系统在设计时之所以有这层软件是因为I/O软件分为两个部分:

  • 一部分与设备有关:这些操作包括缓冲、错误报告、分配与释放独享设备、提供设备独立的数据块尺寸等;设备独立的OS软件与设备驱动软件之间的分界自然与每个设备有关。
  • 一部分与设备无关:将这部分共用起来,放置在设备驱动程序之上,为用户提供一个统一的I/O界面。

@1 统一界面:设备独立的操作系统软件的一个重要目标是提供一个统一的I/O界面。即让所有的I/O设备看上去一样或者相似。使用的办法则是将设备驱动界面进行标准化:在下层规定-个设备驱动程序必须提供的功能清单;在上层规定内核为设备驱动程序提供的功能清单和界面。

@2 缓冲:几乎所有I/O设备都需要的一种操作,目的有两个:

  • 桥接速度不同的设备,使之可以沟通同步。
    • 提高数据传输速度,因为快速设备不必等待慢速设备;
    • 防止溢出,因为慢速设备来不及处理的数据可以存放在缓冲区而不会丢失。
  • 提供灵活的健壮机制,因为在每个缓冲层都可以进行一些健壮性、可靠性、安全性处理。

缓冲也有缺点:降低了数据传输的时效性。因为数据层层缓冲处理是需要时间的。如果一个系统的时效性非常重要,则最好不要使用缓冲,而是在通信双方之间创建一个没有缓冲的直接通道,这样,数据从一方发出后,另一方将马上收到。

@3 错误报告:在I/O操作中,错误是难免的。这是因为I/O需要与计算机外面的世界打交道,计算机壳里面发生数据传输错误的概率很低,而在计算机壳外部进行数据传输发生错误的概率很高。几二者可以相差几百万倍。因此,在I/O中进行错误处理是件十分重要的事情。如何进行错误处理取决于错误的类型,一般来说,错误可以分为程序错误和真正的I/O错误。

  • 程序错误:用户要求设备做一件该设备无法做到的事情,例如从输出设备上读数据。此时I/O软件除了将错误报告给用户外,似乎不能做任何别的事情了。
  • 真正的I/O错误:数据读写过程中发生的错误,例如数据读错了,或者磁盘盘片损坏了等。需要进行适当的纠错操作,看能否消除错误。

如果不能消除错误则采取以下两种方案:

  • 询问调用者如何处理。
  • 返回一个错误码给用户。

19.5.5 用户层I/O软件

设备驱动程序从设备独立的操作系统软件层接受I/O请求。而设备独立的操作系统软件则从用户或应用软件处接受指令。如果需要向1/0软件发出指令,得需要一个发出指令的界面。这个用户层可以直接使用的I/O界而就是用户层I/O软件。这一层由用户控制,因此在用户空间。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值