Definition and Use of System Threads

< BACK  NEXT >
[oR]

A thread is a unit of execution. Each thread maintains an independent program counter and hardware context that includes a private set of CPU registers. Each thread maintains a priority value that determines when it gains control of the system processor(s). In general, the higher a thread's priority, the more likely it is to receive control.

Threads can operate in user mode or kernel mode. A system thread is one that runs exclusively in kernel mode. It has no user-mode context and cannot access user address space. Just like a Win32 thread, a system thread executes at or below APC_LEVEL IRQL and it competes for use of the CPU based on its scheduling priority.

When To Use Threads

There are several reasons to use threads in a driver. One example is working with hardware that has the following characteristics:

  • The device is slow and infrequently accessed.

  • It takes a long time (more than 50 microseconds) for the device to make a state transition, and the driver must wait for the transition to occur.

  • The device needs to make several state transitions in order to complete a single operation.

  • The device does not generate interrupts for some state transitions, and the driver must poll the device for an extended period.

Such a device could be managed using a CustomTimerDpc routine. Depending on the amount of device activity, however, this approach could saturate the DPC queues and slow down other drivers. Threads, on the other hand, run at PASSIVE_LEVEL and do not interfere with DPC routines.

Fortunately, most modern hardware is designed to operate in a way that allows good system performance. (Granted, there are many contradictions to this statement.) Legacy hardware, however, is legendary in forcing drivers to poll (and retry) for state transitions, thus burdening the driver with considerable and messy design. The most notable examples are floppy disks and other devices attached to floppy controllers.

Another need for threads occurs with devices that take excessive time to initialize. The driver must monitor the initialization process, polling the state transitions throughout. A separate thread is needed because the Service Control Manager gives drivers only about 30 seconds to execute their DriverEntry routine. Otherwise, the Service Control Manager forcibly unloads the driver. The only solution is to put the long-running device start-up code in a separate thread and return promptly from the DriverEntry routine with STATUS_SUCCESS.

Finally, there may be some operations that can be performed only at PASSIVE_LEVEL IRQL. For example, if a driver has to access the registry on a regular basis, or perform file operations, a multi-thread design should be considered.

Creating and Terminating System Threads

To create a system thread, a driver uses PsCreateSystemThread, described in Table 14.1. Since this function can only be called at PASSIVE_LEVEL IRQL, threads are usually created in the DriverEntry or AddDevice routines.

When a driver unloads, it must ensure that any system thread it may have created has terminated. System threads must terminate themselves, using PsTerminateSystemThread, described in Table 14.2. Unlike Win32 user-mode threads, there is no way to forcibly terminate a system thread. This means that some kind of signaling mechanism needs to be set up to let a thread know it should exit. As discussed later in this chapter, Event objects provide a convenient mechanism for this.

Table 14.1. PsCreateSystemThread Function Prototype
NTSTATUS PsCreateSystemThread IRQL == PASSIVE_LEVEL
Parameter Description
OUT PHANDLE ThreadHandle Handle of new thread
IN ULONG DesiredAccess 0 for a driver-created thread
IN POBJECT_ATTRIBUTES Attrib NULL for a driver-created thread
IN HANDLE ProcessHandle NULL for a driver-created thread
OUT PCLIENT_ID ClientId NULL for a driver-created thread
IN PKSTART_ROUTINE StartAddr Entry point for thread
IN PVOID Context Argument passed to thread routine
Return value STATUS_SUCCESS: thread was created
STATUS_XXX: an error code

Table 14.2. PsTerminateSystemThread Function Prototype
NTSTATUS PsTerminateSystemThread IRQL == PASSIVE_LEVEL
Parameter Description
IN NTSTATUS ExitStatus Exit code signifying reason for termination
Return value STATUS_SUCCESS: thread was killed

Managing Thread Priority

In general, system threads running in a driver should have priorities near the low end of the real-time range. The following code fragment demonstrates this:

 VOID ThreadStartRoutine( PVOID pContext ) {      ...      KeSetPriorityThread(                          KeGetCurrentThread(),                          LOW_REALTIME_PRIORITY );                                ... } 

Be aware that real-time threads have no quantum timeout value. This means that the CPU is relinquished only when the thread voluntarily enters a wait state, or when preempted by a thread of higher priority. Therefore, drivers cannot depend upon round-robin scheduling.

System Worker Threads

For occasional, quick operations at PASSIVE_LEVEL IRQL, creating and terminating a separate thread may not be very efficient. The alternative is to have one of the kernel's system worker threads perform the task. These threads use a callback mechanism to do work on behalf of any driver.

It is not difficult to use system worker threads. First, allocate storage for a WORK_QUEUE_ITEM structure. The system will use this block to keep track of the work request. Next, call ExInitializeWorkItem to associate a callback function in the driver with the WORK_QUEUE_ITEM.

Later, when a system thread is needed to execute the callback function, call ExQueueWorkItem to insert the request block into one of the system work queues. The request can be executed either by a worker thread with a real-time priority or by one with a variable priority.

Keep in mind that all drivers are sharing the same group of system worker threads. Requests that take a very long time to complete may delay the execution of requests from other drivers. Tasks involving lengthy operations or long time delays should utilize a private driver thread rather than the system work queues.

< BACK  NEXT >


The Windows 2000 Device Driver Book(c) A Guide for Programmers
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
ISBN: 0130204315
EAN: 2147483647
Year: 2000
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net