Geoff Chappell - Software Analyst
With Windows XP, Microsoft introduced the queued spin lock as improving on the basic spin lock because it “guarantees that processors acquire the spin lock on a first-come first-served basis”. Each contender for a lock not only specifies which lock but also provides a KSPIN_LOCK_QUEUE structure so that its contention for the lock can be queued. What Microsoft did not say when introducing queued spin locks for general use is that queued spin locks existed earlier for particular purposes. The KSPIN_LOCK_QUEUE_NUMBER lists those purposes. Each purpose has its own per-processor queued spin lock. Collectively, these are the LockQueue array of KSPIN_LOCK_QUEUE structures in each KPRCB. The KSPIN_LOCK_QUEUE_NUMBER indexes this array.
In 32-bit Windows, the KSPIN_LOCK_QUEUE_NUMBER is an enumeration (formally _KSPIN_LOCK_QUEUE_NUMBER). For 64-bit Windows, Microsoft seems to have rethought the exposure, e.g., in symbol files, and the KSPIN_LOCK_QUEUE_NUMBER is instead defined as a ULONG64. Either way, the possible values are the same.
The KSPIN_LOCK_QUEUE_NUMBER is not documented, but a C-language definition has long been published, first in NTDDK.H from the Device Driver Kit (DDK) for Windows XP and later in WDM.H. Its existence in these kits as anything other than an opaque type is something of a mystery, since the only use that is made of it in any other header from a DDK or Windows Driver Kit (WDK) is in NTIFS.H for declarations of such functions as KeAcquireQueuedSpinLock which have only ever been documented as reserved.
|0x00||LockQueueDispatcherLock||5.0 to 6.0|
|LockQueueUnusedSpare0||6.1 and higher|
|0x01||LockQueueContextSwapLock||5.0 to 5.1|
|LockQueueExpansionLock||6.0 to 6.3|
|LockQueueUnusedSpare1||10.0 and higher|
|0x02||LockQueuePfnLock||5.0 to 6.0|
|LockQueueUnusedSpare2||6.1 and higher|
|0x03||LockQueueSystemSpaceLock||5.0 to 6.3|
|LockQueueUnusedSpare3||10.0 and higher|
|0x04||LockQueueVacbLock||5.0 and higher|
|0x05||LockQueueMasterLock||5.0 and higher|
|0x06||LockQueueNonPagedPoolLock||5.1 and higher|
|0x07||LockQueueIoCancelLock||5.1 and higher|
|0x08||LockQueueWorkQueueLock||5.1 and higher|
|0x09||LockQueueIoVpbLock||5.1 and higher|
|0x0A||LockQueueIoDatabaseLock||5.1 and higher|
|0x0B||LockQueueIoCompletionLock||5.1 and higher|
|0x0C||LockQueueNtfsStructLock||5.1 and higher|
|0x0D||LockQueueAfdWorkQueueLock||5.1 and higher|
|0x0E||LockQueueBcbLock||5.1 and higher|
|0x0F||LockQueueMmNonPagedPoolLock||5.2 to 6.3|
|LockQueueUnusedSpare15||10.0 and higher|
|0x10||LockQueueUnusuedSpare16||late 5.2 and higher|
|0x11||LockQueueTimerTableLock||late 5.2 to 6.0|
0x10 (early 5.2);
0x21 (late 5.2 to early 6.0);
0x31 (late 6.0);
|LockQueueMaximumLock||5.0 and higher|
Because the availability of C-language definitions and of type information in symbol files begins with Windows XP, interpretation for version 5.0 is not certain. Even in that version the LockQueue array has space for 0x10 queued spin locks. That only the first six are seen to be used (or even initialised) doesn’t mean that more were not defined.
The value LockQueueTimerTableLock selects a cache-aligned array of 0x10 or 0x20 lock queues for accessing the kernel’s timer table (shared among processors). This became redundant when Windows 7 introduced per-processor timer tables.