纵横捭阖C++之从异步谈起(二)

2014-11-24 13:16:31 · 作者: · 浏览: 15
初始化、清理和功能调用。驱动程序的调用基于I/O请求包(I/O Request Packet, IRP),而不是像普通的函数调用那样使用栈来传递参数。操作系统和PnP管理器根据注册表在适当的时机初始化和清理相应的驱动程序。在一般的功能调用的时候,IRP里面会指定功能调用号码以及相应的上下文或者参数(I/O stack location)。一个驱动程序可能调用别的驱动程序,这个过程可能是同步的(线程上下文不改变),也可能是异步的。NtReadFile的实现,大致是向最上层的驱动程序发出一个或多个IRP,然后等待相应事件的完成(同步的情况),或者直接返回(带Overlapped的情况),这些都在发起请求的线程执行。

当驱动程序处理IRP的时候,它可能立刻完成,也可能在中断里才能完成,比如说,往硬件设备发出一个请求(通常可以是写I/O port),当设备完成操作的时候会触发一个中断,然后在中断处理函数里得到操作结果。Windows有两类中断,硬件设备的中断和软中断,分成若干个不同的优先级(IRQL)。软中断主要有两种:DPC(Delayed Procedure Call)和APC(Asynchronous Procedure Call),都处于较低的优先级。驱动程序可以为硬件中断注册ISR(Interrupt Service Routine),一般就是修改IDT某个条目的入口。同样,操作系统也会为DPC和APC注册适当的中断处理例程(也是在IDT中)。

值得指出的是,DPC是跟处理器相关的,每个处理器会有一个DPC队列,而APC是跟线程相关的,每个线程会有它的APC队列(实际上包括一个Kernel APC队列和User APC队列,它们的调度策略有所区别),可以想象,APC并不算严格意义上的中断,因为中断可能发生在任何一个线程的上下文中,它被称为中断,主要是因为IRQL的提升(从PASSIVE到APC),APC的调度一般在线程切换等等情形下进行。当中断发生的时候,操作系统会调用中断处理例程,对于硬件设备的ISR,一般处理是关设备中断,发出一个DPC请求,然后返回。不在设备的中断处理中使用太多的CPU时间,主要考虑是否则可能丢失别的中断。由于硬件设备中断的IRQL比DPC中断的高,所以在ISR里面DPC会阻塞,直到ISR返回IRQL回到较低的水平,才会触发DPC中断,在DPC中断里执行从硬件设备读取数据以及重新请求、开中断等操作。ISR或者DPC可能在任何被中断的线程上下文(arbitrary thread context)执行,事实上线程的上下文是不可见的,可以认为是系统借用一下时间片而已。

总的来说,Windows的异步I/O架构中,主要有两种动力,一是发起请求的线程,一部分内核代码会在这个线程上下文执行,二是I