计算机两大主要任务:IO操作和计算处理。许多情况下,主要是IO操作,计算处理只是附带的(而操作系统的两大任务是管理物理设备和为应用程序提供一个虚拟机器的抽象)。操作系统在IO方面的作用是管理IO操作和IO设备。
一、概述
I/O设备在功能与速度方面存在很大差异,所以需要采用多种方法来控制设备。这些方法形成IO子系统的核心,使得操作系统内核其他部分不必涉及复杂的IO设备管理。
IO设备技术呈现两个相矛盾的趋势:一方面,硬件与软件接口日益标准化,有助将设备集成到现有计算机和操作系统,另一方面,IO设备的多样性却又日益增长,甚至有的新旧版本区别很大,以至于很难集成。这种困难需要硬件和软件一起配合解决。操作系统内核设计成使用设备驱动程序模块的结构,而驱程为IO子系统提供了统一设备访问接口。
二、IO硬件
硬件自带有所谓控制器。处理器通过控制器来控制硬件。那么处理器如何向控制器发送命令和数据?简单而言,控制器有一些寄存器,处理器就是通过读写这些寄存器来与控制器通信,这又有2种方式,一是通过IO指令;二是通过内存映射:设备控制寄存器被映射到处理器的地址空间,处理器通过标准数据传输指令来执行IO请求。
具体来说是酱紫的:
1、轮询
主机不断读取寄存器的状态,以决定下一步动作。效率较差。
2、中断
控制器主动发出中断请求信号通知CPU。中断分优先级,多级中断。效率高。
3、直接内存访问
对于需要做大量传输的设备,例如磁盘,耗费CPU来观察寄存器太浪费,通常将任务下方给专用处理器,称之为直接内存访问(DMA)控制器。CPU向内存写入数据,然后就继续忙别的,DMA控制器接手进行数据传输,完了以后中断通知CPU。
三、IO应用接口
IO应用接口使得IO设备可以按统一的标准方式来对待。
具体来说,从不同的IO设备中抽象出通用类型,每个通用类型都可以通过一组标准函数(即接口)来访问。具体的差别被内核模块(设备驱动程序)所封装。设备驱动程序层的作用就是为内核IO子系统隐藏设备控制器之间的差异。
不利的因素是每种操作系统都有自己的接口标准,一个设备可能有多种驱动程序。
对应用程序而言,设备的许多差别都被操作系统所隐藏,设备可以分为几种类型:块与字符设备,网络设备,时钟与定时器等。
1、块与字符设备
比如磁盘,键盘,鼠标、打印机、声卡等。
2、网络设备
Socket接口
3、时钟与定时器
调度程序使用定时器(硬件)产生中断;操作系统也为用户进程提供了使用定时器的接口。
4、阻塞与非阻塞I/O
“当应用程序发出一个阻塞系统调用时,应用程序的执行被挂起,从操作系统的运行队列移到等待队列。在系统调用完成后,应用程序就移回运行队列,并在某个时刻继续执行并收到系统调用返回的值”。IO设备的执行时间不可预计,但操作系统为应用程序接口使用阻塞调用。
就是说,应用程序访问IO设备时,操作系统会让应用程序等待,直至IO设备返回结果。当然,操作系统不可能也陪着干等,它是让应用程序在一旁等候,然后自己继续为另一些程序服务。就好比到麦当劳点餐,收银员(操作系统调度程序)在你(应用程序)点完餐后,吩咐后台(IO设备)准备食物,然后让你移到一旁等候(挂起),接着她说:下一位点餐。
有关 同步异步、阻塞非阻塞,现在我也还不是十分清楚,可参考拙作:
http://blog.csdn.net/leftfist/article/details/41800463
四、IO内核子系统
内核提供了许多与IO有关的服务,如调度、缓冲、高速缓存、假脱机、设备预留及错误处理等。这些服务建立在硬件和设备驱动程序之上。IO子系统还负责保护自己免受错误进程和恶意用户的危害。
1、IO调度
就是确定一个合适的顺序来执行IO请求。调度能改善性能。
调度可由开发人员实现,也可以由操作系统分配。
IO子系统改善计算机效率的方法之一就是IO调度,另外一种方法是使用内存或磁盘上的存储空间技术,如缓冲、高速缓存、假脱机等。
2、缓冲
缓冲区是用来保存两个设备之间或设备和应用程序之间所传输数据的内存区域。
这样做有三个理由:
1)数据流生产者与消费者之间的速度存在差异
2)协调传输数据大小不一致的设备
3)支持应用程序IO的复制语义。所谓复制语义,就是处理前先对数据进行复制,保证处理过程中不受数据源发生变化所影响。
3、高速缓存
高速缓存是可以保留数据副本的高速存储器。高速缓存副本的访问要比原始数据访问更高效。高速缓存与缓冲是两个不同的功能。
4、假脱机与设备预留
假脱机就是一种排队机制。
5、错误处理
操作系统可以预防许多硬件和应用程序的错误,这样就不会因为小的机械失灵导致系统崩溃。
6、IO保护
为了防止用户执行非法IO,定义所有IO指令为特权指令。用户不能直接发出IO指令,只能通过操作系统来进行。
另外,所有内存映射和IO端口内存位置都受到内存保护系统的保护,以阻止用户访问。但内核不能简单地拒绝所有用户访问, 因为有些软件需要直接访问内存映射来提高性能,内核采取锁机制来应对。
7、内核数据结构
内核需要保存IO组件使用的状态信息,可以通过若干内核数据结构如文件打开表等来完成。事实上,内核使用许多类似的结构来跟踪网络连接,字符设备通信和其他IO活动等。
操作系统采用面向对象的技术,采用统一结构来封装不同设备之间的差异。
五、把IO操作转换成硬件操作
现代操作系统通过对请求与物理设备控制器之间的多级表查找,可以获得巨大的灵活性。应用程序与驱动程序之间的请求传递机制是通用的。因此,不必重新编译内核也能为计算机引入新设备和新驱动程序。事实上,有的操作系统能够按需加载设备驱动程序,系统启动之时,系统先检测硬件总线以确定有哪些设备,接着操作系统就马上或等首次IO请求时装入所需的驱程。
以下是一个典型的文件读请求周期:
1)一个进程对已打开文件的文件描述符调用阻塞read()系统调用
2)内核系统调用代码检查参数是否正确。对于输入,如果数据已在高速缓存中,那么将数据返回进程并完成IO请求
3)否则执行物理 IO请求。此时进程从运行队列移到设备的等待队列,并调度IO请求。最后IO子系统对设备驱动程序发出请求。根据操作系统的不同,该请求可能通过子程序调用或内核消息传递
4)设备驱动程序分配内核缓冲区空间以接收数据,并调度IO。最后设备驱动程序通过写入设备控制器寄存器来对设备控制器发送命令。
5)设备控制器控制设备硬件以执行数据传输
6)驱动程序可以轮询检测状态和数据,或动过DMA将数据传入到内核内存。假设为DMA,当传输完成后产生中断
7)中断处理程序通过中断向量表收到中断,保存必要的数据,并向内核设备驱动程序发送信号通知,然后从中断返回。
8)设备驱动程序接收到信号,确定IO请求是否完成,确定请求状态,并向内核IO子系统发送信号,通知请求已完成
9)内核将数据返回代码传递诶请求进程的地址空间,将进程从等待队列移到就绪队列,阻塞解除,进程继续执行
总结:进程请求 -》内核检查,返回或物理IO请求 - 向设备驱动请求 - 设备驱动程序调度IO - 设备控制器数据传输 - 通知设备驱动 - 内核 - 进程
流由流开始 + 若干流模块 + 控制设备驱动程序结尾 组成。它们都有一对队列:读队列和写队列。队列之间使用消息传递进行数据传输。队列会缓冲消息,而且没有足够缓冲空间就不会接收消息,是为流控制。
如图。从流开始,消息不断复制一直到驱动程序结尾和设备。
使用流的好处是流可以提供一个框架,以便以模块化以及递增的方式编写设备驱动程序和网络协议。模块可以为不同的流以及不同的设备所使用。
七、性能
IO是影响系统性能的重要因素之一。
执行设备驱动程序代码,以及随之出现的进程阻塞和调度,上下文切换,这些都增加了CPU或者高速缓存的负担。虽然现代计算机每秒能处理数千个中断,但是中断处理仍然是相对费时的任务,IO暴露出内核中断机制的任何效率缺陷。
为了改善IO效率,可以采用一些原则:
1)减少上下文切换
2)减少设备和应用程序之间传递数据时在内存之间的数据复制次数
3)通过使用大传输,智能控制器,轮询,以减少中断频率
4)通过采用DMA智能控制器和通道来为主CPU承担简单数据复制,以增加并发
5)将处理原语移入硬件,允许控制器内的操作与CPU和总线内的操作并发
6)平衡CPU,内存子系统,总线和IO的性能