首页 > 代码库 > W?i?n?d?o?w?s? ?I?O?处?理?流?程?浅?析?(?I?R?P?)

W?i?n?d?o?w?s? ?I?O?处?理?流?程?浅?析?(?I?R?P?)

       Windows操作系统中(以Windows 2000/XP为例),一个典型的I/O请求要通过一系列复杂的操作实现。 

        讨论Windows 系统的I/O操作的流程之前,不得不提及WindowsI/O系统结构。简单说来,从虚拟机的角度来说,WindowsI/O系统是一个层层封装的虚拟机。Windows在系统核心中,对设备进行了数层封装:直接构建在设备上的是硬件抽象层(HAL),在此之上的是设备驱动程序,然后是I/O系统(I/O管理器、电源管理、WDMWMI例程等);同时还有许多在用户态运行的系统服务如WMI服务,方便应用程序管理I/O设备。正因为有这种复杂的层次结构,统一管理、兼容成百上千不同种类的系统设备才成为可能。各个抽象层次把硬件结构上的多样性屏蔽掉,使用户能够按照一个统一的方式进行I/O操作。由于这里主要讨论I/O处理流程,I/O系统的结构不做细致阐述。 

以下以打开一个文件对象的过程为例,说明Windows I/O请求的处理流程:  

打开文件对象(File Object  

  1. 子系统调用一个I/O系统服务,打开一个有名字的文件。 

  2. I/O管理器(I/O Manager)调用对象管理器(Object Manager)查找这个文件并帮

助它找到所有相关的符号链接。同时也调用安全引用监视器(Security Reference Monitor)检查这个子系统是否有打开这个文件对象的权限。 

  3. 如果这个文件所在的卷还没有装入,那么I/O管理器暂时挂起这个请求,调用其他文件系统,直到装有这个文件的卷装入,然后I/O管理器恢复刚才挂起的请求。 

  4. I/O管理器为文件打开请求的IRP初始化分配内存。对于驱动程序而言,文件打开请求等价于一个"create"请求。 

  5. I/O管理器调用文件系统驱动程序,向它发送IRP。文件系统驱动程序访问它在IRP

中的I/O堆栈单元(I/O stack location)以决定要进行什么操作,检查参数,决定是否需要通过cache访问文件。如果不需要,在IRP中建立更低一级驱动程序的I/O堆栈单元。 

 6. 各级驱动程序处理IRP完成这个I/O操作请求,会调用I/O管理器和其他系统组件

提供的核心态支持例程。  

 7. 驱动程序在IRP中设置I/O状态块(指明操作是否成功或错误代码),并将IRP

回到I/O Manager 

 8. I/O管理器从IRP中获得I/O状态,通过被保护的子系统将状态信息返回到原始调

用者处。 

 9. I/O管理器释放已经完成任务的IRP 

 10. 如果操作成功,I/O管理器返回这个文件对象的句柄到子系统;否则返回相应的失

败状态。  

//如图

 

 

如果打开成功,子系统就可以通过句柄来对这个设备进行各种I/O操作。其他操作的工作流程与此类似。I/O管理器会根据不同的请求类型产生相应的IRP发送到相应的驱动程序中执行特定的操作。 

以上处理流程虽然复杂,但去掉一些细节后,总脉络是清晰的:I/O请求先陷入到系统核心,从上依层次向下将指令传到设备,执行结果依次向上返回到调用进程,切换回用户态。 

整个流程中,有几个重要的数据结构: 

      文件对象(File Object):文件对象是一种逻辑上的对象,它并不仅仅可以代表文件,事实上它可以代表许许多多不同的物理设备(键盘、打印机、屏幕??当然也可以代表文件)。它事实上提供的是一种基于内存共享的物理资源表示法。每个文件对象对应一个句柄,用户程序通过这个句柄实现各种I/O操作。具体说,通过写入/查询特定的内存区段的,即可实现和物理设备的通讯。Windows所有的I/O操作都通过这种虚拟的文件对象进行,它隐藏了I/O操作目标的实现细节,为各种不同的物理设备提供了一个统一的操作接口。 

       驱动程序对象(Driver Object)和设备对象(Device Object):驱动程序对象代表系统中一个独立的驱动程序,并且为I/O记录每个驱动程序的调度例程的地址(入口点);设备对象代表系统中的一个物理、逻辑或虚拟的设备(注意,并不一定是物理设备!)并描述其特征。 

总体上看,可以认为驱动程序对象是在功能上的抽象(对应某个“操作”),设备对象是结构上的抽象(对应某个“设备”)。 完成某个操作通常需要用到多个设备,所以驱动程序对象通常有多个与它相关的设备对象。 

尽管驱动程序对象和设备对象所封装的功能和设备是各种各样的,但它们都有统一的模型和接口,所以I/O管理器可以统一对它们进行管理和调用,而不用在意其具体内部结构的不同。 

I/O请求包(IRP)是I/O系统用来存储处理I/O请求所需信息(例如请求的类型和大小、是同步请求还是异步请求、指向缓冲区的指针和进展状态信息等)的地方。由前面的例子可以看到,在整个系统内核中的I/O处理流程中,所有的调用/返回/控制信息都是由IRP传递的。它在I/O请求开始时由I/O管理器创建,在I/O处理完成后被释放,它是I/O处理中负责信息传递的最主要数据结构,即所谓以IRP驱动的I/O处理机制。 

以上四种数据结构完整的抽象出了一个I/O请求的方方面面,它们在逻辑上把形形色色的I/O操作都统一起来,使用户可以不理会具体实现的细节,用几乎同样的方式实现各种I/O操作。 

      在整个I/O系统中,I/O管理器无疑是非常重要的,具有核心地位。顾名思义,它负责所有I/O请求的调度和管理工作。根据请求的不同内容,选择相应的驱动程序对象,设备对象,并生成、发送、释放各种不同的IRP。整个I/O处理流程是在它的指挥下完成的。 

另外,完成I/O操作还需要有许多系统中其他服务的支持,总体上被称为驱动程序支持例程。 

大体流程概括如下图(课本P317页图7.12所描述的也是这个结构): 

 

 

         事实上由于I/O操作种类繁多,它们有不同的需求和特点,所以Windows提供了不同的I/O操作选项。主要的I/O操作类型有:同步I/O和异步I/O,快速I/O(注意:快速I/O模式比较特殊,不使用IRP),映射文件I/O和文件高速缓存,分散/集中I/O。各种I/O操作类型的内部处理步骤是很不一样的。同时,单层和多层的驱动程序也有不同的执行策略。这些涉及到过多的细节和Windows驱动程序模型(WDM),在此不更多的展开讨论。 

         虽然具体到每一个I/O请求处理策略会各有不同,但总的来说,涉及到的操作对象和数据结构就是前面提到的那些。而且总的处理脉络仍然是:I/O请求先陷入到系统核心,从上依层次向下将指令传到设备,执行结果依次向上返回到调用进程,切换回用户态。  参考资料: 

l 《操作系统教程》 

l MSDN Library DDK部分