System Worker Threads
A driver that requires delayed processing can use a work item, which contains a pointer to a driver callback routine that performs the actual processing. The driver queues the work item, and a system worker thread removes the work item from the queue and runs the driver's callback routine. The system maintains a pool of these system worker threads, which are system threads that each process one work item at a time.
解释:如果一个windows驱动程序需要延时处理一段程序,这段程序可以是一个函数,我们可以使用一个系统工作项来处理。驱动程序会将申请的工作项排成一个队列,系统工作者线程(可以理解为线程池)会自动从队列中移出需要处理的工作项,然后直接运行这个工作项指定的回调函数。windows操作系统提供了一个线程池来管理系统工作者线程,县城池保证每一时刻只可能有一个工作项在运行。
The driver associates a WorkItem callback routine with the work item. When the system worker thread processes the work item, it calls the associated WorkItem routine. On Windows Vista and later versions of Windows, a driver can instead associate a WorkItemEx routine with a work item. WorkItemEx takes parameters that are different from the parameters that WorkItem takes.
解释:设备驱动程序使用一个工作项回调函数来与工作项关联,当系统工作者线程处理这个工作项,它就直接调用这个关联的工作项回调函数。在vista以上的版本中,驱动程序可以直接用WorkItemEx函数替换工作者回调函数。WorkItemEx使用的参数和WorkItem使用的参数也是不同的。
WorkItem and WorkItemEx routines run in a system thread context. If a driver dispatch routine can run in a user-mode thread context, that routine can call a WorkItem or WorkItemEx routine to perform any operations that require a system thread context.
解释:WorkItem和WorkItemEx函数都是运行在系统线程上下文中,如果一个驱动程序派遣了一个运行在用户模式下的线程上下文中的函数,这个函数可以使用WorkItem和WorkItemEx函数去执行运行在系统线程上下文中的操作函数。
To use a work item, a driver performs the following steps:
如下步骤教你如何用工作项:
1. Allocate and initialize a new work item.
The system uses an IO_WORKITEM structure to hold a work item. To allocate a new IO_WORKITEM structure and initialize it as a work item, the driver can call IoAllocateWorkItem. On Windows Vista and later versions of Windows, the driver can alternatively allocate its own IO_WORKITEM structure, and call IoInitializeWorkItem to initialize the structure as a work item. (The driver should call IoSizeofWorkItem to determine the number of bytes that are necessary to hold a work item.)
l 申请和初始化一个新的工作项。
系统用这个IO_WORKITEM结构体去申请一个工作项。申请和初始化IO_WORKITEM结构函数,系统提供IoAllocateWorkItem函数。该函数结构如下;
PIO_WORKITEM IoAllocateWorkItem( IN PDEVICE_OBJECT DeviceObject ); |
在Vista以后版本中,驱动程序可以立即申请一个IO_WORKITEM结构体,然后使用IoInitializeWorkItem函数初始化一个工作项结构体(驱动程序还应该使用IoSizeofWorkItem函数指定需要申请的工作项的大小,以字节为单位)。IoInitializeWorkItem函数原形如下;
VOID |
2. Associate a callback routine with the work item, and queue the work item so that it will be processed by a system worker thread.
To associate a WorkItem routine with the work item and queue the work item, the driver should call IoQueueWorkItem. To instead associate a WorkItemEx routine with the work item and queue the work item, the driver should call IoQueueWorkItemEx.
l 关联回调函数,同时将工作项压入栈中以便于系统工作者线程使用。
实现上述功能只需要调用IoQueueWorkItem,vista版本以后可以直接使用IoQueueWorkItemEx函数。这两个函数的的原型如下;
VOID ------------------------------------------------------------------------------- VOID |
两个函数中WorkerRoutine指向工作项的回调函数。
3. Once the work item is no longer required, free it.
A work item that was allocated by IoAllocateWorkItem should be freed by IoFreeWorkItem. A work item that was initialized by IoInitializeWorkItem must be uninitialized by IoUninitializeWorkItem before it can be freed.
The work item can only be uninitialized or freed when the work item is not currently queued. The system dequeues the work item before it calls the work item's callback routine, so IoFreeWorkItem and IoUninitializeWorkItem can be called from within the callback.
l 一旦工作项不需要使用的时候,我们应该释放他们。
如果使用IoAllocateWorkItem函数申请的,我们应该调用IoFreeWorkItem释放。如果调用IoInitializeWorkItem初始化,我们应该在释放之前调用IoUninitializeWorkItem卸载。不管怎样释放和卸载的操作都应该确保这个工作项不在使用,系统在调用工作项回调函数之前将需要处理的工作项出栈。因此、IoFreeWorkItem和IoUninitializeWorkItem函数可以在回调函数中执行,从而释放工作项。
IoFreeWorkItem和IoUninitializeWorkItem函数原形如下;
VOID VOID |
Because the pool of system worker threads is a limited resource, WorkItem and WorkItemEx routines can be used only for operations that take a short period of time. If one of these routines runs for too long (if it contains an indefinite loop, for example), the system can deadlock. Therefore, if a driver requires long periods of delayed processing, it should instead call PsCreateSystemThread to create its own system thread.
线程池的资源是和有限的,WorkItem和WorkItemEx函数应该执行的函数是执行时间非常短的函数,如果太长,系统将僵持着,因此驱动程序不应该使用工作项来处理长延时的程序。一般可以利用PsCreateSystemThread函数创建一个系统线程。该函数原型如下;
NTSTATUS |