/** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory * FILE: xtoskrnl/ke/spinlock.cc * DESCRIPTION: Spinlocks support * DEVELOPERS: Rafal Kupiec * Aiken Harris */ #include /** * Acquires a specified queued spinlock. * * @param LockLevel * Supplies the queued spinlock level. * * @return This routine does not return any value. * * @since XT 1.0 */ XTFASTCALL VOID KE::SpinLock::AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel) { /* Acquire the queued spinlock */ AcquireSpinLock(KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel].Lock); } /** * Acquires a kernel spin lock. * * @param SpinLock * Supplies a pointer to the kernel spin lock. * * @return This routine does not return any value. * * @since XT 1.0 */ XTFASTCALL VOID KE::SpinLock::AcquireSpinLock(IN OUT PKSPIN_LOCK SpinLock) { /* Try to acquire the lock */ while(RTL::Atomic::BitTestAndSet((PLONG)SpinLock, 0)) { /* Wait until locked is cleared */ while(*(VOLATILE PKSPIN_LOCK)SpinLock & 1) { /* Yield processor and keep waiting */ AR::CpuFunc::YieldProcessor(); } } /* Add an explicit memory barrier */ AR::CpuFunc::ReadWriteBarrier(); } /** * Initializes all kernel spinlocks. * * @return This routine does not return any value. * * @since XT 1.0 */ XTAPI VOID KE::SpinLock::InitializeAllLocks() { /* Initialize all spin locks */ InitializeSpinLock(&DispatcherLockQueue); InitializeSpinLock(&PfnLockQueue); InitializeSpinLock(&SystemSpaceLockQueue); } /** * Initializes spinlock queues for current processor. * * @return This routine does not return any value. * * @since XT 1.0 */ XTAPI VOID KE::SpinLock::InitializeLockQueues() { PKPROCESSOR_CONTROL_BLOCK ControlBlock; /* Get current processor control block */ ControlBlock = KE::Processor::GetCurrentProcessorControlBlock(); /* Initialize PCB lock queues */ ControlBlock->LockQueue[DispatcherLock].Lock = &DispatcherLockQueue; ControlBlock->LockQueue[DispatcherLock].Next = NULLPTR; ControlBlock->LockQueue[PfnLock].Lock = &PfnLockQueue; ControlBlock->LockQueue[PfnLock].Next = NULLPTR; ControlBlock->LockQueue[SystemSpaceLock].Lock = &SystemSpaceLockQueue; ControlBlock->LockQueue[SystemSpaceLock].Next = NULLPTR; } /** * Initializes a kernel spinlock object. * * @param SpinLock * Supplies a pointer to a kernel spin lock. * * @return This routine does not return any value. * * @since NT 3.5 */ XTAPI VOID KE::SpinLock::InitializeSpinLock(IN PKSPIN_LOCK SpinLock) { /* Zero initialize spinlock */ *SpinLock = 0; } /** * Releases a queued spinlock. * * @param LockLevel * Supplies the queued spinlock level. * * @return This routine does not return any value. * * @since XT 1.0 */ XTFASTCALL VOID KE::SpinLock::ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel) { /* Clear the lock */ ReleaseSpinLock(KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel].Lock); } /** * Releases a kernel spin lock. * * @param SpinLock * Supplies a pointer to the kernel spin lock. * * @return This routine does not return any value. * * @since XT 1.0 */ XTFASTCALL VOID KE::SpinLock::ReleaseSpinLock(IN OUT PKSPIN_LOCK SpinLock) { /* Clear the lock */ RTL::Atomic::And32((PLONG)SpinLock, 0); /* Add an explicit memory barrier */ AR::CpuFunc::ReadWriteBarrier(); } /** * Tests a kernel spin lock. * * @param SpinLock * Supplies a pointer to the kernel spin lock. * * @return This routine returns TRUE if the lock is free, FALSE otherwise. * * @since XT 1.0 */ XTFASTCALL BOOLEAN TestSpinLock(IN PKSPIN_LOCK SpinLock) { /* Check if the lock is free */ if(*SpinLock) { /* Spinlock is busy, yield processor and return FALSE */ AR::CpuFunc::YieldProcessor(); return FALSE; } /* Spinlock is free, return TRUE */ return TRUE; }