/*++ Copyright (c) 1999 Microsoft Corporation Module Name: locks.c Abstract: Millennium locks. See below for details of the WHY you might do this. Author: Scott Holden (sholden) 2/10/2000 Revision History: --*/ #include "tcpipbase.h" // // The TCP/IP stacks makes a number of assumptions about the receive indication // path being at DPC. Since Millennium indicates receives up on a global event // at PASSIVE level, we need to take extra precautions in this path to return // the thread to the correct IRQL upon releasing a spin lock. // // Since TCP/IP will grab locks and release in a different order and in some // situations CTEGetLockAtDPC will not save the previous IRQL, there were many // issues with leaving threads at the wrong IRQL when enabling spin locks. // // This implementation solves this issue -- since we are on a uniproc machine. // When we enter the first lock, we can raise IRQL to DISPATCH to ensure // that we are not pre-empted. Each additional lock will increment the count. // When the last lock is released, the old IRQL is restored. // // LONG gTcpipLock = 0; KIRQL gTcpipOldIrql; VOID TcpipMillenGetLock( CTELock *pLock ) { #if DBG KIRQL OldIrql; #endif // DBG ASSERT(gTcpipLock >= 0); // First spinlock acquire raises DPC. if (gTcpipLock++ == 0) { KeRaiseIrql(DISPATCH_LEVEL, &gTcpipOldIrql); } // Verify that our individual locks are somehow not reentrant. // KeAcquireSpinLock will do that for us on Millennium. ASSERT((KeAcquireSpinLock(pLock, &OldIrql),OldIrql==DISPATCH_LEVEL) && ((*pLock)&1)); ASSERT(gTcpipLock >= 1); return; } VOID TcpipMillenFreeLock( CTELock *pLock ) { ASSERT(gTcpipLock >= 1); // Verify that our individual locks are somehow not reentrant. // KeReleaseSpinLock on Millennium does that and more for us. ASSERT(KeGetCurrentIrql()==DISPATCH_LEVEL && (KeReleaseSpinLock(pLock, DISPATCH_LEVEL),TRUE)); // Last release lowers IRQL to original. if (--gTcpipLock == 0) { KeLowerIrql(gTcpipOldIrql); } ASSERT(gTcpipLock >= 0); return; }