mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
hopefully a better implementation of rundown protections, thanks also to Alex.
svn path=/trunk/; revision=11395
This commit is contained in:
parent
1270089c9f
commit
75009fd35f
2 changed files with 129 additions and 49 deletions
|
@ -1,4 +1,4 @@
|
|||
/* $Id: extypes.h,v 1.24 2004/10/03 03:03:53 ion Exp $ */
|
||||
/* $Id: extypes.h,v 1.25 2004/10/22 22:49:00 weiden Exp $ */
|
||||
|
||||
#ifndef __INCLUDE_DDK_EXTYPES_H
|
||||
#define __INCLUDE_DDK_EXTYPES_H
|
||||
|
@ -39,16 +39,18 @@ typedef struct _ERESOURCE
|
|||
} ERESOURCE, *PERESOURCE;
|
||||
|
||||
#define EX_RUNDOWN_ACTIVE 0x1
|
||||
#define EX_RUNDOWN_COUNT_SHIFT 0x1
|
||||
#define EX_RUNDOWN_COUNT_INC (0x1 << EX_RUNDOWN_COUNT_SHIFT)
|
||||
|
||||
typedef struct _RUNDOWN_DESCRIPTOR {
|
||||
ULONG References;
|
||||
PKEVENT RundownEvent;
|
||||
ULONG_PTR References;
|
||||
KEVENT RundownEvent;
|
||||
} RUNDOWN_DESCRIPTOR, *PRUNDOWN_DESCRIPTOR;
|
||||
|
||||
typedef struct _EX_RUNDOWN_REF {
|
||||
union {
|
||||
ULONG_PTR Count;
|
||||
PRUNDOWN_DESCRIPTOR Pointer;
|
||||
PRUNDOWN_DESCRIPTOR Ptr;
|
||||
};
|
||||
} EX_RUNDOWN_REF, *PEX_RUNDOWN_REF;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* ReactOS kernel
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
|
||||
* Copyright (C) 1998 - 2004 ReactOS Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -54,11 +54,27 @@ ExAcquireRundownProtectionEx (
|
|||
IN ULONG Count
|
||||
)
|
||||
{
|
||||
/* Make sure a Rundown is not in progress */
|
||||
if (RunRef->Count & EX_RUNDOWN_ACTIVE) return FALSE;
|
||||
ULONG_PTR PrevCount, Current;
|
||||
|
||||
Count <<= EX_RUNDOWN_COUNT_SHIFT;
|
||||
|
||||
/* Loop until successfully incremented the counter */
|
||||
do
|
||||
{
|
||||
Current = RunRef->Count;
|
||||
|
||||
/* Make sure a rundown is not active */
|
||||
if (Current & EX_RUNDOWN_ACTIVE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Increment Reference Count */
|
||||
RunRef->Count += Count * 2;
|
||||
#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;
|
||||
|
@ -87,7 +103,11 @@ ExReInitializeRundownProtection (
|
|||
)
|
||||
{
|
||||
/* Reset the count */
|
||||
RunRef->Count = 0;
|
||||
#ifdef _WIN64
|
||||
InterlockedExchangeAdd64((LONGLONG*)&RunRef->Count, 0LL);
|
||||
#else
|
||||
InterlockedExchangeAdd((LONG*)&RunRef->Count, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -101,26 +121,67 @@ ExReleaseRundownProtectionEx (
|
|||
IN ULONG Count
|
||||
)
|
||||
{
|
||||
PRUNDOWN_DESCRIPTOR RundownDescriptor;
|
||||
Count <<= EX_RUNDOWN_COUNT_SHIFT;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ULONG_PTR Current = RunRef->Count;
|
||||
|
||||
/* Check if Rundown is active */
|
||||
if (Current & EX_RUNDOWN_ACTIVE)
|
||||
{
|
||||
/* Get Pointer */
|
||||
PRUNDOWN_DESCRIPTOR RundownDescriptor = (PRUNDOWN_DESCRIPTOR)((ULONG_PTR)RunRef->Ptr & ~EX_RUNDOWN_ACTIVE);
|
||||
|
||||
/* Check if Rundown is in progress */
|
||||
if (RunRef->Count & EX_RUNDOWN_ACTIVE) {
|
||||
/* Decrease Reference Count by RundownDescriptor->References */
|
||||
for (;;)
|
||||
{
|
||||
ULONG_PTR PrevCount, NewCount;
|
||||
|
||||
/* Get Pointer */
|
||||
RundownDescriptor = RunRef->Pointer;
|
||||
if ((Current >> EX_RUNDOWN_COUNT_SHIFT) == RundownDescriptor->References)
|
||||
{
|
||||
NewCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewCount = (((Current >> EX_RUNDOWN_COUNT_SHIFT) - RundownDescriptor->References) << EX_RUNDOWN_COUNT_SHIFT) | EX_RUNDOWN_ACTIVE;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
if (NewCount == 0)
|
||||
{
|
||||
/* Signal the event so anyone waiting on it can now kill it */
|
||||
KeSetEvent(&RundownDescriptor->RundownEvent, 0, FALSE);
|
||||
}
|
||||
|
||||
/* Decrease Reference Count */
|
||||
RundownDescriptor->References -= Count;
|
||||
|
||||
/* If anyone else is still referencing, don't signal the event */
|
||||
if (RundownDescriptor->References) return;
|
||||
|
||||
/* Signal the event so anyone waiting on it can now kill it */
|
||||
KeSetEvent(RundownDescriptor->RundownEvent, 0, FALSE);
|
||||
|
||||
} else {
|
||||
/* Decrease Count */
|
||||
RunRef->Count -= Count * 2;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +195,7 @@ ExReleaseRundownProtection (
|
|||
)
|
||||
{
|
||||
/* Call the general function with only 1 reference removal */
|
||||
ExReleaseRundownProtectionEx(RunRef, 1);
|
||||
ExReleaseRundownProtectionEx(RunRef, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -146,8 +207,12 @@ ExRundownCompleted (
|
|||
IN PEX_RUNDOWN_REF RunRef
|
||||
)
|
||||
{
|
||||
/* Remove pending rundown */
|
||||
RunRef->Count++;
|
||||
/* mark the */
|
||||
#ifdef _WIN64
|
||||
InterlockedExchange64((LONGLONG*)&RunRef->Count, (LONGLONG)EX_RUNDOWN_ACTIVE);
|
||||
#else
|
||||
InterlockedExchange((LONG*)&RunRef->Count, EX_RUNDOWN_ACTIVE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -159,30 +224,43 @@ ExWaitForRundownProtectionRelease (
|
|||
IN PEX_RUNDOWN_REF RunRef
|
||||
)
|
||||
{
|
||||
ULONG_PTR PrevCount, NewPtr, PrevPtr;
|
||||
RUNDOWN_DESCRIPTOR RundownDescriptor;
|
||||
|
||||
#ifdef _WIN64
|
||||
PrevCount = (ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Ptr, (LONGLONG)EX_RUNDOWN_ACTIVE, 0LL);
|
||||
#else
|
||||
PrevCount = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Ptr, EX_RUNDOWN_ACTIVE, 0);
|
||||
#endif
|
||||
|
||||
/* Check if anyone is referencing the structure */
|
||||
if (!RunRef->Count) {
|
||||
/* It's free, set it to Rundown Mode */
|
||||
RunRef->Count = EX_RUNDOWN_ACTIVE;
|
||||
} else {
|
||||
/* Check if it's already in rundown */
|
||||
if (RunRef->Count == EX_RUNDOWN_ACTIVE) return;
|
||||
if (PrevCount == 0 ||
|
||||
PrevCount & EX_RUNDOWN_ACTIVE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save number of references */
|
||||
RundownDescriptor.References = RunRef->Count / 2;
|
||||
|
||||
|
||||
/* save the reference counter */
|
||||
RundownDescriptor.References = PrevCount >> EX_RUNDOWN_COUNT_SHIFT;
|
||||
|
||||
/* Pending references... wait on them to be closed with an event */
|
||||
KeInitializeEvent(RundownDescriptor.RundownEvent, NotificationEvent, FALSE);
|
||||
|
||||
/* Save Rundown Descriptor. This is safe because this stack won't be modified */
|
||||
RunRef->Pointer = &RundownDescriptor;
|
||||
|
||||
/* Set the Count to 1 so nobody else acquires and so release notifies us */
|
||||
RunRef->Count++;
|
||||
KeInitializeEvent(&RundownDescriptor.RundownEvent, NotificationEvent, FALSE);
|
||||
|
||||
NewPtr = (ULONG_PTR)&RundownDescriptor | EX_RUNDOWN_ACTIVE;
|
||||
PrevCount = EX_RUNDOWN_ACTIVE;
|
||||
|
||||
do
|
||||
{
|
||||
#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
|
||||
|
||||
PrevCount = PrevPtr;
|
||||
} while (PrevPtr != PrevCount);
|
||||
|
||||
/* Wait for whoever needs to release to notify us */
|
||||
KeWaitForSingleObject(RundownDescriptor.RundownEvent, Executive, KernelMode, FALSE, NULL);
|
||||
KeWaitForSingleObject(&RundownDescriptor.RundownEvent, Executive, KernelMode, FALSE, NULL);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue