diff --git a/xtoskrnl/includes/ke/pushlock.hh b/xtoskrnl/includes/ke/pushlock.hh index 4a6c536..0a7d1da 100644 --- a/xtoskrnl/includes/ke/pushlock.hh +++ b/xtoskrnl/includes/ke/pushlock.hh @@ -32,6 +32,8 @@ namespace KE STATIC XTFASTCALL VOID ReleaseWaitPushLock(IN PKPUSH_LOCK PushLock); STATIC XTFASTCALL BOOLEAN TryAcquireExclusivePushLock(PKPUSH_LOCK PushLock); STATIC XTFASTCALL VOID TryWakePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID UnblockPushLock(IN PKPUSH_LOCK PushLock, + IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock); STATIC XTFASTCALL VOID WaitOnPushLock(IN PKPUSH_LOCK PushLock); STATIC XTFASTCALL VOID WakePushLockWaiters(IN PKPUSH_LOCK PushLock, IN KPUSH_LOCK OldState); diff --git a/xtoskrnl/ke/pushlock.cc b/xtoskrnl/ke/pushlock.cc index 6540fab..30480c3 100644 --- a/xtoskrnl/ke/pushlock.cc +++ b/xtoskrnl/ke/pushlock.cc @@ -864,6 +864,61 @@ KE::PushLock::TryWakePushLock(IN PKPUSH_LOCK PushLock) } } +/** + * Unblocks an executive push lock and wakes up any pending threads waiting on it. + * + * @param PushLock + * Supplies a pointer to the executive push lock being unblocked. + * + * @param CurrentWaitBlock + * Optionally supplies a pointer to the current thread's push lock wait block. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::UnblockPushLock(IN PKPUSH_LOCK PushLock, + IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock) +{ + PKPUSH_LOCK_WAIT_BLOCK CurrentWaitBlock, NextWaitBlock; + + /* Capture the entire chain of wait blocks and clear the push lock pointer */ + CurrentWaitBlock = (PKPUSH_LOCK_WAIT_BLOCK)RTL::Atomic::ExchangePointer((PVOID *)&PushLock->Ptr, NULLPTR); + + /* Check if any wait blocks are present */ + if(CurrentWaitBlock) + { + /* Raise runlevel to DISPATCH level */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL, CurrentWaitBlock->Next); + + /* Iterate through the captured chain of wait blocks */ + while(CurrentWaitBlock) + { + /* Cache the next block pointer */ + NextWaitBlock = CurrentWaitBlock->Next; + + /* Test and clear the lock flag */ + if(!RTL::Atomic::BitTestAndReset((VOLATILE PLONG)&CurrentWaitBlock->Flags, KPUSHLOCK_LOCK)) + { + /* Boost priority and signal the wake event */ + KE::Event::SetEventBoostPriority(&CurrentWaitBlock->WakeEvent, NULLPTR); + } + + /* Advance to the next wait block */ + CurrentWaitBlock = NextWaitBlock; + } + } + + /* Check if a wait context was provided and its wait flag is pending */ + if(WaitBlock && (WaitBlock->Flags & KPUSHLOCK_WAITING)) + { + /* Suspend the thread until push lock wake event is signaled */ + KE::Dispatcher::WaitForSingleObject(&WaitBlock->WakeEvent, WrPushLock, KernelMode, FALSE, NULLPTR); + } +} + /** * Wakes threads waiting on a PushLock. *