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);