- Implemented InterlockedBitTestAndReset, InterlockedBitTestAndSet, InterlockedExchangeAddSizeT.

- Rundown re-implementation:

* Added inlined functions for internal system use for quickest path.
* Correctly named all functions Exf instead of Ex.
* Removed PAGED_CODE(); macro where it shouldn't be used.
* Addded multiple ASSERTS for sanity checks.
* Used macros for win64/32 portability.
* Fixed the following bugs/features:
    * ExfAcquireRundownProtection:
        ** Added specific code instead of calling the generic function. Rundown locks are
           performance critical and a dedicated path is prefered.
    * ExfAcquireRundownProtectionEx:
        ** Added a quick immediate check to see if the rundown is active.
    * ExfReleaseRundownProtection:
        ** Added specific code instead of calling the generic function. Rundown locks are
           performance critical and a dedicated path is prefered.
    * ExfReleaseRundownProtectionEx: 
        ** Simplified the loop code.
        ** Fixed a bug in signaling of the event during waitblock count removal
    * ExfWaitForRundownProtectionRelease:
        ** Add quick case when we don't actually need a full wait.
        ** Simplified loop code.
* Added stubs for cache-aware implementation.
* Documented the functions.

svn path=/trunk/; revision=20435
This commit is contained in:
Alex Ionescu 2005-12-29 19:12:09 +00:00
parent 8b5a187ddc
commit ea4fcb6188
7 changed files with 793 additions and 230 deletions

View file

@ -37,11 +37,62 @@ typedef struct _EVENT_TRACE_HEADER *PEVENT_TRACE_HEADER;
//
VOID
FASTCALL
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex);
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(
PFAST_MUTEX FastMutex
);
VOID
FASTCALL
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(PFAST_MUTEX FastMutex);
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(
PFAST_MUTEX FastMutex
);
//
// Pushlock functions
//
VOID
FASTCALL
ExfAcquirePushLockExclusive(
PEX_PUSH_LOCK PushLock
);
VOID
FASTCALL
ExfAcquirePushLockShared(
PEX_PUSH_LOCK PushLock
);
VOID
FASTCALL
ExfReleasePushLock(
PEX_PUSH_LOCK PushLock
);
VOID
FASTCALL
ExfReleasePushLockExclusive(
PEX_PUSH_LOCK PushLock
);
VOID
FASTCALL
ExfReleasePushLockShared(
PEX_PUSH_LOCK PushLock
);
VOID
FASTCALL
ExfTryToWakePushLock(
PEX_PUSH_LOCK PushLock
);
VOID
FASTCALL
ExfUnblockPushLock(
PEX_PUSH_LOCK PushLock,
PVOID CurrentWaitBlock
);
#endif
//

View file

