I/O结构
通用计算机系统由一个CPU和多个设备控制器所组成,它们通过共同的总线连接起来。每个设备控制器负责特定类型的设备。整体的结构可以用下图来表示:
每个设备控制器负责特定的设备,即维护一定的本地缓冲存储器和一组特定用途的存储器。设备控制器负责在其所控制的设备与本地缓冲存储器之间进行数据的传递。
为了开始I/O操作,CPU在设备控制器内装入合适的寄存器值。相应地,设备控制器检查这些寄存器中的值,已决定采取何种操作,换句话说就是CPU控制设备是通过设定对应设备的设备控制器中的寄存器值来进行的。例如,如果一个进程发出了读设备的请求,CPU设定对应设备的设备控制器中的对应寄存器中的值,设备控制器发现了读请求,那么设备控制器就开始从设备向本地的缓冲区传递数据,如果数据传输完成,设备控制器就会通知CPU,说已完成操作,请把数据拿走吧。CPU接到这种通知就会从设备的缓冲区中读取数据。这个过程还有同步I/O和异步I/O之分。用户请求I/O,一旦I/O开始,就可能有两种行动过程。一种是进行I/O,直到I/O操作完成,才会把CPU的控制权返回给用户进程,这种称为同步I/O。另一种是,用户发出I/O请求后,就把CPU的控制权返回给用户进程,这种称为异步I/O。同步I/O过程,CPU总是等待I/O完成,那么任何时候最多只能处理一个I/O请求。因此,只要发生了I/O中断,系统就知道是哪个设备产生了中断(这里的中断是设备控制器发出的用于通知CPU I/O操作完成,请读取缓冲区中的数据),但是在另一方面,这种方法排除了多个设备的并发I/O操作,也排出了将有用计算与I/O相重叠的可能性。设想一下,设备控制器从对应的设备取数据的过程即开始i/o到i/o完成这段时间CPU就在那傻等着,直到设备控制器发出准备好了的i/o中断。
一种更好的选择是开始I/O之后,cpu就继续执行其他操作系统或用户进程,即异步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被大量的数据传输的IO中断所占用。
如何将CPU从繁重的数据拷贝的任务中解放出来,就这样DMA应运而生。
上图所示,CPU只是在IO中断产生后,为其在内存中设置一个缓冲区,然后通知DMA拷贝,全程CPU只是开个头,然后大量的拷贝工作交给DMA去完成。