IO管理器的任务就是管理IO,本质上windows的IO操做都是异步的,这是由IO流的分层下递和IRQL共同决定的,效果就是IO流被处理的每个步骤均可能在任意线程上下文中进行,那么若是最下面的驱动完成了一个irp,这个怎么让上面的驱动知道呢?固然方法不少,好比上层驱动等待在一个 event上,而microsoft的做法显然更好,就是为每个irp流经的每个设备提供了一个选择,该设备的驱动能够提供一个回调函数,以便下层驱动完成请求的时候通知该层,这就是IO完成回调函数,按照常规理解,这个函数应该由下层的驱动调用,而实际上这样作的话,实现就不是那么“结构化”了, 驱动的开发者就必须负责去手工调用该函数,失去了回调原本的含义,增长了驱动开发者的负担,所以这个回调函数就由IO管理器来调用,这里的说法仅仅是按照模块化思想来的,在整个windows内核中你实际上看不到一个叫作IO管理器的模块的,所谓的IO管理器就是一系列函数接口,对于IO完成回调函数的调用,你只须要调用一个IofCompleteRequest就能够了,而这个接口的实现就是IO管理器的重要内容,那么它是怎么实现的呢?若是不看ReactOS的代码,也不反汇编windows内核的话,还有一种状况可以获得它的实现,那就是本身想,我就是这么干的,没想到还真蒙对了。windows
在分层的驱动逐次往下层的设备递交irp的过程当中,只要有一个分发函数调用了IofCompleteRequest,那么该irp就不会再往下走了,而是顺着来的方向的反方向逐个的调用irp栈上的IO完成回调函数,所以IofCompleteRequest的实现首先就是遍历全部的irp栈帧,而后在每个上执行其IO完成回调函数便可,这只是最简单的方式,windows内核的逻辑也是这么来的,可是每每本身能想到的都是最简单的,扩展开来的话会有不少本身想不到的,好比:有一种状况就是irp栈某一层完成了io,IO管理器调用了上层的io完成回调,接下来该回调返回之后,IO管理器会接着调用上上层的io完成回调,然而若是这个上层的io完成回调中若是一个数据没有准备好,而上上层io完成回调中又须要这个数据的话,这就会引发问题,IO管理器直接 调用了上上层的io完成回调,而实际上这个上层的io尚未完成呢(一个数据没有到位)。以上这种状况是很常见的,毕竟windows内核是一个本质上异步的操做系统内核,一个irp到达某个层次后可能为了实现某项功能会进行一些别的操做,好比查询一些信息,好比和别的内核模块进行交互,这都会产生另外的 irp,而这些irp是和上层没有关系的,是在本层产生并下发的,所以若是这些irp不完成,那个原本的irp也就算没有完成,所以虽然下层完成了这个原本的irp,只由于这些额外的咱们本身在本层生成的irp尚未完成,这就意味着IO完成不能这么简单的逆流而上,实际上最简单的方式就是告诉IO管理器,也就是告诉IofCompleteRequest不要继续逆流而上了,等到时机成熟的时候,我本身逆流而上,这就是IO完成回调函数 STATUS_MORE_PROCESSING_REQUIRED返回值的含义,IofCompleteRequest一旦接收到某个回调函数的返回值是这个,那么就终止循环,而后退出IO管理器,等到这个层次的全部数据都准备好以后,该驱动自行调用IofCompleteRequest,这将重复一样的过程,只是起点变化了,不是最底层的驱动了,而是该层驱动,也就是由于数据而等待的驱动,数据能够在io完成中被准备好,也能够是别的,这就是另外的话题了。异步
最终irp会回到它生成的地方,到这里以后,大多数状况下仍然是任意线程上下文,由于最底层驱动的完成是靠中断触发,因此一系列的逆流而上就是在DPC中执行的(DPC在cpu的队列中排队,为了延迟执行硬中断任务,而APC在线程队列中排队,执行线程上下文中执行的任务),所以为了将完成消息通知到发出请求的线程,就须要将最后的irp层次的io完成回调函数排入到该线程的apc队列中,而后最终在该线程的上下文中被执行,实际上排入apc队列的是 IopCompleteRequest函数。底层驱动不能立马完成的irp,返回时必定要设置pending状态,这样上层才能够正确处理完成回调函数, 注意,这个pending和STATUS_MORE_PROCESSING_REQUIRED的含义是不一样 的,STATUS_MORE_PROCESSING_REQUIRED是本身来处理接下来的完成回调,而pending则是指示io尚未完成,但是完成 回调却要调用,为了防止阻塞,真正的完成操做将在dpc/apc中进行。模块化