@ -147,7 +147,7 @@ CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
if(!CurrentCallback->PendingDelete &&
ExAcquireRundownProtectionEx(&CurrentCallback->RundownRef, 1))
ExAcquireRundownProtection(&CurrentCallback->RundownRef))
{
/* don't hold locks during the callbacks! */
ExReleaseFastMutex(&CmiCallbackLock);
@ -160,7 +160,7 @@ CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
/* don't release the rundown protection before holding the callback lock
so the pointer to the next callback isn't cleared in case this callback
get's deleted */
ExReleaseRundownProtectionEx(&CurrentCallback->RundownRef, 1);
ExReleaseRundownProtection(&CurrentCallback->RundownRef);
if(!NT_SUCCESS(Status))
{
/* one callback returned failure, don't call any more callbacks */

View file

@ -1,10 +1,10 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ex/rundown.c
* PURPOSE: Rundown Protection Functions
*
* PROGRAMMERS: Alex Ionescu & Thomas Weidenmueller - Implementation
* PURPOSE: Rundown and Cache-Aware Rundown Protection
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Thomas Weidenmueller
*/
/* INCLUDES *****************************************************************/
@ -15,261 +15,489 @@
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
/*++
* @name ExfAcquireRundownProtection
* @implemented NT5.1
*
* The ExfAcquireRundownProtection routine acquires rundown protection for
* the specified descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return TRUE if access to the protected structure was granted, FALSE otherwise.
*
* @remarks Callers of ExfAcquireRundownProtection can be running at any IRQL.
*
*--*/
BOOLEAN
FASTCALL
ExAcquireRundownProtection (
IN PEX_RUNDOWN_REF RunRef
)
ExfAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
/* Call the general function with only one Reference add */
return ExAcquireRundownProtectionEx(RunRef, 1);
ULONG_PTR Value = RunRef->Count, NewValue;
/* Make sure a rundown is not active */
if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
/* Loop until successfully incremented the counter */
for (;;)
{
/* Add a reference */
NewValue = Value + EX_RUNDOWN_COUNT_INC;
/* Change the value */
Value = ExpChangeRundown(RunRef, NewValue, Value);
if (Value == NewValue) return TRUE;
/* Make sure a rundown is not active */
if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
}
}
/*
* @implemented
*/
/*++
* @name ExfAcquireRundownProtectionEx
* @implemented NT5.2
*
* The ExfAcquireRundownProtectionEx routine acquires multiple rundown
* protection references for the specified descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @param Count
* Number of times to reference the descriptor.
*
* @return TRUE if access to the protected structure was granted, FALSE otherwise.
*
* @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL.
*
*--*/
BOOLEAN
FASTCALL
ExAcquireRundownProtectionEx (
IN PEX_RUNDOWN_REF RunRef,
IN ULONG Count
)
ExfAcquireRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef,
IN ULONG Count)
{
ULONG_PTR PrevCount, Current;
ULONG_PTR Value = RunRef->Count, NewValue;
PAGED_CODE();
/* Make sure a rundown is not active */
if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
/* Convert the count to our internal representation */
Count <<= EX_RUNDOWN_COUNT_SHIFT;
/* Loop until successfully incremented the counter */
do
for (;;)
{
Current = RunRef->Count;
/* Add references */
NewValue = Value + Count;
/* Change the value */
Value = ExpChangeRundown(RunRef, NewValue, Value);
if (Value == NewValue) return TRUE;
/* Make sure a rundown is not active */
if (Current & EX_RUNDOWN_ACTIVE)
{
return FALSE;
}
#ifdef _WIN64
PrevCount = (ULONG_PTR)InterlockedExchangeAdd64((LONGLONG*)&RunRef->Count, (LONGLONG)Count);
#else
PrevCount = (ULONG_PTR)InterlockedExchangeAdd((LONG*)&RunRef->Count, (LONG)Count);
#endif
} while (PrevCount != Current);
/* Return Success */
return TRUE;
if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
}
}
/*
* @implemented
*/
/*++
* @name ExfInitializeRundownProtection
* @implemented NT5.1
*
* The ExfInitializeRundownProtection routine initializes a rundown
* protection descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks Callers of ExfInitializeRundownProtection can be running at any IRQL.
*
*--*/
VOID
FASTCALL
ExInitializeRundownProtection (
IN PEX_RUNDOWN_REF RunRef
)
ExfInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
PAGED_CODE();
/* Set the count to zero */
RunRef->Count = 0;
}
/*
* @implemented
*/
/*++
* @name ExfReInitializeRundownProtection
* @implemented NT5.1
*
* The ExfReInitializeRundownProtection routine re-initializes a rundown
* protection descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks Callers of ExfReInitializeRundownProtection can be running at any IRQL.
*
*--*/
VOID
FASTCALL
ExReInitializeRundownProtection (
IN PEX_RUNDOWN_REF RunRef
)
ExfReInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
PAGED_CODE();
/* Sanity check */
ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
/* Reset the count */
#ifdef _WIN64
InterlockedExchange64((LONGLONG*)&RunRef->Count, 0LL);
#else
InterlockedExchange((LONG*)&RunRef->Count, 0);
#endif
InterlockedExchange((PLONG)&RunRef->Count, 0);
}
/*
* @implemented
*/
/*++
* @name ExfRundownCompleted
* @implemented NT5.1
*
* The ExfRundownCompleted routine completes the rundown of the specified
* descriptor by setting the active bit.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks Callers of ExfRundownCompleted must be running at IRQL <= APC_LEVEL.
*
*--*/
VOID
FASTCALL
ExReleaseRundownProtectionEx (
IN PEX_RUNDOWN_REF RunRef,
IN ULONG Count
)
ExfRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
{
PAGED_CODE();
Count <<= EX_RUNDOWN_COUNT_SHIFT;
/* Sanity check */
ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
for (;;)
/* Mark the counter as active */
InterlockedExchange((PLONG)&RunRef->Count, EX_RUNDOWN_ACTIVE);
}
/*++
* @name ExfReleaseRundownProtection
* @implemented NT5.1
*
* The ExfReleaseRundownProtection routine releases the rundown protection
* reference for the specified descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks Callers of ExfReleaseRundownProtection can be running at any IRQL.
*
*--*/
VOID
FASTCALL
ExfReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
ULONG_PTR Value = RunRef->Count, NewValue;
PEX_RUNDOWN_WAIT_BLOCK WaitBlock;
/* Check if rundown is not active */
if (!(Value & EX_RUNDOWN_ACTIVE))
{
ULONG_PTR Current = RunRef->Count;
/* Check if Rundown is active */
if (Current & EX_RUNDOWN_ACTIVE)
{
/* Get Pointer */
PEX_RUNDOWN_WAIT_BLOCK RundownDescriptor = (PEX_RUNDOWN_WAIT_BLOCK)(Current & ~EX_RUNDOWN_ACTIVE);
if (RundownDescriptor == NULL)
{
/* the rundown was completed and there's no one to notify */
break;
}
Current = RundownDescriptor->Count;
/* Decrease RundownDescriptor->Count by Count Count */
for (;;)
{
ULONG_PTR PrevCount, NewCount;
if ((Count >> EX_RUNDOWN_COUNT_SHIFT) == Current)
{
NewCount = 0;
}
else
{
NewCount = ((RundownDescriptor->Count - (Count >> EX_RUNDOWN_COUNT_SHIFT)) << EX_RUNDOWN_COUNT_SHIFT) | EX_RUNDOWN_ACTIVE;
}
#ifdef _WIN64
PrevCount = (ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RundownDescriptor->Count, (LONGLONG)NewCount, (LONGLONG)Current);
#else
PrevCount = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RundownDescriptor->Count, (LONG)NewCount, (LONG)Current);
#endif
if (PrevCount == Current)
{
if (NewCount == 0)
{
/* Signal the event so anyone waiting on it can now kill it */
KeSetEvent(&RundownDescriptor->RundownEvent, 0, FALSE);
}
/* Successfully decremented the counter, so bail! */
break;
}
Current = PrevCount;
}
break;
}
else
{
ULONG_PTR PrevCount, NewCount = Current - (ULONG_PTR)Count;
#ifdef _WIN64
PrevCount = (ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Count, (LONGLONG)NewCount, (LONGLONG)Current);
#else
PrevCount = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Count, (LONG)NewCount, (LONG)Current);
#endif
if (PrevCount == Current)
{
/* Successfully decremented the counter, so bail! */
break;
}
}
}
}
/*
* @implemented
*/
VOID
FASTCALL
ExReleaseRundownProtection (
IN PEX_RUNDOWN_REF RunRef
)
{
/* Call the general function with only 1 reference removal */
ExReleaseRundownProtectionEx(RunRef, 1);
}
/*
* @implemented
*/
VOID
FASTCALL
ExRundownCompleted (
IN PEX_RUNDOWN_REF RunRef
)
{
PAGED_CODE();
/* mark the counter as active */
#ifdef _WIN64
InterlockedExchange64((LONGLONG*)&RunRef->Count, (LONGLONG)EX_RUNDOWN_ACTIVE);
#else
InterlockedExchange((LONG*)&RunRef->Count, EX_RUNDOWN_ACTIVE);
#endif
}
/*
* @implemented
*/
VOID
FASTCALL
ExWaitForRundownProtectionRelease (
IN PEX_RUNDOWN_REF RunRef
)
{
ULONG_PTR PrevCount, NewPtr, PrevPtr;
EX_RUNDOWN_WAIT_BLOCK RundownDescriptor;
PAGED_CODE();
PrevCount = RunRef->Count;
if (PrevCount != 0 && !(PrevCount & EX_RUNDOWN_ACTIVE))
{
/* save the reference counter */
RundownDescriptor.Count = PrevCount >> EX_RUNDOWN_COUNT_SHIFT;
/* Pending Count... wait on them to be closed with an event */
KeInitializeEvent(&RundownDescriptor.RundownEvent, NotificationEvent, FALSE);
ASSERT(!((ULONG_PTR)&RundownDescriptor & EX_RUNDOWN_ACTIVE));
NewPtr = (ULONG_PTR)&RundownDescriptor | EX_RUNDOWN_ACTIVE;
/* Loop until successfully incremented the counter */
for (;;)
{
#ifdef _WIN64
PrevPtr = (ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Ptr, (LONGLONG)NewPtr, (LONGLONG)PrevCount);
#else
PrevPtr = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Ptr, (LONG)NewPtr, (LONG)PrevCount);
#endif
if (PrevPtr == PrevCount)
{
/* Wait for whoever needs to release to notify us */
KeWaitForSingleObject(&RundownDescriptor.RundownEvent, Executive, KernelMode, FALSE, NULL);
break;
}
else if (PrevPtr == 0 || (PrevPtr & EX_RUNDOWN_ACTIVE))
{
/* some one else was faster, let's just bail */
break;
}
/* Sanity check */
ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
PrevCount = PrevPtr;
/* Get the new value */
NewValue = Value - EX_RUNDOWN_COUNT_INC;
/* save the changed reference counter and try again */
RundownDescriptor.Count = PrevCount >> EX_RUNDOWN_COUNT_SHIFT;
/* Change the value */
Value = ExpChangeRundown(RunRef, NewValue, Value);
if (Value == NewValue) return;
/* Loop again if we're still not active */
if (Value & EX_RUNDOWN_ACTIVE) break;
}
}
/* Get the wait block */
WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE);
ASSERT((WaitBlock->Count > 0) || (KeNumberProcessors > 1));
/* Remove the one count */
if (InterlockedExchangeAddSizeT(&WaitBlock->Count, -1))
{
/* We're down to 0 now, so signal the event */
KeSetEvent(&WaitBlock->RundownEvent, IO_NO_INCREMENT, FALSE);
}
}
/*++
* @name ExfReleaseRundownProtectionEx
* @implemented NT5.2
*
* The ExfReleaseRundownProtectionEx routine releases multiple rundown
* protection references for the specified descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @param Count
* Number of times to dereference the descriptor.
*
* @return None.
*
* @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL.
*
*--*/
VOID
FASTCALL
ExfReleaseRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef,
IN ULONG Count)
{
ULONG_PTR Value = RunRef->Count, NewValue;
PEX_RUNDOWN_WAIT_BLOCK WaitBlock;
/* Check if rundown is not active */
if (!(Value & EX_RUNDOWN_ACTIVE))
{
/* Loop until successfully incremented the counter */
for (;;)
{
/* Sanity check */
ASSERT((Value >= EX_RUNDOWN_COUNT_INC * Count) || (KeNumberProcessors > 1));
/* Get the new value */
NewValue = Value - (Count * EX_RUNDOWN_COUNT_INC);
/* Change the value */
Value = ExpChangeRundown(RunRef, NewValue, Value);
if (Value == NewValue) return;
/* Loop again if we're still not active */
if (Value & EX_RUNDOWN_ACTIVE) break;
}
}
/* Get the wait block */
WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE);
ASSERT((WaitBlock->Count >= Count) || (KeNumberProcessors > 1));
/* Remove the count */
if (InterlockedExchangeAddSizeT(WaitBlock->Count, -(LONG)Count) ==
(LONG)Count)
{
/* We're down to 0 now, so signal the event */
KeSetEvent(&WaitBlock->RundownEvent, IO_NO_INCREMENT, FALSE);
}
}
/*++
* @name ExfWaitForRundownProtectionRelease
* @implemented NT5.1
*
* The ExfWaitForRundownProtectionRelease routine waits until the specified
* rundown descriptor has been released.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks Callers of ExfWaitForRundownProtectionRelease must be running
* at IRQL <= APC_LEVEL.
*
*--*/
VOID
FASTCALL
ExfWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
{
ULONG_PTR Value, Count, NewValue;
EX_RUNDOWN_WAIT_BLOCK WaitBlock;
PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer;
PKEVENT Event;
PAGED_CODE();
/* Set the active bit */
Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
if ((Value == 0) || (Value == EX_RUNDOWN_ACTIVE)) return;
/* No event for now */
Event = NULL;
WaitBlockPointer = (PEX_RUNDOWN_WAIT_BLOCK)((ULONG_PTR)&WaitBlock |
EX_RUNDOWN_ACTIVE);
/* Start waitblock set loop */
for(;;)
{
/* Save the count */
Count = Value >> EX_RUNDOWN_COUNT_SHIFT;
/* If the count is over one or we don't have en event yet, create it */
if (Count || !Event)
{
/* Initialize the event */
KeInitializeEvent(&WaitBlock.RundownEvent,
NotificationEvent,
FALSE);
/* Set the pointer */
Event = &WaitBlock.RundownEvent;
}
/* Set the count */
WaitBlock.Count = Count;
/* Now set the pointer */
NewValue = ExpChangeRundown(RunRef, PtrToUlong(WaitBlockPointer), Value);
if (NewValue == Value) break;
/* Loop again */
Value = NewValue;
ASSERT((Value & EX_RUNDOWN_ACTIVE) == 0);
}
/* If the count was 0, we're done */
if (!Count) return;
/* Wait for whoever needs to release to notify us */
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
ASSERT(WaitBlock.Count == 0);
}
/* FIXME: STUBS **************************************************************/
/*
* @unimplemented NT5.2
*/
BOOLEAN
FASTCALL
ExfAcquireRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented NT5.2
*/
BOOLEAN
FASTCALL
ExfAcquireRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
IN ULONG Count)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
DBG_UNREFERENCED_PARAMETER(Count);
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented NT5.2
*/
VOID
FASTCALL
ExfReleaseRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
VOID
FASTCALL
ExfReleaseRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
IN ULONG Count)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
DBG_UNREFERENCED_PARAMETER(Count);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
VOID
FASTCALL
ExfWaitForRundownProtectionReleaseCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
VOID
FASTCALL
ExfRundownCompletedCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
VOID
FASTCALL
ExfReInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
PEX_RUNDOWN_REF_CACHE_AWARE
NTAPI
ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType,
IN ULONG Tag)
{
DBG_UNREFERENCED_PARAMETER(PoolType);
DBG_UNREFERENCED_PARAMETER(Tag);
UNIMPLEMENTED;
return NULL;
}
/*
* @unimplemented NT5.2
*/
VOID
NTAPI
ExFreeCacheAwareRundownProtection(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
VOID
NTAPI
ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
IN ULONG Count)
{
DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
DBG_UNREFERENCED_PARAMETER(Count);
UNIMPLEMENTED;
}
/*
* @unimplemented NT5.2
*/
SIZE_T
NTAPI
ExSizeOfRundownProtectionCacheAware(VOID)
{
UNIMPLEMENTED;
return 0;
}
/* EOF */

