- Implemented Queued and In-Stack Queued Spinlocks (at DPC-Level). See "Windows Internals II" Chapter 4, Pages 25-27. Modified: trunk/reactos/ntoskrnl/ke/spinlock.c _____
Modified: trunk/reactos/ntoskrnl/ke/spinlock.c --- trunk/reactos/ntoskrnl/ke/spinlock.c 2006-01-05 12:48:33 UTC (rev 20572) +++ trunk/reactos/ntoskrnl/ke/spinlock.c 2006-01-05 13:12:48 UTC (rev 20573) @@ -18,6 +18,9 @@
#undef KefReleaseSpinLockFromDpcLevel #undef KeReleaseSpinLockFromDpcLevel
+#define LQ_WAIT 1 +#define LQ_OWN 2 + /* FUNCTIONS ***************************************************************/
/* @@ -190,25 +193,98 @@ #endif }
+VOID +FASTCALL +KeAcquireQueuedSpinLockAtDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle) +{ +#ifdef CONFIG_SMP + PKSPIN_LOCK_QUEUE Prev; + + /* Set the new lock */ + Prev = (PKSPIN_LOCK_QUEUE) + InterlockedExchange((PLONG)LockHandle->LockQueue.Lock, + (LONG)LockHandle); + if (!Prev) + { + /* There was nothing there before. We now own it */ + *(ULONG_PTR*)&LockHandle->LockQueue.Lock |= LQ_OWN; + return; + } + + /* Set the wait flag */ + *(ULONG_PTR*)&LockHandle->LockQueue.Lock |= LQ_WAIT; + + /* Link us */ + Prev->Next = (PKSPIN_LOCK_QUEUE)LockHandle; + + /* Loop and wait */ + while ( *(ULONG_PTR*)&LockHandle->LockQueue.Lock & LQ_WAIT) YieldProcessor(); + return; +#endif +} + +VOID +FASTCALL +KeReleaseQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle) +{ +#ifdef CONFIG_SMP + KSPIN_LOCK LockVal; + PKSPIN_LOCK_QUEUE Waiter; + + /* Remove own and wait flags */ + *(ULONG_PTR*)&LockHandle->LockQueue.Lock &= ~(LQ_OWN | LQ_WAIT); + LockVal = *LockHandle->LockQueue.Lock; + + /* Check if we already own it */ + if (LockVal == (KSPIN_LOCK)LockHandle) + { + /* Disown it */ + LockVal = (KSPIN_LOCK) + InterlockedCompareExchangePointer(LockHandle->LockQueue.Lock, + NULL, + LockHandle); + } + if (LockVal == (KSPIN_LOCK)LockHandle) return; + + /* Need to wait for it */ + Waiter = LockHandle->LockQueue.Next; + while (!Waiter) + { + YieldProcessor(); + Waiter = LockHandle->LockQueue.Next; + } + + /* It's gone */ + *(ULONG_PTR*)&Waiter->Lock ^= (LQ_OWN | LQ_WAIT); + LockHandle->LockQueue.Next = NULL; +#endif +} + /* - * @unimplemented + * @implemented */ VOID FASTCALL KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle) { - UNIMPLEMENTED; + /* Set it up properly */ + LockHandle->LockQueue.Next = NULL; + LockHandle->LockQueue.Lock = SpinLock; + KeAcquireQueuedSpinLockAtDpcLevel((PKLOCK_QUEUE_HANDLE) + &LockHandle->LockQueue.Next); }
/* - * @unimplemented + * @implemented */ VOID FASTCALL KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle) { - UNIMPLEMENTED; + /* Call the internal function */ + KeReleaseQueuedSpinLockFromDpcLevel((PKLOCK_QUEUE_HANDLE) + &LockHandle->LockQueue.Next); }
/* EOF */