内核调度对象简介
内核定义了一系列叫做内核调度对象,或简称调度对象的对象类型。调度对象包含定时器对象,事件对象,信号量对象,互斥体对象和线程对象。
的一个“非任意”线程上下文上执行时,可以使用内核调度对象作同步机制使用。
调度对象的状态
每一种内核定义的调度对象类型拥有两种状态:信号态或非型号态。
一组线程的其中一个或者多个线程可以通过调用KeWaitForSingleObject, KeWaitForMutexObject,或者KeWaitForMultipleObjects同步他们的操作。
这些函数把一个调度对象指针作为输入参数,在调度对象上等待,直到另一个例程或者线程设置一个或多个调度对象为信号态。
当一个线程调用KeWaitForSingleObject 去等待一个内核调度对象(或者调用KeWaitForSingleObject 等待一个互斥体)时,线程被设置为等待状态,直到调度对象被设置为信号态。一个线程可以通过调用KeWaitForMultipleObjects 去等待任意一个或者全部调度对象被设置为信号态。
无论在何时,当一个调度对象设置为信号态时,内核将在这个对象上等待的线程的状态改为ready状态。(同步定时器和同步事件例外;当一个同步事件或者定时器被设置为信号态,仅一个在此对象上等待的线程被设置为ready状态。更多有关信息见Timer Objects and DPCs 和 Event Objects。)操作系统将根据线程当前的运行时线程优先级调度(thread priority)和处理器的当前可用性(and the current availability of processors for any thread with that priority.)去运行一个ready状态的线程。
什么时候驱动程序可以等待一个调度对象?
通常来说,仅在至少以下一个条件满足时驱动程序可以等待一个调度对象设置为信号态:
·
驱动程序运行在一个“非任意”线程的上下文中。
也就是,你可以标示线程将进入一个等待状态。在实际中,驱动程序在一个“非任意”上下文执行的例程为: 任意驱动程序的DriverEntry, AddDevice, Reinitialize, 和Unload 例程,加上高层级驱动程序的调度例程。这些例程都被系统直接调用。
·
驱动程序正在执行一个完全同步的I/O请求。
·
也就是说,驱动程序在处理I/O请求时,没有为任何操作排队,并且直到此驱动下层的驱动完成对请求的处理之前没有任何驱动返回。
另外,如果一个驱动程序运行在IRQL = DISPATCH_LEVEL或者高于这个IRQL时不能进入一个等待状态。
基于这些限制,您必须遵循一下规则:
·
在任意驱动程序的DriverEntry, AddDevice, Reinitialize, 和Unload 例程可以等待调度对象.
·
高层级的驱动程序的派遣例程可以等待一个调度对象。
·
低层级的驱动程序可以在I/O操作是同步的情况下等待一个调度对象,例如create, flush, shutdown, 和 close 操作,一些设备I/O控制操作,和一些PnP以及电源操作。
·
低层级驱动程序不可以在派遣例程的异步操作的completion例程上等待一个调度对象。
·
执行在IRQL DISPATCH_LEVEL或者高于它的驱动例程不可以等待一个调度对象设置为信号态。
·
在一个传输操作的来源或者目的是分页设备(paging device)时,驱动程序绝对不可以试图在这个操作的completion 例程上等待一个调度对象被设置为信号态。
·
为read/write请求服务的驱动派遣例程一般来说不可以等待一个调度对象被设置为信号态。
·
设备I/O控制请求的派遣例程仅可以在I/O控制码为METHOD_BUFFERED时可以等待一个调度对象被设置为信号态。
·
SCSI miniport 驱动程序不应使用内核调度对象,SCSI miniport 驱动程序仅应当调用SCSI Port 库例程.
·
Every other standard driver routine executes in an arbitrary thread context: that of whatever thread happens to be current when the driver routine is called to process a queued operation or to handle a device interrupt. 此外,大多数标准驱动程序例程运行在一个提高的IRQL(即高于 PASSIVE_LEVEL), 或是DISPATCH_LEVEL, 或是设备驱动程序的IRQL,即在DIRQL。
如果有必要,一个驱动程序可以创建它设备专用的线程,它可以等待驱动程序的其他例程(除了一个ISR或者SynchCritSection例程)设置一个调度对象为信号态,也可设置调度对象为非信号态。作为一个一般的准则,如果你预料你的新设备驱动程序在执行I/O操作的过程中需要等待设备状态改变时将经常需要延迟超过50毫秒,考虑实现一个带设备专用线程的驱动程序。如果设备驱动又是一个高层级的驱动程序,考虑使用系统工作线程(system worker threads)并实现一个或者多个工作线程回调例程。见PsCreateSystemThread和Managing Interlocked Queues with a Driver-Created Thread。