View file

@ -77,6 +77,58 @@ VOID
STDCALL
ExpInitializeProfileImplementation(VOID);
/* Rundown Functions ********************************************************/
VOID
FASTCALL
ExfInitializeRundownProtection(
OUT PEX_RUNDOWN_REF RunRef
);
VOID
FASTCALL
ExfReInitializeRundownProtection(
OUT PEX_RUNDOWN_REF RunRef
);
BOOLEAN
FASTCALL
ExfAcquireRundownProtection(
IN OUT PEX_RUNDOWN_REF RunRef
);
BOOLEAN
FASTCALL
ExfAcquireRundownProtectionEx(
IN OUT PEX_RUNDOWN_REF RunRef,
IN ULONG Count
);
VOID
FASTCALL
ExfReleaseRundownProtection(
IN OUT PEX_RUNDOWN_REF RunRef
);
VOID
FASTCALL
ExfReleaseRundownProtectionEx(
IN OUT PEX_RUNDOWN_REF RunRef,
IN ULONG Count
);
VOID
FASTCALL
ExfRundownCompleted(
OUT PEX_RUNDOWN_REF RunRef
);
VOID
FASTCALL
ExfWaitForRundownProtectionRelease(
IN OUT PEX_RUNDOWN_REF RunRef
);
/* HANDLE TABLE FUNCTIONS ***************************************************/
#define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1))
@ -192,6 +244,184 @@ static __inline _SEH_FILTER(_SEH_ExSystemExceptionFilter)
return ExSystemExceptionFilter();
}
/* RUNDOWN *******************************************************************/
#ifdef _WIN64
#define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
#define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
#else
#define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, y, z)
#define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
#endif
/*++
* @name ExfAcquireRundownProtection
* INTERNAL MACRO
*
* The ExfAcquireRundownProtection routine acquires rundown protection for
* the specified descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return TRUE if access to the protected structure was granted, FALSE otherwise.
*
* @remarks This is the internal macro for system use only.In case the rundown
* was active, then the slow-path will be called through the exported
* function.
*
*--*/
BOOLEAN
FORCEINLINE
ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
ULONG_PTR Value, NewValue, OldValue;
/* Get the current value and mask the active bit */
Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
/* Add a reference */
NewValue = Value + EX_RUNDOWN_COUNT_INC;
/* Change the value */
OldValue = ExpChangeRundown(RunRef, NewValue, Value);
if (OldValue != Value)
{
/* Rundown was active, use long path */
return ExfAcquireRundownProtection(RunRef);
}
/* Success */
return TRUE;
}
/*++
* @name ExReleaseRundownProtection
* INTERNAL MACRO
*
* The ExReleaseRundownProtection routine releases rundown protection for
* the specified descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return TRUE if access to the protected structure was granted, FALSE otherwise.
*
* @remarks This is the internal macro for system use only.In case the rundown
* was active, then the slow-path will be called through the exported
* function.
*
*--*/
VOID
FORCEINLINE
ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
ULONG_PTR Value, NewValue, OldValue;
/* Get the current value and mask the active bit */
Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
/* Remove a reference */
NewValue = Value - EX_RUNDOWN_COUNT_INC;
/* Change the value */
OldValue = ExpChangeRundown(RunRef, NewValue, Value);
/* Check if the rundown was active */
if (OldValue != Value)
{
/* Rundown was active, use long path */
ExfReleaseRundownProtection(RunRef);
}
else
{
/* Sanity check */
ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
}
}
/*++
* @name ExInitializeRundownProtection
* INTERNAL MACRO
*
* The ExInitializeRundownProtection routine initializes a rundown
* protection descriptor.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks This is the internal macro for system use only.
*
*--*/
VOID
FORCEINLINE
ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
{
/* Set the count to zero */
RunRef->Count = 0;
}
/*++
* @name ExWaitForRundownProtectionRelease
* INTERNAL MACRO
*
* The ExWaitForRundownProtectionRelease routine waits until the specified
* rundown descriptor has been released.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks This is the internal macro for system use only. If a wait is actually
* necessary, then the slow path is taken through the exported function.
*
*--*/
VOID
FORCEINLINE
ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
{
ULONG_PTR Value;
/* Set the active bit */
Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
if ((Value) || (Value != EX_RUNDOWN_ACTIVE))
{
/* If the the rundown wasn't already active, then take the long path */
ExfWaitForRundownProtectionRelease(RunRef);
}
}
/*++
* @name ExRundownCompleted
* INTERNAL MACRO
*
* The ExRundownCompleted routine completes the rundown of the specified
* descriptor by setting the active bit.
*
* @param RunRef
* Pointer to a rundown reference descriptor.
*
* @return None.
*
* @remarks This is the internal macro for system use only.
*
*--*/
VOID
FORCEINLINE
ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
{
/* Sanity check */
ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
/* Mark the counter as active */
ExpSetRundown(&RunRef->Count, EX_RUNDOWN_ACTIVE);
}
/* OTHER FUNCTIONS **********************************************************/
LONGLONG

