Extend rundown protection with counted acquire and release functions
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in 55s
Builds / ExectOS (i686, release) (push) Successful in 51s
Builds / ExectOS (amd64, release) (push) Successful in 1m3s
Builds / ExectOS (i686, debug) (push) Successful in 1m0s

This commit is contained in:
2026-06-22 11:22:09 +02:00
parent 7526f90759
commit e431bccd44
2 changed files with 134 additions and 0 deletions

View File

@@ -4,6 +4,7 @@
* FILE: xtoskrnl/ex/rundown.cc * FILE: xtoskrnl/ex/rundown.cc
* DESCRIPTION: Rundown protection mechanism * DESCRIPTION: Rundown protection mechanism
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org> * DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
* Aiken Harris <harraiken91@gmail.com>
*/ */
#include <xtos.hh> #include <xtos.hh>
@@ -57,6 +58,58 @@ EX::Rundown::AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor)
} }
} }
/**
* Acquires the rundown protection for given descriptor.
*
* @param Descriptor
* Supplies a pointer to the rundown block descriptor.
*
* @param Count
* Supplies the number of times the protection should be acquired.
*
* @return This routine returns TRUE if protection acquired successfully, or FALSE otherwise.
*
* @since XT 1.0
*/
XTFASTCALL
BOOLEAN
EX::Rundown::AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor,
IN ULONG Count)
{
ULONG_PTR CurrentValue, NewValue;
/* Get current value */
CurrentValue = Descriptor->Count;
/* Main loop execution */
while(TRUE)
{
/* Make sure protection is not active yet */
if(CurrentValue & 0x1)
{
/* Already active, nothing to do */
return FALSE;
}
/* Attempt to increment the usage count */
NewValue = CurrentValue + 2 * Count;
/* Exchange the value */
NewValue = (ULONG_PTR)RTL::Atomic::CompareExchangePointer(&Descriptor->Ptr, (PVOID)NewValue,
(PVOID)CurrentValue);
/* Make sure protection acquired */
if(NewValue == CurrentValue)
{
/* Successfully acquired protection */
return TRUE;
}
/* Update value and try once again */
CurrentValue = NewValue;
}
}
/** /**
* Marks the rundown descriptor as completed. * Marks the rundown descriptor as completed.
* *
@@ -71,6 +124,7 @@ XTFASTCALL
VOID VOID
EX::Rundown::CompleteProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) EX::Rundown::CompleteProtection(IN PEX_RUNDOWN_REFERENCE Descriptor)
{ {
/* Mark the descriptor as completely run down */
RTL::Atomic::ExchangePointer(&Descriptor->Ptr, (PVOID)EX_RUNDOWN_ACTIVE); RTL::Atomic::ExchangePointer(&Descriptor->Ptr, (PVOID)EX_RUNDOWN_ACTIVE);
} }
@@ -106,6 +160,7 @@ XTFASTCALL
VOID VOID
EX::Rundown::ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) EX::Rundown::ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor)
{ {
/* Reset the descriptor to its initial state */
RTL::Atomic::ExchangePointer(&Descriptor->Ptr, NULLPTR); RTL::Atomic::ExchangePointer(&Descriptor->Ptr, NULLPTR);
} }
@@ -126,19 +181,26 @@ EX::Rundown::ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor)
ULONG_PTR CurrentValue, NewValue; ULONG_PTR CurrentValue, NewValue;
PEX_RUNDOWN_WAIT_BLOCK WaitBlock; PEX_RUNDOWN_WAIT_BLOCK WaitBlock;
/* Read the current state of the rundown descriptor */
CurrentValue = Descriptor->Count; CurrentValue = Descriptor->Count;
/* Enter a CAS loop */
while(TRUE) while(TRUE)
{ {
/* Check if the rundown is currently active */
if(CurrentValue & 0x1) if(CurrentValue & 0x1)
{ {
/* Extract the pointer to the wait block */
WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(CurrentValue & ~0x1); WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(CurrentValue & ~0x1);
/* Decrement the pending reference count */
if(!RTL::Atomic::Decrement64((PLONG_PTR)&WaitBlock->Count)) if(!RTL::Atomic::Decrement64((PLONG_PTR)&WaitBlock->Count))
{ {
/* Signal the event to wake up the teardown thread */
KE::Event::SetEvent(&WaitBlock->WakeEvent, 0, FALSE); KE::Event::SetEvent(&WaitBlock->WakeEvent, 0, FALSE);
} }
/* Break the loop */
break; break;
} }
else else
@@ -150,11 +212,79 @@ EX::Rundown::ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor)
NewValue = (ULONG_PTR)RTL::Atomic::CompareExchangePointer(&Descriptor->Ptr, (PVOID)NewValue, NewValue = (ULONG_PTR)RTL::Atomic::CompareExchangePointer(&Descriptor->Ptr, (PVOID)NewValue,
(PVOID)CurrentValue); (PVOID)CurrentValue);
/* Check if the atomic swap succeeded without interference from other processors */
if(NewValue == CurrentValue) if(NewValue == CurrentValue)
{ {
/* Reference count is decremented, break the loop */
break; break;
} }
/* Collision detected, update current state and retry */
CurrentValue = NewValue;
}
}
}
/**
* Releases the rundown protection for given descriptor.
*
* @param Descriptor
* Supplies a pointer to the descriptor to be initialized.
*
* @param Count
* Supplies the number of references to release.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTFASTCALL
VOID
EX::Rundown::ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor,
IN ULONG Count)
{
ULONG_PTR CurrentValue, NewValue;
PEX_RUNDOWN_WAIT_BLOCK WaitBlock;
/* Read the current state of the rundown descriptor */
CurrentValue = Descriptor->Count;
/* Enter a CAS loop */
while(TRUE)
{
/* Check if the rundown is currently active */
if(CurrentValue & 0x1)
{
/* Extract the pointer to the wait block */
WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(CurrentValue & ~0x1);
/* Decrement the pending reference count */
if(!RTL::Atomic::Decrement64((PLONG_PTR)&WaitBlock->Count))
{
/* Signal the event to wake up the teardown thread */
KE::Event::SetEvent(&WaitBlock->WakeEvent, 0, FALSE);
}
/* Break the loop */
break;
}
else
{
/* Attempt to decrement the usage count */
NewValue = CurrentValue - 2 * Count;
/* Exchange the value */
NewValue = (ULONG_PTR)RTL::Atomic::CompareExchangePointer(&Descriptor->Ptr, (PVOID)NewValue,
(PVOID)CurrentValue);
/* Check if the atomic swap succeeded without interference from other processors */
if(NewValue == CurrentValue)
{
/* Reference count is decremented, break the loop */
break;
}
/* Collision detected, update current state and retry */
CurrentValue = NewValue; CurrentValue = NewValue;
} }
} }

View File

@@ -19,10 +19,14 @@ namespace EX
{ {
public: public:
STATIC XTFASTCALL BOOLEAN AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL BOOLEAN AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor);
STATIC XTFASTCALL BOOLEAN AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor,
IN ULONG Count);
STATIC XTFASTCALL VOID CompleteProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID CompleteProtection(IN PEX_RUNDOWN_REFERENCE Descriptor);
STATIC XTFASTCALL VOID InitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID InitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor);
STATIC XTFASTCALL VOID ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor);
STATIC XTFASTCALL VOID ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor);
STATIC XTFASTCALL VOID ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor,
IN ULONG Count);
STATIC XTFASTCALL VOID WaitForProtectionRelease(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID WaitForProtectionRelease(IN PEX_RUNDOWN_REFERENCE Descriptor);
}; };
} }