Author: ion
Date: Fri Jan 26 02:48:48 2007
New Revision: 25632
URL:
http://svn.reactos.org/svn/reactos?rev=25632&view=rev
Log:
- Multiple fixes to ERESOURCE implementation.
Modified:
trunk/reactos/ntoskrnl/ex/resource.c
Modified: trunk/reactos/ntoskrnl/ex/resource.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/resource.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/resource.c (original)
+++ trunk/reactos/ntoskrnl/ex/resource.c Fri Jan 26 02:48:48 2007
@@ -20,16 +20,13 @@
#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
-
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, ExpResourceInitialization)
-#endif
+#include <debug.h>
/* Macros for reading resource flags */
#define IsExclusiveWaiting(r) (r->NumberOfExclusiveWaiters)
#define IsSharedWaiting(r) (r->NumberOfSharedWaiters)
#define IsOwnedExclusive(r) (r->Flag & ResourceOwnedExclusive)
+#define IsBoostAllowed(r) (r->Flag & ResourceHasDisabledPriorityBoost)
/* DATA***********************************************************************/
@@ -258,6 +255,7 @@
IN PKIRQL OldIrql)
{
POWNER_ENTRY Owner, Table;
+ KIRQL OldIrql2;
ULONG NewSize, OldSize;
DPRINT("ExpExpandResourceOwnerTable: %p\n", Resource);
@@ -285,7 +283,7 @@
TAG_RESOURCE_TABLE);
/* Zero the table */
- RtlZeroMemory((PVOID)(Table + OldSize),
+ RtlZeroMemory(Table + OldSize,
(NewSize - OldSize) * sizeof(OWNER_ENTRY));
/* Lock the resource */
@@ -302,22 +300,24 @@
else
{
/* Copy the table */
- RtlCopyMemory((PVOID)Table,
+ RtlCopyMemory(Table,
Owner,
OldSize * sizeof(OWNER_ENTRY));
/* Acquire dispatcher lock to prevent thread boosting */
- KiAcquireDispatcherLockAtDpcLevel();
+ OldIrql2 = KiAcquireDispatcherLock();
/* Set the new table data */
Table->TableSize = NewSize;
Resource->OwnerTable = Table;
+ /* Release dispatcher lock */
+ KiReleaseDispatcherLock(OldIrql2);
+
/* Sanity check */
ExpVerifyResource(Resource);
- /* Release locks */
- KiReleaseDispatcherLockFromDpcLevel();
+ /* Release lock */
ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
/* Free the old table */
@@ -358,9 +358,7 @@
IN PKIRQL OldIrql)
{
POWNER_ENTRY Owner, Limit;
- ULONG Size;
POWNER_ENTRY FreeEntry = NULL;
- DPRINT("ExpFindFreeEntry: %p\n", Resource);
/* Sanity check */
ASSERT(OldIrql != 0);
@@ -378,34 +376,24 @@
Owner = Resource->OwnerTable;
if (Owner)
{
- /* Loop every entry */
- Size = Owner->TableSize;
- Limit = &Owner[Size];
-
- /* Go to the next entry and loop */
+ /* Set the limit, move to the next owner and loop owner entries */
+ Limit = &Owner[Owner->TableSize];
Owner++;
do
{
- /* Check for a free entry */
+ /* Check if the entry is free */
if (!Owner->OwnerThread)
{
- /* Found one, return it!*/
- FreeEntry = Owner;
- break;
+ /* Update the resource entry and return it */
+ KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner -
+ Resource->
+ OwnerTable);
+ return Owner;
}
- /* Move on */
+ /* Move to the next one */
Owner++;
} while (Owner != Limit);
-
- /* If we found a free entry by now, return it */
- if (FreeEntry)
- {
- /* Set the resource index */
- KeGetCurrentThread()->ResourceIndex =
- (UCHAR)(Owner - Resource->OwnerTable);
- return FreeEntry;
- }
}
/* No free entry, expand the table */
@@ -445,63 +433,39 @@
IN PKIRQL OldIrql)
{
POWNER_ENTRY FreeEntry, Owner, Limit;
- ULONG Size;
- DPRINT("ExpFindEntryForThread: %p\n", Resource);
/* Start by looking in the static array */
- if (Resource->OwnerThreads[0].OwnerThread == Thread)
- {
- /* Found it, return it! */
- return &Resource->OwnerThreads[0];
- }
- else if (Resource->OwnerThreads[1].OwnerThread == Thread)
- {
- /* Return it */
- return &Resource->OwnerThreads[1];
- }
- else
- {
- /* Check if the first array is empty for our use */
- FreeEntry = NULL;
- if (!Resource->OwnerThreads[1].OwnerThread)
- {
- /* Use this as the first free entry */
- FreeEntry = &Resource->OwnerThreads[1];
- }
-
- /* Get the current table pointer */
- Owner = Resource->OwnerTable;
- if (!Owner)
- {
- /* The current table is empty, so no size */
- Size = 0;
- }
- else
- {
- /* We have a table, get it's size and limit */
- Size = Owner->TableSize;
- Limit = &Owner[Size];
-
- /* Go to the next entry and loop */
+ Owner = &Resource->OwnerThreads[0];
+ if (Owner->OwnerThread == Thread) return Owner;
+ Owner++;
+ if (Owner->OwnerThread == Thread) return Owner;
+
+ /* Check if this is a free entry */
+ FreeEntry = !Owner->OwnerThread ? Owner : NULL;
+
+ /* Loop the table */
+ Owner = Resource->OwnerTable;
+ if (Owner)
+ {
+ /* Calculate the limit, skip the first entry, and start looping */
+ Limit = &Owner[Owner->TableSize];
+ Owner++;
+ do
+ {
+ /* Check if we found a match */
+ if (Owner->OwnerThread == Thread)
+ {
+ /* We did, update the index and return it */
+ KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner -
+ Resource->
+ OwnerTable);
+ return Owner;
+ }
+
+ /* If we don't yet have a free entry and this one is, choose it */
+ if (!(FreeEntry) && !(Owner->OwnerThread)) FreeEntry = Owner;
Owner++;
- do
- {
- /* Check for a match */
- if (Owner->OwnerThread == Thread)
- {
- /* Match found! Set the resource index */
- KeGetCurrentThread()->ResourceIndex =
- (UCHAR)(Owner - Resource->OwnerTable);
- return Owner;
- }
-
- /* If we don't have a free entry yet, make this one free */
- if (!(FreeEntry) && !(Owner->OwnerThread)) FreeEntry = Owner;
-
- /* Move on */
- Owner++;
- } while (Owner != Limit);
- }
+ } while (Owner != Limit);
}
/* Check if it's OK to do an expansion */
@@ -511,8 +475,8 @@
if (FreeEntry)
{
/* Set the resource index */
- KeGetCurrentThread()->ResourceIndex = (UCHAR)
- (Owner - Resource->OwnerTable);
+ KeGetCurrentThread()->ResourceIndex = (UCHAR)(FreeEntry -
+ Resource->OwnerTable);
return FreeEntry;
}
@@ -538,19 +502,11 @@
* @remarks None.
*
*--*/
-#if 0
-
-/*
- * Disabled, read the comments bellow.
- */
VOID
FASTCALL
ExpBoostOwnerThread(IN PKTHREAD Thread,
IN PKTHREAD OwnerThread)
{
- BOOLEAN Released = FALSE;
- DPRINT("ExpBoostOwnerThread: %p\n", Thread);
-
/* Make sure the owner thread is a pointer, not an ID */
if (!((ULONG_PTR)OwnerThread & 0x3))
{
@@ -558,8 +514,8 @@
if ((OwnerThread->Priority < Thread->Priority) &&
(OwnerThread->Priority < 14))
{
- /* Make sure we're at dispatch */
- ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+ /* Acquire the thread lock */
+ KiAcquireThreadLock(Thread);
/* Set the new priority */
OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority;
@@ -568,17 +524,13 @@
OwnerThread->Quantum = OwnerThread->QuantumReset;
/* Update the kernel state */
- KiSetPriorityThread(OwnerThread, 14, &Released);
-
- /* Reacquire lock if it got releases */
- if (Released) KiAcquireDispatcherLockFromDpcLevel();
-
- /* Make sure we're still at dispatch */
- ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
- }
- }
-}
-#endif
+ KiSetPriorityThread(OwnerThread, 14);
+
+ /* Release the thread lock */
+ KiReleaseThreadLock(Thread);
+ }
+ }
+}
/*++
* @name ExpWaitForResource
@@ -601,20 +553,21 @@
ExpWaitForResource(IN PERESOURCE_XP Resource,
IN PVOID Object)
{
-#if DBG
ULONG i;
ULONG Size;
- KIRQL OldIrql;
POWNER_ENTRY Owner;
-#endif
ULONG WaitCount = 0;
NTSTATUS Status;
LARGE_INTEGER Timeout;
+ PKTHREAD Thread, OwnerThread;
+#if DBG
+ KIRQL OldIrql;
+#endif
/* Increase contention count and use a 5 second timeout */
Resource->ContentionCount++;
Timeout.QuadPart = 500 * -10000;
- for(;;)
+ for (;;)
{
/* Wait for ownership */
Status = KeWaitForSingleObject(Object,
@@ -675,20 +628,10 @@
ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
#endif
}
-#if 0
-/*
- * Disabled because:
- * - We cannot access the OwnerTable without locking the resource.
- * - The shared waiters may wait also on the semaphore. It makes no sense to boost a
waiting thread.
- * - The thread header is initialized like KeWaitForSingleObject (?, ?, ?, TRUE, ?).
- * During the boost, possible the dispatcher lock is released but the thread block
(WaitNext) isn't changed.
- */
/* Check if we can boost */
- if (!(Resource->Flag & ResourceHasDisabledPriorityBoost))
- {
- PKTHREAD Thread, OwnerThread;
-
+ if (IsBoostAllowed(Resource))
+ {
/* Get the current kernel thread and lock the dispatcher */
Thread = KeGetCurrentThread();
Thread->WaitIrql = KiAcquireDispatcherLock();
@@ -725,7 +668,6 @@
}
}
}
-#endif
}
}
@@ -791,8 +733,6 @@
/* Check if there is a shared owner or exclusive owner */
TryAcquire:
- DPRINT("ExAcquireResourceExclusiveLite(Resource 0x%p, Wait %d)\n",
- Resource, Wait);
if (Resource->ActiveCount)
{
/* Check if it's exclusively owned, and we own it */
@@ -831,7 +771,7 @@
ExpWaitForResource(Resource, Resource->ExclusiveWaiters);
/* Set owner and return success */
- Resource->OwnerThreads[0].OwnerThread = Thread;
+ Resource->OwnerThreads[0].OwnerThread =
ExGetCurrentResourceThread();
return TRUE;
}
}
@@ -905,21 +845,10 @@
/* See if nobody owns us */
TryAcquire:
- DPRINT("ExAcquireResourceSharedLite(Resource 0x%p, Wait %d)\n",
- Resource, Wait);
if (!Resource->ActiveCount)
{
- if (Resource->NumberOfSharedWaiters == 0)
- {
- Owner = &Resource->OwnerThreads[1];
- }
- else
- {
- /* Find a free entry */
- Owner = ExpFindFreeEntry(Resource, &OldIrql);
- if (!Owner) goto TryAcquire;
- }
-
+ /* Setup the owner entry */
+ Owner = &Resource->OwnerThreads[1];
Owner->OwnerThread = Thread;
Owner->OwnerCount = 1;
Resource->ActiveCount = 1;
@@ -1066,8 +995,6 @@
/* See if nobody owns us */
TryAcquire:
- DPRINT("ExAcquireSharedStarveExclusive(Resource 0x%p, Wait %d)\n",
- Resource, Wait);
if (!Resource->ActiveCount)
{
/* Nobody owns it, so let's take control */
@@ -1097,22 +1024,6 @@
/* Find a free entry */
Owner = ExpFindFreeEntry(Resource, &OldIrql);
if (!Owner) goto TryAcquire;
-
- /* If we got here, then we need to wait. Are we allowed? */
- if (!Wait)
- {
- /* Release the lock and return */
- ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- return TRUE;
- }
-
- /* Check if we have a shared waiters semaphore */
- if (!Resource->SharedWaiters)
- {
- /* Allocate one and try again */
- ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
- goto TryAcquire;
- }
}
else
{
@@ -1194,8 +1105,8 @@
*--*/
BOOLEAN
NTAPI
-ExAcquireSharedWaitForExclusive(PERESOURCE resource,
- BOOLEAN Wait)
+ExAcquireSharedWaitForExclusive(IN PERESOURCE resource,
+ IN BOOLEAN Wait)
{
KIRQL OldIrql;
ERESOURCE_THREAD Thread;
@@ -1214,8 +1125,6 @@
/* See if nobody owns us */
TryAcquire:
- DPRINT("ExAcquireSharedWaitForExclusive(Resource 0x%p, Wait %d)\n",
- Resource, Wait);
if (!Resource->ActiveCount)
{
/* Nobody owns it, so let's take control */
@@ -1241,16 +1150,20 @@
ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
return TRUE;
}
- else
- {
- /* Find a free entry */
- Owner = ExpFindFreeEntry(Resource, &OldIrql);
- if (!Owner) goto TryAcquire;
-
- /* If we got here, then we need to wait. Are we allowed? */
+
+ /* Find a free entry */
+ Owner = ExpFindFreeEntry(Resource, &OldIrql);
+ if (!Owner) goto TryAcquire;
+ }
+ else
+ {
+ /* Try to find if there are exclusive waiters */
+ if (IsExclusiveWaiting(Resource))
+ {
+ /* We have to wait for the exclusive waiter to be done */
if (!Wait)
{
- /* Release the lock and return */
+ /* So bail out if we're not allowed */
ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
return TRUE;
}
@@ -1263,38 +1176,6 @@
goto TryAcquire;
}
- /* Now take control of the resource */
- Owner->OwnerThread = Thread;
- Owner->OwnerCount = 1;
- Resource->NumberOfSharedWaiters++;
-
- /* Release the lock and wait for it to be ours */
- ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- ExpWaitForResource(Resource, Resource->SharedWaiters);
- return TRUE;
- }
- }
- else
- {
- /* Try to find if there are exclusive waiters */
- if (IsExclusiveWaiting(Resource))
- {
- /* We have to wait for the exclusive waiter to be done */
- if (!Wait)
- {
- /* So bail out if we're not allowed */
- ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- return TRUE;
- }
-
- /* Check if we have a shared waiters semaphore */
- if (!Resource->SharedWaiters)
- {
- /* Allocate one and try again */
- ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
- goto TryAcquire;
- }
-
/* Now wait for the resource */
Resource->NumberOfSharedWaiters++;
ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
@@ -1304,7 +1185,7 @@
ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
/* Find who owns it now */
- Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+ while (!(Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql)));
/* Sanity checks */
ASSERT(IsOwnedExclusive(Resource) == FALSE);
@@ -1347,6 +1228,32 @@
return TRUE;
}
}
+
+ /* We have to wait for the exclusive waiter to be done */
+ if (!Wait)
+ {
+ /* So bail out if we're not allowed */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Check if we have a shared waiters semaphore */
+ if (!Resource->SharedWaiters)
+ {
+ /* Allocate one and try again */
+ ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
+ goto TryAcquire;
+ }
+
+ /* Take control */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->NumberOfSharedWaiters++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ ExpWaitForResource(Resource, Resource->SharedWaiters);
+ return TRUE;
}
/*++
@@ -1372,10 +1279,6 @@
ULONG OldWaiters;
KIRQL OldIrql;
PERESOURCE_XP Resource = (PERESOURCE_XP)resource;
- DPRINT("ExConvertExclusiveToSharedLite(Resource 0x%p)\n", Resource);
-
- /* Lock the resource */
- ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
/* Sanity checks */
ASSERT(KeIsExecutingDpc() == FALSE);
@@ -1383,14 +1286,17 @@
ASSERT(IsOwnedExclusive(Resource));
ASSERT(Resource->OwnerThreads[0].OwnerThread ==
(ERESOURCE_THREAD)PsGetCurrentThread());
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
/* Erase the exclusive flag */
Resource->Flag &= ~ResourceOwnedExclusive;
/* Check if we have shared waiters */
- OldWaiters = Resource->NumberOfSharedWaiters;
- if (OldWaiters)
+ if (IsSharedWaiting(Resource))
{
/* Make the waiters active owners */
+ OldWaiters = Resource->NumberOfSharedWaiters;
Resource->ActiveCount = Resource->ActiveCount + (USHORT)OldWaiters;
Resource->NumberOfSharedWaiters = 0;
@@ -1427,7 +1333,6 @@
{
KIRQL OldIrql;
PERESOURCE_XP Resource = (PERESOURCE_XP)resource;
- DPRINT("ExDeleteResourceLite(Resource 0x%p)\n", Resource);
/* Sanity checks */
ASSERT(IsSharedWaiting(Resource) == FALSE);
@@ -1559,7 +1464,6 @@
ExInitializeResourceLite(PERESOURCE resource)
{
PERESOURCE_XP Resource = (PERESOURCE_XP)resource;
- DPRINT("ExInitializeResourceLite(Resource 0x%p)\n", Resource);
/* Clear the structure */
RtlZeroMemory(Resource, sizeof(ERESOURCE_XP));
@@ -1806,7 +1710,6 @@
KIRQL OldIrql;
POWNER_ENTRY Owner, Limit;
PERESOURCE_XP Resource = (PERESOURCE_XP)resource;
- DPRINT("ExReleaseResourceLite: %p\n", Resource);
/* Sanity check */
ExpVerifyResource(Resource);
@@ -1832,42 +1735,45 @@
/* Clear the owner */
Resource->OwnerThreads[0].OwnerThread = 0;
- /* Check if there are shared waiters */
- if (IsSharedWaiting(Resource))
- {
- /* Remove the exclusive flag */
- Resource->Flag &= ~ResourceOwnedExclusive;
-
- /* Give ownage to another thread */
- Count = Resource->NumberOfSharedWaiters;
- Resource->ActiveCount = (USHORT)Count;
- Resource->NumberOfSharedWaiters = 0;
-
- /* Release lock and let someone else have it */
- ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- KeReleaseSemaphore(Resource->SharedWaiters, 0, Count, FALSE);
- return;
- }
- else if (IsExclusiveWaiting(Resource))
- {
- /* Give exclusive access */
- Resource->OwnerThreads[0].OwnerThread = 1;
- Resource->OwnerThreads[0].OwnerCount = 1;
- Resource->ActiveCount = 1;
- Resource->NumberOfExclusiveWaiters--;
-
- /* Release the lock and give it away */
- ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- KeSetEventBoostPriority(Resource->ExclusiveWaiters,
- (PKTHREAD*)
- &Resource->OwnerThreads[0].OwnerThread);
- return;
- }
+ /* Check the active count */
+ ASSERT(Resource->ActiveCount > 0);
+ if (!(--Resource->ActiveCount))
+ {
+ /* Check if there are shared waiters */
+ if (IsSharedWaiting(Resource))
+ {
+ /* Remove the exclusive flag */
+ Resource->Flag &= ~ResourceOwnedExclusive;
+
+ /* Give ownage to another thread */
+ Count = Resource->NumberOfSharedWaiters;
+ Resource->ActiveCount = (SHORT)Count;
+ Resource->NumberOfSharedWaiters = 0;
+
+ /* Release lock and let someone else have it */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ KeReleaseSemaphore(Resource->SharedWaiters, 0, Count, FALSE);
+ return;
+ }
+ else if (IsExclusiveWaiting(Resource))
+ {
+ /* Give exclusive access */
+ Resource->OwnerThreads[0].OwnerThread = 1;
+ Resource->OwnerThreads[0].OwnerCount = 1;
+ Resource->ActiveCount = 1;
+ Resource->NumberOfExclusiveWaiters--;
+
+ /* Release the lock and give it away */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ KeSetEventBoostPriority(Resource->ExclusiveWaiters,
+ (PKTHREAD*)
+ &Resource->OwnerThreads[0].OwnerThread);
+ return;
+ }
+ }
/* Remove the exclusive flag */
Resource->Flag &= ~ResourceOwnedExclusive;
-
- Resource->ActiveCount = 0;
}
else
{
@@ -1876,6 +1782,11 @@
{
/* Found it, get owner */
Owner = &Resource->OwnerThreads[1];
+ }
+ else if (Resource->OwnerThreads[0].OwnerThread == Thread)
+ {
+ /* Found it, get owner */
+ Owner = &Resource->OwnerThreads[0];
}
else
{
@@ -1965,7 +1876,6 @@
/* Release lock */
ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- return;
}
/*++
@@ -1998,7 +1908,6 @@
POWNER_ENTRY Owner;
PERESOURCE_XP Resource = (PERESOURCE_XP)resource;
ASSERT(Thread != 0);
- DPRINT("ExReleaseResourceForThreadLite: %p\n", Resource);
/* Get the thread and lock the resource */
ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
@@ -2034,7 +1943,7 @@
/* Give ownage to another thread */
Count = Resource->NumberOfSharedWaiters;
- Resource->ActiveCount = (USHORT)Count;
+ Resource->ActiveCount = (SHORT)Count;
Resource->NumberOfSharedWaiters = 0;
/* Release lock and let someone else have it */
@@ -2147,7 +2056,6 @@
/* Release lock */
ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
- return;
}
/*++
@@ -2266,7 +2174,6 @@
KIRQL OldIrql;
BOOLEAN Acquired = FALSE;
PERESOURCE_XP Resource = (PERESOURCE_XP)resource;
- DPRINT("ExTryToAcquireResourceExclusiveLite: %p\n", Resource);
/* Sanity check */
ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);