View file

@ -65,11 +65,28 @@ DbgQueryDebugFilterState@8
DbgSetDebugFilterState@12
@ExiAcquireFastMutex@4=@ExAcquireFastMutex@4
@ExAcquireFastMutexUnsafe@4
ExAcquireRundownProtection=@ExfAcquireRundownProtection@4
ExAcquireRundownProtectionCacheAware=@ExfAcquireRundownProtectionCacheAware@4
ExAcquireRundownProtectionCacheAwareEx=@ExfAcquireRundownProtectionCacheAwareEx@8
ExAcquireRundownProtectionEx=@ExfAcquireRundownProtectionEx@8
ExInitializeRundownProtection=@ExfInitializeRundownProtection@4
ExReInitializeRundownProtection=@ExfReInitializeRundownProtection@4
ExReInitializeRundownProtectionCacheAware=@ExfReInitializeRundownProtectionCacheAware@4
ExReleaseRundownProtection=@ExfReleaseRundownProtection@4
ExReleaseRundownProtectionCacheAware=@ExfReleaseRundownProtectionCacheAware@4
ExReleaseRundownProtectionCacheAwareEx=@ExfReleaseRundownProtectionCacheAwareEx@8
ExReleaseRundownProtectionEx=@ExfReleaseRundownProtectionEx@8
ExRundownCompleted=@ExfRundownCompleted@4
ExRundownCompletedCacheAware=@ExfRundownCompletedCacheAware@4
ExWaitForRundownProtectionRelease=@ExfWaitForRundownProtectionRelease@4
ExWaitForRundownProtectionReleaseCacheAware=@ExfWaitForRundownProtectionReleaseCacheAware@4
ExAllocateCacheAwareRundownProtection@8
ExFreeCacheAwareRundownProtection@4
ExInitializeRundownProtectionCacheAware@8
ExSizeOfRundownProtectionCacheAware@0
ExAcquireResourceExclusive@8
ExAcquireResourceExclusiveLite@8
ExAcquireResourceSharedLite@8
@ExAcquireRundownProtection@4
@ExAcquireRundownProtectionEx@8
ExAcquireSharedStarveExclusive@8
ExAcquireSharedWaitForExclusive@8
ExAllocateFromPagedLookasideList@4=ExiAllocateFromPagedLookasideList@4
@ -98,7 +115,6 @@ ExGetCurrentProcessorCpuUsage@4
ExGetExclusiveWaiterCount@4
ExGetPreviousMode@0
ExGetSharedWaiterCount@4
@ExInitializeRundownProtection@4
ExInitializeNPagedLookasideList@28
ExInitializePagedLookasideList@28
ExInitializeResource@4
@ -134,16 +150,12 @@ ExRaiseHardError@24
ExRaiseStatus@4=RtlRaiseStatus@4
ExRegisterCallback@12
ExReinitializeResourceLite@4
@ExReInitializeRundownProtection@4
@ExiReleaseFastMutex@4=@ExReleaseFastMutex@4
@ExReleaseFastMutexUnsafe@4
@ExReleaseFastMutexUnsafeAndLeaveCriticalRegion@4
ExReleaseResourceForThread@8
ExReleaseResourceForThreadLite@8
@ExReleaseResourceLite@4
@ExReleaseRundownProtection@4
@ExReleaseRundownProtectionEx@8
@ExRundownCompleted@4
ExSemaphoreObjectType DATA
ExSetResourceOwnerPointer@8
ExSetTimerResolution@8
@ -153,11 +165,7 @@ ExTryToAcquireResourceExclusiveLite@4
ExUnregisterCallback@4
ExUuidCreate@4
ExVerifySuite@4
@ExWaitForRundownProtectionRelease@4
ExWindowStationObjectType DATA
@ExfAcquirePushLockExclusive@4
@ExfAcquirePushLockShared@4
@ExfReleasePushLock@4
@ExfInterlockedAddUlong@12
@ExfInterlockedInsertHeadList@12
@ExfInterlockedInsertTailList@12

