KWAIT_BLOCK

The KWAIT_BLOCK (formally _KWAIT_BLOCK) is the kernel-mode structure for keeping state about a thread’s waiting on a dispatcher object. A KWAIT_BLOCK is needed for each dispatcher object that a thread waits on. That programmers are mostly not aware of the KWAIT_BLOCK as anything they need to provide when making a thread wait on an object is because most such waits use an array of KWAIT_BLOCK structures that are built in to the thread’s KTHREAD structure (as the latter’s WaitBlock member). The first three in this array are dedicated to supporting the KeWaitForSingleObject and KeWaitForMultipleObject functions. Only when the latter is to wait on more than three objects must the caller provide its own KWAIT_BLOCK array, one structure for each object.

Variability

The KWAIT_BLOCK is another of the several structures that looks to be defined for kernel-mode programmers only so that their code has the structure’s size, in turn only so that their code can allocate space for the structure, whether dynamically or by nesting it in other structures. Microsoft might as well have defined it as an opaque array of some number of bytes, with the kernel free to make whatever internal use it wants, including to change wildly between versions. Unusually for such structures, not only has the kernel varied its use but the size of the KWAIT_BLOCK has varied too:

Version Size (x86) Size (x64)
3.10 to 3.50 0x1C  
3.51 to 2004 0x18 0x30

That the reduction for version 3.51 creates an incompatibility is especially curious in contrast with the trouble Microsoft took over the reduction of the ERESOURCE in version 3.50. The concern in each case is that new drivers built with new headers will allow too little space for safe use on old Windows versions. For the ERESOURCE, Microsoft created a whole family of new functions for new drivers to call for their work with the reduced structure. For the KWAIT_BLOCK, callers of KeWaitForMultipleObjects who wait on more than three objects (and thus must provide their own KWAIT_BLOCK array) were left to discover for themselves that what they provided for version 3.51 is too small for the earlier two versions.

Layout

Offsets, names and types of KWAIT_BLOCK members for all Windows versions are known from C-language declarations published in the corresponding DDK or WDK.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 0x00
LIST_ENTRY WaitListEntry;
all  
0x08 0x10
UCHAR WaitType;
6.2 and higher previously at 0x16 and 0x2A
0x09 0x11
UCHAR volatile BlockState;
6.2 and higher previously at 0x17 and 0x2B
0x0A 0x12
USHORT WaitKey;
6.2 and higher previously at 0x14 and 0x28
  0x14
LONG SpareLong;
6.2 and higher previously at 0x2C
0x08 (3.10 to 6.1);
0x0C
0x10 (5.2 to 6.1);
0x18
KTHREAD *Thread;
3.10 to 6.1  
union {
    KTHREAD *Thread;
    KQUEUE *NotificationQueue;
};
6.2 and higher  
0x0C (3.10 to 6.1);
0x10
0x18 (5.2 to 6.1);
0x20
PVOID Object;
all  
0x10 (3.10 to 6.1);
0x14
0x20 (5.2 to 6.1);
0x28
KWAIT_BLOCK *NextWaitBlock;
3.10 to 6.1  
PVOID SparePtr;
6.2 and higher  
0x14 (3.10 to 6.1) 0x28 (5.2 to 6.1)
CSHORT WaitKey;
3.10 to 3.50  
USHORT WaitKey;
3.51 to 6.1 next at 0x0A and 0x12
0x18 (3.10 to 3.50);
0x16 (3.51 to 6.1)
0x2A (5.2 to 6.1)
WAIT_TYPE WaitType;
3.10 to 3.50  
USHORT WaitType;
3.51 to early 5.2  
UCHAR WaitType;
late 5.2 to 6.1 next at 0x08 and 0x10
0x17 (late 5.1 to 6.1) 0x2B (5.2 to 6.1)
UCHAR SpareByte;
late 5.2 to 6.0  
UCHAR volatile BlockState;
6.1 next at 0x09 and 0x11
  0x2C (5.2 to 6.1)
LONG SpareLong;
late 5.2 to 6.1 next at 0x14

The WaitListEntry links the KWAIT_BLOCK into the WaitListHead in the DISPATCHER_HEADER of the dispatcher object that is being waited on.

The structure’s larger size in the earliest versions is entirely due to having the WaitType as a four-byte enum. Later versions still have this member take its values from the WAIT_TYPE enumeration (defined in NTDEF.H) but reduced to two bytes and even later to just one.

The single-byte BlockState takes its values from the undocumented KWAIT_BLOCK_STATE enumeration.

The WaitKey has two uses. In the WaitAny type of wait for multiple objects, the return value of the KeWaitForMultipleObjects function can tell which object satisfied the wait. This applies trivially to KeWaitForSingleObject. Either way, the WaitKey in the KWAIT_BLOCK for each object is the 0-based index into the KWAIT_BLOCK array. The other use is a little obscure. Waiting with a timeout, whether for a single object or for multiple objects, adds a timer object to the wait. The timer is built in to the KTHREAD as its Timer member. Adding it to the wait uses a built-in KWAIT_BLOCK from the thread’s WaitBlock array (the second when waiting on a single object, the last when waiting on multiple objects). In this block, the WaitKey is set to STATUS_TIMEOUT.