KDPC_DATA

The KDPC_DATA structure is an internal detail of the kernel’s implementation of Deferred Procedure Calls. Though the DpcData member of a KDPC in version 5.2 and higher is declared as pointing to void, what it actually points to is a KDPC_DATA structure.

Before version 5.2, each processor has one list of DPCs. The list’s head and lock and other control data are in the processor’s KPRCB, as the DpcListHead, DpcLock, DpcQueueDepth and DpcCount members. To support threaded DPCs, version 5.2 introduces a second per-processor DPC list. The two are handled so very nearly identically that the same control data works for both, in separate instantiations for independent operation.

Thus did the previously separate members get collected into the new DPC_DATA structure, which every KPRCB has two of, in an array that is also named DpcData. While a KDPC is inserted in the per-processor list of ordinary DPCs or of threaded DPCs, its DpcData points to the first or second element, respectively, of the DpcData array in the KPRCB. The macro definitions DPC_NORMAL (0) and DPC_THREADED (1) in WDM.H, which might otherwise seem mysterious for being referenced from nowhere among all the WDK headers, correspond to the array indices.

Documentation Status

The KDPC_DATA structure is not documented.

Layout

The KDPC_DATA is 0x14 and 0x20 bytes in 32-bit and 64-bit Windows, respectively, until expansion for Windows 8.1 brings the sizes to 0x18 and 0x28.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
LIST_ENTRY DpcListHead;
5.2 to 6.1
KDPC_LIST DpcList;
6.3 and higher
0x08 0x10
KSPIN_LOCK DpcLock;
5.2 and higher
0x0C 0x18
ULONG volatile DpcQueueDepth;
5.2 only
LONG volatile DpcQueueDepth;
6.0 and higher
0x10 0x1C
ULONG DpcCount;
5.2 and higher
0x14 0x20
KDPC * volatile ActiveDpc;
6.3 and higher

KDPC_LIST

To make space in the KDPC for the ProcessorHistory, Windows 8.1 changes the link in each KDPC from double to single. Accessing a particular KDPC at its arbitrary position in the list is necessarily less efficient with single linkage, but is needed only for the KeRemoveQueueDpc function, whose use is relatively infrequent in practice. Quick access to the last KDPC in the list, is another matter, being needed at every insertion of a KDPC that doesn’t have HighImportance. Where the DPC_DATA had a double-linked list head it instead has separate single links to both head and tail, modelled together as the DPC_LIST structure:

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
SINGLE_LIST_ENTRY ListHead;
6.3 and higher
0x04 0x08
SINGLE_LIST_ENTRY *LastEntry;
6.3 and higher