View file

@ -146,7 +146,6 @@
<file>resource.c</file>
<file>rundown.c</file>
<file>sem.c</file>
<file>synch.c</file>
<file>sysinfo.c</file>
<file>time.c</file>
<file>timer.c</file>

View file

@ -3692,6 +3692,53 @@ static __inline PVOID GetFiberData(void)
return *((PVOID *)GetCurrentFiber());
}
#if defined(__GNUC__)
static __inline__ BOOLEAN
InterlockedBitTestAndSet(IN LONG *Base,
IN LONG Bit)
{
LONG OldBit;
__asm__ __volatile__("lock"
"btsl %2,%1\n\t"
"sbbl %0,%0\n\t"
:"=r" (OldBit),"=m" (*Base)
:"Ir" (Bit)
: "memory");
return OldBit;
}
static __inline__ BOOLEAN
InterlockedBitTestAndReset(IN LONG *Base,
IN LONG Bit)
{
LONG OldBit;
__asm__ __volatile__("lock"
"btrl %2,%1\n\t"
"sbbl %0,%0\n\t"
:"=r" (OldBit),"=m" (*Base)
:"Ir" (Bit)
: "memory");
return OldBit;
}
#endif
#if defined(_AMD64_)
#if defined(_M_AMD64)
#define InterlockedExchangeAddSizeT(a, b) InterlockedExchangeAdd64((LONG64 *)a, b)
#endif
#else
#define InterlockedExchangeAddSizeT(a, b) InterlockedExchangeAdd((LONG *)a, b)
#endif
#endif /* RC_INVOKED */
#ifdef __cplusplus