16.2.5 Preventing Errors or Deadlocks While Using Spin Locks
When an NT driver routine holds a spin lock, it cannot cause a hardware exception or raise a software exception without bringing down the system. In other words, an NT driver’s ISR and any SynchCritSection routine that the driver supplies in a call to KeSynchronizeExecution must not cause a fault or trap, such as a page fault or an arithmetic exception, and cannot raise a software exception. A routine that calls KeAcquireSpinLock also cannot cause a hardware exception or raise a software exception until it has released its executive spin lock and is no longer running at IRQL DISPATCH_LEVEL.
Pageable Data and Support Routines
NT drivers must not call routines that access pageable data while holding a spin lock. Drivers can call certain support routines that access pageable data if and only if their calls occur while executing at an IRQL strictly less than DISPATCH_LEVEL. Note that this IRQL restriction precludes calling such a support routine while holding a spin lock.
Recursion
Attempting to acquire a spin lock recursively is guaranteed to cause a deadlock: the holding instantiation of a recursive routine cannot release the spin lock while a second instantiation spins, trying to acquire the same spin lock.
NT driver writers who implement a recursive routine should follow these guidelines concerning spin lock usage:
·The recursive routine must not call itself while holding a spin lock, or must not attempt to acquire the same spin lock on subsequent calls.
·While it holds a spin lock, another driver routine must not call the recursive routine if recursion might cause a deadlock or could cause the caller to hold the spin lock for longer than 25 microseconds.
For more information about recursive driver routines, see also Section 16.4.2.
Nested Spin Lock Acquisitions
Attempting to acquire a second spin lock while holding another spin lock also can cause deadlocks or poor driver performance.
NT driver writers should follow these implementation guidelines in drivers holding a spin lock:
·The driver must not call a support routine that uses a spin lock unless a deadlock cannot occur.
·Even if a deadlock cannot occur, the driver should not call a support routine that uses a spin lock unless alternate coding techniques cannot provide comparable driver performance and functionality.
·If a driver makes nested calls to acquire spin locks, it must release those spin locks in inverse order: that is, if a driver acquires spin lock A before acquiring spin lock B, it must release spin lock B before it releases spin lock A.
In general, NT driver writers should avoid using nested spin locks to protect overlapping subsets or discrete sets of shared data and resources. Consider what can happen if a driver uses two executive spin locks to protect discrete resources, such as a pair of timer objects that might be set individually and collectively by various driver routines. Such a driver would deadlock intermittently in an SMP machine, whenever either of two routines, each holding one spin lock, tried to acquire the other spin lock.
Even if a deadlock-proof driver can be designed to use nested spin locks, it could be difficult to implement successfully. Nested spin locks are very difficult to debug and to test adequately in a Windows NT SMP machine. Moreover, using nested spin locks can degrade both driver and system performance severely.