Geoff Chappell - Software Analyst
This function gives up the current thread’s exclusive access to whatever resource is protected by the given lock.
VOID KeReleaseSpinLock (KSPIN_LOCK *SpinLock, KIRQL NewIrql);
The SpinLock argument is the address of the lock that is to be released.
The NewIrql argument is the Interrupt Request Level (IRQL) to execute at once the lock is released. This is typically the IRQL to restore from before the lock’s acquisition.
The KeReleaseSpinLock function is exported by name from x86 builds of the HAL in all versions and of the kernel in version 6.2 and higher. The HAL’s export in version 6.2 and higher is merely a forward to the kernel.
For 64-bit Windows, KeReleaseSpinLock is not a HAL export. It is instead exported by name from the x64 builds of the kernel in all versions, i.e., starting with the version 5.2 from Windows Server 2003 SP1.
The KeReleaseSpinLock function is documented in all known editions of the DDK or Windows Driver Kit (WDK) since at least the DDK for Windows NT 3.51.
As early as version 3.50, the KeReleaseSpinLock implementation was shifted to a __fastcall alternative named KfReleaseSpinLock. Starting at least from the Device Driver Kit (DDK) for Windows NT 3.51, a macro definition reinterprets the former in terms of the latter. New code is written as if calling KeReleaseSpinLock but actually calls KfReleaseSpinLock. The old function continues to be exported, presumably to support (old) code that tries to import the function, but its implementation is only a stub that reinterprets in terms of KfReleaseSpinLock just like the macro.
That KfReleaseSpinLock has all the substance is here treated just as a detail of internal organisation. As far as should concern any code outside the kernel or HAL, the behavour is all in KeReleaseSpinLock.
The KeReleaseSpinLock function is in some sense a convenience. Its work is in two parts which can be done independently of KeReleaseSpinLock by calling exported functions, the first from the kernel, the second from the HAL. The KeReleaseSpinLock implementation gains by inlining its two parts (and skipping the first entirely for single-processor builds).
The first part is to release the current processor’s exclusive use of the protected resource. All threads that seek to use the resource must acquire the agreed lock. All call KeAcquireSpinLock or a similar one so that all try to mark the lock in the same way but can do so only while the lock is not already marked. Typically, they wait in a more or less tight loop until they are able to mark the lock to signify that they now own the resource. The first part of releasing the lock is to clear this mark. Equivalent exported functions for this first part are KeReleaseSpinLockFromDpcLevel and, on x86 builds only, KefReleaseSpinLockFromDpcLevel and KiReleaseSpinLock. This part is trivial in single-processor builds.
The second part is to set the desired NewIrql. Typically, this lowers the IRQL from DISPATCH_LEVEL, which allows that other threads can now execute on the current processor. Equivalent exported functions are KeLowerIrql and KfLowerIrql.
The KeReleaseSpinLock function is intended for use at DISPATCH_LEVEL or higher. The address that is given in the SpinLock argument must be of non-paged memory.
The implementation merely assumes that the calling thread does own the spin lock.