-/* $Id: resource.c,v 1.28 2004/08/15 16:39:01 chorns Exp $
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+ * PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ex/resource.c
- * PURPOSE: Resource synchronization construct
- * PROGRAMMER: Unknown
- * UPDATE HISTORY:
- * Created 22/05/98
+ * PURPOSE: ERESOURCE Implementation
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
-
-/*
- * Usage of ERESOURCE members is not documented.
- * From names of members and functionnalities, we can assume :
- *
- * OwnerTable = list of threads who have shared access(if more than one)
- * ActiveCount = number of threads who have access to the resource
- * Flag = bits : ResourceOwnedExclusive=0x80
- * ResourceNeverExclusive=0x10
- * ResourceReleaseByOtherThread=0x20
- * ResourceDisableBoost=0x08
- * SharedWaiters = semaphore, used to manage wait list of shared waiters.
- * ExclusiveWaiters = event, used to manage wait list of exclusive waiters.
- * OwnerThreads[0]= thread who have exclusive access
- * OwnerThreads[1]= if only one thread own the resource
- * thread who have shared access
- * else
- * OwnerThread=0
- * and TableSize = number of entries in the owner table
- * NumberOfExclusiveWaiters = number of threads waiting for exclusive access.
- * NumberOfSharedWaiters = number of threads waiting for exclusive access.
- *
+/* WARNING:
+ * This implementation is the Windows NT 5.x one.
+ * NT 6.0 beta has optimized the OwnerThread entry array
+ * and the internals of ExpFindEntryForThread and ExpFindFreeEntry
+ * need to be modified accordingly in order to support the WDK.
+ * These changes will not be made here until NT 6.0 reaches RTM status since
+ * there is a possibility that they will be removed; as such, do NOT
+ * update ERESOURCE/relevant code to the WDK definition.
*/
-#define ResourceOwnedExclusive 0x80
-#define ResourceDisableBoost 0x08
-
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
-/* GLOBALS *******************************************************************/
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, ExpResourceInitialization)
+#endif
-#define TAG_OWNER_TABLE TAG('R', 'O', 'W', 'N')
-#define TAG_EXCLUSIVE_LOCK TAG('E', 'R', 'E', 'L')
-#define TAG_SHARED_SEM TAG('E', 'R', 'S', 'S')
+/* Macros for reading resource flags */
+#define IsExclusiveWaiting(r) (r->NumberOfExclusiveWaiters)
+#define IsSharedWaiting(r) (r->NumberOfSharedWaiters)
+#define IsOwnedExclusive(r) (r->Flag & ResourceOwnedExclusive)
-/* FUNCTIONS *****************************************************************/
+/* DATA***********************************************************************/
+LARGE_INTEGER ExpTimeout;
+ULONG ExpResourceTimeoutCount = 90 * 3600 / 2;
+KSPIN_LOCK ExpResourceSpinLock;
+LIST_ENTRY ExpSystemResourcesList;
+BOOLEAN ExResourceStrict = FALSE; /* FIXME */
-BOOLEAN
-STDCALL
-ExTryToAcquireResourceExclusiveLite (
- PERESOURCE Resource
- )
-/*
- * FUNCTION: Attempts to require the resource for exclusive access
- * ARGUMENTS:
- * Resource = Points to the resource of be acquired
- * RETURNS: TRUE if the resource was acquired for the caller
- * NOTES: Must be acquired at IRQL < DISPATCH_LEVEL
- */
+/* PRIVATE FUNCTIONS *********************************************************/
+
+#if DBG
+/*++
+ * @name ExpVerifyResource
+ *
+ * The ExpVerifyResource routine verifies the correctness of an ERESOURCE
+ *
+ * @param Resource
+ * Pointer to the resource being verified.
+ *
+ * @return None.
+ *
+ * @remarks Only present on DBG builds.
+ *
+ *--*/
+VOID
+NTAPI
+ExpVerifyResource(IN PERESOURCE Resource)
{
- return(ExAcquireResourceExclusiveLite(Resource,FALSE));
+ /* Verify the resource data */
+ ASSERT((((ULONG_PTR)Resource) & (sizeof(ULONG_PTR) - 1)) == 0);
+ ASSERT(!Resource->SharedWaiters ||
+ Resource->SharedWaiters->Header.Type == SemaphoreObject);
+ ASSERT(!Resource->SharedWaiters ||
+ Resource->SharedWaiters->Header.Size == (sizeof(KSEMAPHORE) / sizeof(ULONG)));
+ ASSERT(!Resource->ExclusiveWaiters ||
+ Resource->ExclusiveWaiters->Header.Type == SynchronizationEvent);
+ ASSERT(!Resource->ExclusiveWaiters ||
+ Resource->ExclusiveWaiters->Header.Size == (sizeof(KEVENT) / sizeof(ULONG)));
}
-#ifdef ExAcquireResourceExclusive
-#undef ExAcquireResourceExclusive
+/*++
+ * @name ExpCheckForApcsDisabled
+ *
+ * The ExpCheckForApcsDisabled routine checks if Kernel APCs are still
+ * enabled when they should be disabled, and optionally breakpoints.
+ *
+ * @param BreakIfTrue
+ * Specifies if we should break if an invalid APC State is detected.
+ *
+ * @param Resource
+ * Pointer to the resource being checked.
+ *
+ * @param Thread
+ * Pointer to the thread being checked.
+ *
+ * @return None.
+ *
+ * @remarks Only present on DBG builds. Depends on ExResourceStrict value.
+ *
+ *--*/
+VOID
+NTAPI
+ExpCheckForApcsDisabled(IN BOOLEAN BreakIfTrue,
+ IN PERESOURCE Resource,
+ IN PETHREAD Thread)
+{
+ /* Check if we should care and check if we should break */
+ if ((ExResourceStrict) &&
+ (BreakIfTrue) &&
+ !(Thread->SystemThread) &&
+ !(Thread->Tcb.CombinedApcDisable))
+ {
+ /* Bad! */
+ DPRINT1("EX: resource: APCs still enabled before resource %p acquire "
+ "!!!\n", Resource);
+ DbgBreakPoint();
+ }
+}
#endif
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExAcquireResourceExclusive (
- PERESOURCE Resource,
- BOOLEAN Wait
- )
+/*++
+ * @name ExpResourceInitialization
+ *
+ * The ExpResourceInitialization routine initializes resources for use.
+ *
+ * @param None.
+ *
+ * @return None.
+ *
+ * @remarks This routine should only be called once, during system startup.
+ *
+ *--*/
+VOID
+NTAPI
+INIT_FUNCTION
+ExpResourceInitialization(VOID)
{
- return(ExAcquireResourceExclusiveLite(Resource,Wait));
+ /* Setup the timeout */
+ ExpTimeout.QuadPart = Int32x32To64(4, -10000000);
+ InitializeListHead(&ExpSystemResourcesList);
+ KeInitializeSpinLock(&ExpResourceSpinLock);
}
+/*++
+ * @name ExpAllocateExclusiveWaiterEvent
+ *
+ * The ExpAllocateExclusiveWaiterEvent routine creates the event that will
+ * be used by exclusive waiters on the resource.
+ *
+ * @param Resource
+ * Pointer to the resource.
+ *
+ * @param OldIrql
+ * Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return None.
+ *
+ * @remarks The pointer to the event must be atomically set.
+ *
+ *--*/
+VOID
+NTAPI
+ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource,
+ IN PKIRQL OldIrql)
+{
+ PKEVENT Event;
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExAcquireResourceExclusiveLite (
- PERESOURCE Resource,
- BOOLEAN Wait
- )
-/*
- * FUNCTION: Acquires a resource exclusively for the calling thread
- * ARGUMENTS:
- * Resource = Points to the resource to acquire
- * Wait = Is set to TRUE if the caller should wait to acquire the
- * resource if it can't be acquired immediately
- * RETURNS: TRUE if the resource was acquired,
- * FALSE otherwise
- * NOTES: Must be called at IRQL < DISPATCH_LEVEL
- */
+ /* Release the lock */
+ ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+ /* Allocate the event */
+ Event = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(KEVENT),
+ TAG_RESOURCE_EVENT);
+
+ /* Initialize it */
+ KeInitializeEvent(Event, SynchronizationEvent, FALSE);
+
+ /* Set it */
+ if (InterlockedCompareExchangePointer(&Resource->ExclusiveWaiters,
+ Event,
+ NULL))
+ {
+ /* Someone already set it, free our event */
+ DPRINT1("WARNING: Handling race condition\n");
+ ExFreePool(Event);
+ }
+
+ /* Re-acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
+}
+
+/*++
+ * @name ExpAllocateSharedWaiterSemaphore
+ *
+ * The ExpAllocateSharedWaiterSemaphore routine creates the semaphore that
+ * will be used by shared waiters on the resource.
+ *
+ * @param Resource
+ * Pointer to the resource.
+ *
+ * @param OldIrql
+ * Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return None.
+ *
+ * @remarks The pointer to the semaphore must be atomically set.
+ *
+ *--*/
+VOID
+NTAPI
+ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource,
+ IN PKIRQL OldIrql)
{
- KIRQL oldIrql;
-
- DPRINT("ExAcquireResourceExclusiveLite(Resource %x, Wait %d)\n",
- Resource, Wait);
-
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
- /* resource already locked */
- if((Resource->Flag & ResourceOwnedExclusive)
- && Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
- {
- /* it's ok : same lock for same thread */
- Resource->OwnerThreads[0].OwnerCount++;
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
- return(TRUE);
- }
-
- if (Resource->ActiveCount && !Wait)
- {
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceExclusiveLite() = FALSE\n");
- return(FALSE);
- }
-
- /*
- * This is slightly better than it looks because other exclusive
- * threads who are waiting won't be woken up but there is a race
- * with new threads trying to grab the resource so we must have
- * the spinlock, still normally this loop will only be executed
- * once
- * NOTE: We might want to set a timeout to detect deadlock
- * (10 minutes?)
- */
- while (Resource->ActiveCount)
- {
- Resource->NumberOfExclusiveWaiters++;
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- KeWaitForSingleObject(Resource->ExclusiveWaiters,
- Executive,
- KernelMode,
- FALSE,
- NULL);
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
- Resource->NumberOfExclusiveWaiters--;
- }
- Resource->Flag |= ResourceOwnedExclusive;
- Resource->ActiveCount = 1;
- Resource->OwnerThreads[0].OwnerThread = ExGetCurrentResourceThread();
- Resource->OwnerThreads[0].OwnerCount = 1;
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
- return(TRUE);
+ PKSEMAPHORE Semaphore;
+
+ /* Release the lock */
+ ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+ /* Allocate the semaphore */
+ Semaphore = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(KSEMAPHORE),
+ TAG_RESOURCE_SEMAPHORE);
+
+ /* Initialize it */
+ KeInitializeSemaphore(Semaphore, 0, MAXLONG);
+
+ /* Set it */
+ if (InterlockedCompareExchangePointer(&Resource->SharedWaiters,
+ Semaphore,
+ NULL))
+ {
+ /* Someone already set it, free our semaphore */
+ DPRINT1("WARNING: Handling race condition\n");
+ ExFreePool(Semaphore);
+ }
+
+ /* Re-acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
}
-static BOOLEAN EiRemoveSharedOwner(PERESOURCE Resource,
- ERESOURCE_THREAD ResourceThreadId)
-/*
- * FUNCTION: Removes the current thread from the shared owners of the resource
- * ARGUMENTS:
- * Resource = Pointer to the resource for which the thread is to be
- * added
- * NOTE: Must be called with the resource spinlock held
- */
+/*++
+ * @name ExpExpandResourceOwnerTable
+ *
+ * The ExpExpandResourceOwnerTable routine expands the owner table of the
+ * specified resource.
+ *
+ * @param Resource
+ * Pointer to the resource.
+ *
+ * @param OldIrql
+ * Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+ExpExpandResourceOwnerTable(IN PERESOURCE Resource,
+ IN PKIRQL OldIrql)
{
- ULONG i;
-
- if (Resource->OwnerThreads[1].OwnerThread == ResourceThreadId)
- {
- Resource->OwnerThreads[1].OwnerCount--;
- if (Resource->OwnerThreads[1].OwnerCount == 0)
- {
- Resource->ActiveCount--;
- Resource->OwnerThreads[1].OwnerThread = 0;
- }
- return(TRUE);
- }
-
- if (Resource->OwnerThreads[1].OwnerThread)
- {
- /* Oh dear, the caller didn't own the resource after all */
- return(FALSE);;
- }
-
- for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
- {
- if (Resource->OwnerTable[i].OwnerThread == ResourceThreadId)
- {
- Resource->OwnerTable[i].OwnerCount--;
- if (Resource->OwnerTable[i].OwnerCount == 0)
- {
- Resource->ActiveCount--;
- Resource->OwnerTable[i].OwnerThread = 0;
- }
- return TRUE;
- }
- }
- return(FALSE);
+ POWNER_ENTRY Owner, Table;
+ ULONG NewSize, OldSize;
+ DPRINT("ExpExpandResourceOwnerTable: %p\n", Resource);
+
+ /* Get the owner table */
+ Owner = Resource->OwnerTable;
+ if (!Owner)
+ {
+ /* Start with the default size of 3 */
+ OldSize = 0;
+ NewSize = 3;
+ }
+ else
+ {
+ /* Add 4 more entries */
+ OldSize = Owner->TableSize;
+ NewSize = OldSize + 4;
+ }
+
+ /* Release the lock */
+ ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+ /* Allocate memory for the table */
+ Table = ExAllocatePoolWithTag(NonPagedPool,
+ NewSize * sizeof(OWNER_ENTRY),
+ TAG_RESOURCE_TABLE);
+
+ /* Zero the table */
+ RtlZeroMemory((PVOID)(Table + OldSize),
+ (NewSize - OldSize) * sizeof(OWNER_ENTRY));
+
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
+
+ /* Make sure nothing has changed */
+ if ((Owner != Resource->OwnerTable) ||
+ ((Owner) && (OldSize != Resource->OwnerTable->TableSize)))
+ {
+ /* Resource changed while we weren't holding the lock; bail out */
+ ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+ ExFreePool(Table);
+ }
+ else
+ {
+ /* Copy the table */
+ RtlCopyMemory((PVOID)Table,
+ Owner,
+ OldSize * sizeof(OWNER_ENTRY));
+
+ /* Acquire dispatcher lock to prevent thread boosting */
+ //KeAcquireDispatcherDatabaseLockAtDpcLevel();
+
+ /* Set the new table data */
+ Table->TableSize = NewSize;
+ Resource->OwnerTable = Table;
+
+ /* Sanity check */
+ ExpVerifyResource(Resource);
+
+ /* Release locks */
+ //KeReleaseDispatcherDatabaseLockFromDpcLevel();
+ ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+ /* Free the old table */
+ if (Owner) ExFreePool(Owner);
+
+ /* Set the resource index */
+ if (!OldSize) OldSize = 1;
+ }
+
+ /* Set the resource index */
+ KeGetCurrentThread()->ResourceIndex = (UCHAR)OldSize;
+
+ /* Lock the resource again */
+ ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
}
-static BOOLEAN EiAddSharedOwner(PERESOURCE Resource)
-/*
- * FUNCTION: Adds the current thread to the shared owners of the resource
- * ARGUMENTS:
- * Resource = Pointer to the resource for which the thread is to be
- * added
- * NOTE: Must be called with the resource spinlock held
- */
+/*++
+ * @name ExpFindFreeEntry
+ *
+ * The ExpFindFreeEntry routine locates an empty owner entry in the
+ * specified resource. If none was found, then the owner table is
+ * expanded.
+ *
+ * @param Resource
+ * Pointer to the resource.
+ *
+ * @param OldIrql
+ * Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return Pointer to an empty OWNER_ENTRY structure.
+ *
+ * @remarks None.
+ *
+ *--*/
+POWNER_ENTRY
+FASTCALL
+ExpFindFreeEntry(IN PERESOURCE Resource,
+ IN PKIRQL OldIrql)
{
- ERESOURCE_THREAD CurrentThread = ExGetCurrentResourceThread();
- POWNER_ENTRY freeEntry;
- ULONG i = 0;
-
- DPRINT("EiAddSharedOwner(Resource %x)\n", Resource);
-
- if (Resource->ActiveCount == 0)
- {
- /* no owner, it's easy */
- Resource->OwnerThreads[1].OwnerThread = ExGetCurrentResourceThread();
- Resource->OwnerThreads[1].OwnerCount = 1;
- if (Resource->OwnerTable != NULL)
- {
- ExFreePool(Resource->OwnerTable);
- }
- Resource->OwnerTable = NULL;
- Resource->ActiveCount = 1;
- DPRINT("EiAddSharedOwner() = TRUE\n");
- return(TRUE);
- }
-
- /*
- * now, we must search if this thread has already acquired this resource
- * then increase ownercount if found, else create new entry or reuse free
- * entry
- */
- if (Resource->OwnerTable == NULL)
- {
- DPRINT("Creating owner table\n");
-
- /* allocate ownertable,memset to 0, initialize first entry */
- Resource->OwnerTable =
- ExAllocatePoolWithTag(NonPagedPool, sizeof(OWNER_ENTRY)*3,
- TAG_OWNER_TABLE);
- if (Resource->OwnerTable == NULL)
- {
- KEBUGCHECK(0);
- return(FALSE);
- }
- memset(Resource->OwnerTable,0,sizeof(OWNER_ENTRY)*3);
- memcpy(&Resource->OwnerTable[0], &Resource->OwnerThreads[1],
- sizeof(OWNER_ENTRY));
-
- Resource->OwnerThreads[1].OwnerThread = 0;
- Resource->OwnerThreads[1].TableSize = 3;
-
- Resource->OwnerTable[1].OwnerThread = CurrentThread;
- Resource->OwnerTable[1].OwnerCount = 1;
- Resource->ActiveCount++;
-
- return(TRUE);
- }
-
- DPRINT("Search free entries\n");
-
- DPRINT("Number of entries %d\n",
- Resource->OwnerThreads[1].TableSize);
-
- freeEntry = NULL;
- for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
- {
- if (Resource->OwnerTable[i].OwnerThread == CurrentThread)
- {
- DPRINT("Thread already owns resource\n");
- Resource->OwnerTable[i].OwnerCount++;
- return(TRUE);
- }
- if (Resource->OwnerTable[i].OwnerThread == 0)
- {
- freeEntry = &Resource->OwnerTable[i];
- break;
- }
- }
-
- DPRINT("Found free entry %x\n", freeEntry);
-
- if (!freeEntry)
- {
- DPRINT("Allocating new entry\n");
-
- /* reallocate ownertable with one more entry */
- freeEntry =
- ExAllocatePoolWithTag(NonPagedPool,
- sizeof(OWNER_ENTRY)*
- (Resource->OwnerThreads[1].TableSize+1),
- TAG_OWNER_TABLE);
- if (freeEntry == NULL)
- {
- KEBUGCHECK(0);
- return(FALSE);
- }
- memcpy(freeEntry,Resource->OwnerTable,
- sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].TableSize));
- ExFreePool(Resource->OwnerTable);
- Resource->OwnerTable=freeEntry;
- freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].TableSize];
- Resource->OwnerThreads[1].TableSize++;
- }
- DPRINT("Creating entry\n");
- freeEntry->OwnerThread=ExGetCurrentResourceThread();
- freeEntry->OwnerCount=1;
- Resource->ActiveCount++;
- return(TRUE);
+ POWNER_ENTRY Owner, Limit;
+ ULONG Size;
+ POWNER_ENTRY FreeEntry = NULL;
+ DPRINT("ExpFindFreeEntry: %p\n", Resource);
+
+ /* Sanity check */
+ ASSERT(OldIrql != 0);
+ ASSERT(Resource->OwnerThreads[0].OwnerThread != 0);
+
+ /* Check if the next built-in entry is free */
+ if (!Resource->OwnerThreads[1].OwnerThread)
+ {
+ /* Return it */
+ FreeEntry = &Resource->OwnerThreads[1];
+ }
+ else
+ {
+ /* Get the current table pointer */
+ Owner = Resource->OwnerTable;
+ if (Owner)
+ {
+ /* Loop every entry */
+ Size = Owner->TableSize;
+ Limit = &Owner[Size];
+
+ /* Go to the next entry and loop */
+ Owner++;
+ do
+ {
+ /* Check for a free entry */
+ if (!Owner->OwnerThread)
+ {
+ /* Found one, return it!*/
+ FreeEntry = Owner;
+ break;
+ }
+
+ /* Move on */
+ 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 */
+ ExpExpandResourceOwnerTable(Resource, OldIrql);
+ FreeEntry = NULL;
+ }
+
+ /* Return the entry found */
+ return FreeEntry;
}
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExAcquireResourceSharedLite (
- PERESOURCE Resource,
- BOOLEAN Wait
- )
-/*
- * FUNCTION: Acquires the given resource for shared access by the calling
- * thread
- * ARGUMENTS:
- * Resource = Points to the resource to acquire
- * Wait = Is set to TRUE if the caller should be put into wait state
- * until the resource can be acquired if it cannot be acquired
- * immediately
- * RETURNS: TRUE, if the resource is acquire
- * FALSE otherwise
- */
+/*++
+ * @name ExpFindEntryForThread
+ *
+ * The ExpFindEntryForThread routine locates the owner entry associated with
+ * the specified thread in the given resource. If none was found, then the
+ * owner table is expanded.
+ *
+ * @param Resource
+ * Pointer to the resource.
+ *
+ * @param Thread
+ * Pointer to the thread to find.
+ *
+ * @param OldIrql
+ * Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return Pointer to an empty OWNER_ENTRY structure.
+ *
+ * @remarks None.
+ *
+ *--*/
+POWNER_ENTRY
+FASTCALL
+ExpFindEntryForThread(IN PERESOURCE Resource,
+ IN ERESOURCE_THREAD Thread,
+ IN PKIRQL OldIrql)
{
- KIRQL oldIrql;
-
- DPRINT("ExAcquireResourceSharedLite(Resource %x, Wait %d)\n",
- Resource, Wait);
-
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
- /* first, resolve trivial cases */
- if (Resource->ActiveCount == 0)
- {
- EiAddSharedOwner(Resource);
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
- return(TRUE);
- }
-
- if ((Resource->Flag & ResourceOwnedExclusive)
- && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
- {
- /* exclusive, but by same thread : it's ok */
- /*
- * NOTE: Is this correct? Seems the same as ExConvertExclusiveToShared
- */
- Resource->OwnerThreads[0].OwnerCount++;
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
- return(TRUE);
- }
-
- if ((Resource->Flag & ResourceOwnedExclusive)
- || Resource->NumberOfExclusiveWaiters)
- {
- /* exclusive by another thread , or thread waiting for exclusive */
- if (!Wait)
- {
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceSharedLite() = FALSE\n");
- return(FALSE);
- }
- else
- {
- Resource->NumberOfSharedWaiters++;
- do
- {
- /* wait for the semaphore */
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- KeWaitForSingleObject(Resource->SharedWaiters,0, KernelMode, FALSE, NULL);
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
- /* the spin lock was released we must check again */
- }
- while ((Resource->Flag & ResourceOwnedExclusive)
- || Resource->NumberOfExclusiveWaiters);
- Resource->NumberOfSharedWaiters--;
- }
- }
-
- EiAddSharedOwner(Resource);
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
- return(TRUE);
+ 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++;
+ 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);
+ }
+ }
+
+ /* Check if it's OK to do an expansion */
+ if (!OldIrql) return NULL;
+
+ /* 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 */
+ ExpExpandResourceOwnerTable(Resource, OldIrql);
+ return NULL;
}
+/*++
+ * @name ExpBoostOwnerThread
+ *
+ * The ExpBoostOwnerThread routine increases the priority of a waiting
+ * thread in an attempt to fight a possible deadlock.
+ *
+ * @param Thread
+ * Pointer to the current thread.
+ *
+ * @param OwnerThread
+ * Pointer to thread that owns the resource.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+#if 0
+
/*
- * @implemented
+ * Disabled, read the comments bellow.
*/
VOID
-STDCALL
-ExConvertExclusiveToSharedLite (
- PERESOURCE Resource
- )
-/*
- * FUNCTION: Converts a given resource from acquired for exclusive access
- * to acquire for shared access
- * ARGUMENTS:
- * Resource = Points to the resource for which the access should be
- * converted
- * NOTES: Caller must be running at IRQL < DISPATCH_LEVEL
- */
+FASTCALL
+ExpBoostOwnerThread(IN PKTHREAD Thread,
+ IN PKTHREAD OwnerThread)
{
- ULONG oldWaiters;
- KIRQL oldIrql;
-
- DPRINT("ExConvertExclusiveToSharedLite(Resource %x)\n", Resource);
-
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
- oldWaiters = Resource->NumberOfSharedWaiters;
-
- if (!(Resource->Flag & ResourceOwnedExclusive))
- {
- /* Might not be what the caller expects, better bug check */
- KEBUGCHECK(0);
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- return;
- }
-
- //transfer infos from entry 0 to entry 1 and erase entry 0
- Resource->OwnerThreads[1].OwnerThread=Resource->OwnerThreads[0].OwnerThread;
- Resource->OwnerThreads[1].OwnerCount=Resource->OwnerThreads[0].OwnerCount;
- Resource->OwnerThreads[0].OwnerThread=0;
- Resource->OwnerThreads[0].OwnerCount=0;
- /* erase exclusive flag */
- Resource->Flag &= (~ResourceOwnedExclusive);
- /* if no shared waiters, that's all */
- if (!oldWaiters)
- {
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- return;
- }
- /* else, awake the waiters */
- KeReleaseSemaphore(Resource->SharedWaiters,0,oldWaiters,0);
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExConvertExclusiveToSharedLite() finished\n");
+ BOOLEAN Released = FALSE;
+ DPRINT("ExpBoostOwnerThread: %p\n", Thread);
+
+ /* Make sure the owner thread is a pointer, not an ID */
+ if (!((ULONG_PTR)OwnerThread & 0x3))
+ {
+ /* Check if we can actually boost it */
+ if ((OwnerThread->Priority < Thread->Priority) &&
+ (OwnerThread->Priority < 14))
+ {
+ /* Make sure we're at dispatch */
+ ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+
+ /* Set the new priority */
+ OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority;
+
+ /* Update quantum */
+ OwnerThread->Quantum = OwnerThread->QuantumReset;
+
+ /* Update the kernel state */
+ KiSetPriorityThread(OwnerThread, 14, &Released);
+
+ /* Reacquire lock if it got releases */
+ if (Released) KeAcquireDispatcherDatabaseLockFromDpcLevel();
+
+ /* Make sure we're still at dispatch */
+ ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+ }
+ }
}
+#endif
-/*
- * @implemented
- */
+/*++
+ * @name ExpWaitForResource
+ *
+ * The ExpWaitForResource routine performs a wait on the specified resource.
+ *
+ * @param Resource
+ * Pointer to the resource to wait on.
+ *
+ * @param OwnerThread
+ * Pointer to object (exclusive event or shared semaphore) to wait on.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
VOID
-STDCALL
-ExDisableResourceBoostLite (
- PERESOURCE Resource
- )
+FASTCALL
+ExpWaitForResource(IN PERESOURCE Resource,
+ IN PVOID Object)
{
- Resource->Flag |= ResourceDisableBoost;
-}
+ ULONG i;
+ ULONG Size, WaitCount = 0;
+ KIRQL OldIrql;
+ POWNER_ENTRY Owner;
+ NTSTATUS Status;
+ LARGE_INTEGER Timeout;
-/*
- * @implemented
+ /* Increase contention count and use a 5 second timeout */
+ Resource->ContentionCount++;
+ Timeout.QuadPart = 500 * -10000;
+ for(;;)
+ {
+ /* Wait for ownership */
+ Status = KeWaitForSingleObject(Object,
+ WrResource,
+ KernelMode,
+ FALSE,
+ &Timeout);
+ if (Status != STATUS_TIMEOUT) break;
+
+ /* Increase wait count */
+ WaitCount++;
+ Timeout = ExpTimeout;
+
+ /* Check if we've exceeded the limit */
+ if (WaitCount > ExpResourceTimeoutCount)
+ {
+ /* Reset wait count */
+ WaitCount = 0;
+#if DBG
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* Dump debug information */
+ DPRINT1("Resource @ %lx\n", Resource);
+ DPRINT1(" ActiveCount = %04lx Flags = %s%s%s\n",
+ Resource->ActiveCount,
+ IsOwnedExclusive(Resource) ? "IsOwnedExclusive " : "",
+ IsSharedWaiting(Resource) ? "SharedWaiter " : "",
+ IsExclusiveWaiting(Resource) ? "ExclusiveWaiter " : "");
+ DPRINT1(" NumberOfExclusiveWaiters = %04lx\n",
+ Resource->NumberOfExclusiveWaiters);
+ DPRINT1(" Thread = %08lx, Count = %02x\n",
+ Resource->OwnerThreads[0].OwnerThread,
+ Resource->OwnerThreads[0].OwnerCount);
+ DPRINT1(" Thread = %08lx, Count = %02x\n",
+ Resource->OwnerThreads[1].OwnerThread,
+ Resource->OwnerThreads[1].OwnerCount);
+
+ /* Dump out the table too */
+ Owner = Resource->OwnerTable;
+ if (Owner)
+ {
+ /* Loop every entry */
+ Size = Owner->TableSize;
+ for (i = 1; i < Size; i++)
+ {
+ /* Print the data */
+ Owner++;
+ DPRINT1(" Thread = %08lx, Count = %02x\n",
+ Owner->OwnerThread,
+ Owner->OwnerCount);
+ }
+ }
+
+ /* Break */
+ DbgBreakPoint();
+ DPRINT1("EX - Rewaiting\n");
+ 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.
*/
-ULONG
-STDCALL
-ExGetExclusiveWaiterCount (
- PERESOURCE Resource
- )
+
+ /* Check if we can boost */
+ if (!(Resource->Flag & ResourceHasDisabledPriorityBoost))
+ {
+ PKTHREAD Thread, OwnerThread;
+
+ /* Get the current kernel thread and lock the dispatcher */
+ Thread = KeGetCurrentThread();
+ Thread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+ Thread->WaitNext = TRUE;
+
+ /* Get the owner thread and boost it */
+ OwnerThread = (PKTHREAD)Resource->OwnerThreads[0].OwnerThread;
+ if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
+
+ /* If it's a shared resource */
+ if (!IsOwnedExclusive(Resource))
+ {
+ /* Boost the other owner thread too */
+ OwnerThread = (PKTHREAD)Resource->OwnerThreads[1].OwnerThread;
+ if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
+
+ /* Get the table */
+ Owner = Resource->OwnerTable;
+ if (Owner)
+ {
+ /* Loop every entry */
+ Size = Owner->TableSize;
+ for (i = 1; i < Size; i++)
+ {
+ /* Boot every thread in the table */
+ OwnerThread = (PKTHREAD)
+ Resource->OwnerThreads[1].OwnerThread;
+ if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
+ }
+ }
+ }
+ }
+#endif
+ }
+}
+
+/* FUNCTIONS *****************************************************************/
+
+/*++
+ * @name ExAcquireResourceExclusiveLite
+ * @implemented NT4
+ *
+ * The ExAcquireResourceExclusiveLite routine acquires the given resource
+ * for exclusive access by the calling thread.
+ *
+ * @param Resource
+ * Pointer to the resource to acquire.
+ *
+ * @param Wait
+ * Specifies the routine's behavior whenever the resource cannot be
+ * acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ * and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ * Normal kernel APC delivery must be disabled before calling this
+ * routine. Disable normal kernel APC delivery by calling
+ * KeEnterCriticalRegion. Delivery must remain disabled until the
+ * resource is released, at which point it can be reenabled by calling
+ * KeLeaveCriticalRegion.
+ *
+ * For better performance, call ExTryToAcquireResourceExclusiveLite,
+ * rather than calling ExAcquireResourceExclusiveLite with Wait set
+ * to FALSE.
+ *
+ * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ * DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExAcquireResourceExclusiveLite(PERESOURCE Resource,
+ BOOLEAN Wait)
{
- return(Resource->NumberOfExclusiveWaiters);
+ KIRQL OldIrql = PASSIVE_LEVEL;
+ ERESOURCE_THREAD Thread;
+ BOOLEAN Success;
+
+ /* Sanity check */
+ ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
+
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+
+ /* Sanity check and validation */
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+
+ /* Acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+ ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread);
+
+ /* 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 */
+ if ((IsOwnedExclusive(Resource)) &&
+ (Resource->OwnerThreads[0].OwnerThread == Thread))
+ {
+ /* Increase the owning count */
+ Resource->OwnerThreads[0].OwnerCount++;
+ Success = TRUE;
+ }
+ else
+ {
+ /*
+ * If the caller doesn't want us to wait, we can't acquire the
+ * resource because someone else then us owns it. If we can wait,
+ * then we'll wait.
+ */
+ if (!Wait)
+ {
+ Success = FALSE;
+ }
+ else
+ {
+ /* Check if it has exclusive waiters */
+ if (!Resource->ExclusiveWaiters)
+ {
+ /* It doesn't, allocate the event and try acquiring again */
+ ExpAllocateExclusiveWaiterEvent(Resource, &OldIrql);
+ goto TryAcquire;
+ }
+ else
+ {
+ /* Has exclusive waiters, wait on it */
+ Resource->NumberOfExclusiveWaiters++;
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ ExpWaitForResource(Resource, Resource->ExclusiveWaiters);
+
+ /* Set owner and return success */
+ Resource->OwnerThreads[0].OwnerThread = Thread;
+ return TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Nobody owns it, so let's! */
+ Resource->Flag |= ResourceOwnedExclusive;
+ Resource->ActiveCount = 1;
+ Resource->OwnerThreads[0].OwnerThread = Thread;
+ Resource->OwnerThreads[0].OwnerCount = 1;
+ Success = TRUE;
+ }
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return Success;
}
-/*
- * @implemented
- */
+/*++
+ * @name ExAcquireResourceSharedLite
+ * @implemented NT4
+ *
+ * The ExAcquireResourceSharedLite routine acquires the given resource
+ * for shared access by the calling thread.
+ *
+ * @param Resource
+ * Pointer to the resource to acquire.
+ *
+ * @param Wait
+ * Specifies the routine's behavior whenever the resource cannot be
+ * acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ * and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ * Normal kernel APC delivery must be disabled before calling this
+ * routine. Disable normal kernel APC delivery by calling
+ * KeEnterCriticalRegion. Delivery must remain disabled until the
+ * resource is released, at which point it can be reenabled by calling
+ * KeLeaveCriticalRegion.
+ *
+ * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ * DISPATCH_LEVEL.
+ *
+ *--*/
BOOLEAN
-STDCALL
-ExAcquireSharedStarveExclusive (
- PERESOURCE Resource,
- BOOLEAN Wait
- )
-/*
- * FUNCTION: Acquires a given resource for shared access without waiting
- * for any pending attempts to acquire exclusive access to the
- * same resource
- * ARGUMENTS:
- * Resource = Points to the resource to be acquired for shared access
- * Wait = Is set to TRUE if the caller will wait until the resource
- * becomes available when access can't be granted immediately
- * RETURNS: TRUE if the requested access is granted. The routine returns
- * FALSE if the input Wait is FALSE and shared access can't be
- * granted immediately
- */
+NTAPI
+ExAcquireResourceSharedLite(PERESOURCE Resource,
+ BOOLEAN Wait)
{
- KIRQL oldIrql;
-
- DPRINT("ExAcquireSharedStarveExclusive(Resource %x, Wait %d)\n",
- Resource, Wait);
-
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
- /* no owner, it's easy */
- if (Resource->ActiveCount == 0)
- {
- Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread();
- Resource->OwnerThreads[1].OwnerCount=1;
- Resource->ActiveCount=1;
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
- return(TRUE);
- }
-
- if ((Resource->Flag & ResourceOwnedExclusive)
- && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
- {
- /* exclusive, but by same thread : it's ok */
- Resource->OwnerThreads[0].OwnerCount++;
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
- return(TRUE);
- }
-
- if (Resource->Flag & ResourceOwnedExclusive)
- {
- /* exclusive by another thread */
- if (!Wait)
- {
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireSharedStarveExclusive() = FALSE\n");
- return(FALSE);
- }
- else
- {
- Resource->NumberOfSharedWaiters++;
- /* wait for the semaphore */
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0);
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
- Resource->NumberOfSharedWaiters--;
- }
- }
- EiAddSharedOwner(Resource);
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
- return(TRUE);
+ KIRQL OldIrql;
+ ERESOURCE_THREAD Thread;
+ POWNER_ENTRY Owner;
+
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+
+ /* Sanity check and validation */
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+
+ /* Acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+ ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread);
+
+ /* 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;
+ }
+
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->ActiveCount = 1;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Check if it's exclusively owned */
+ if (IsOwnedExclusive(Resource))
+ {
+ /* Check if we own it */
+ if (Resource->OwnerThreads[0].OwnerThread == Thread)
+ {
+ /* Increase the owning count */
+ Resource->OwnerThreads[0].OwnerCount++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Find a free entry */
+ Owner = ExpFindFreeEntry(Resource, &OldIrql);
+ if (!Owner) goto TryAcquire;
+ }
+ else
+ {
+ /* Resource is shared, find who owns it */
+ Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+ if (!Owner) goto TryAcquire;
+
+ /* Is it us? */
+ if (Owner->OwnerThread == Thread)
+ {
+ /* Increase acquire count and return */
+ Owner->OwnerCount++;
+ ASSERT(Owner->OwnerCount != 0);
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Try to find if there are exclusive waiters */
+ if (!IsExclusiveWaiting(Resource))
+ {
+ /* There are none, so acquire it */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->ActiveCount++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+ }
+
+ /* If we got here, then we need to wait. Are we allowed? */
+ if (!Wait)
+ {
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return FALSE;
+ }
+
+ /* Check if we have a shared waiters semaphore */
+ if (!Resource->SharedWaiters)
+ {
+ /* Allocate it and try another acquire */
+ ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
+ goto TryAcquire;
+ }
+
+ /* Now wait for the resource */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->NumberOfSharedWaiters++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ ExpWaitForResource(Resource, Resource->SharedWaiters);
+ return TRUE;
}
-/*
- * @implemented
- */
+/*++
+ * @name ExAcquireSharedStarveExclusive
+ * @implemented NT4
+ *
+ * The ExAcquireSharedStarveExclusive routine acquires the given resource
+ * shared access without waiting for any pending attempts to acquire
+ * exclusive access to the same resource.
+ *
+ * @param Resource
+ * Pointer to the resource to acquire.
+ *
+ * @param Wait
+ * Specifies the routine's behavior whenever the resource cannot be
+ * acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ * and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ * Normal kernel APC delivery must be disabled before calling this
+ * routine. Disable normal kernel APC delivery by calling
+ * KeEnterCriticalRegion. Delivery must remain disabled until the
+ * resource is released, at which point it can be reenabled by calling
+ * KeLeaveCriticalRegion.
+ *
+ * Callers of ExAcquireSharedStarveExclusive usually need quick access
+ * to a shared resource in order to save an exclusive accessor from
+ * doing redundant work. For example, a file system might call this
+ * routine to modify a cached resource, such as a BCB pinned in the
+ * cache, before the Cache Manager can acquire exclusive access to the
+ * resource and write the cache out to disk.
+ *
+ * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ * DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExAcquireSharedStarveExclusive(PERESOURCE Resource,
+ BOOLEAN Wait)
+{
+ KIRQL OldIrql;
+ ERESOURCE_THREAD Thread;
+ POWNER_ENTRY Owner;
+
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+
+ /* Sanity check and validation */
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+
+ /* Acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* 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 */
+ Resource->ActiveCount = 1;
+ Resource->OwnerThreads[1].OwnerThread = Thread;
+ Resource->OwnerThreads[1].OwnerCount = 1;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Check if it's exclusively owned */
+ if (IsOwnedExclusive(Resource))
+ {
+ /* Check if we own it */
+ if (Resource->OwnerThreads[0].OwnerThread == Thread)
+ {
+ /* Increase the owning count */
+ Resource->OwnerThreads[0].OwnerCount++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* 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
+ {
+ /* Resource is shared, find who owns it */
+ Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+ if (!Owner) goto TryAcquire;
+
+ /* Is it us? */
+ if (Owner->OwnerThread == Thread)
+ {
+ /* Increase acquire count and return */
+ Owner->OwnerCount++;
+ ASSERT(Owner->OwnerCount != 0);
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Acquire it */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->ActiveCount++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* 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;
+ }
+
+ /* Now wait for the resource */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->NumberOfSharedWaiters++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ ExpWaitForResource(Resource, Resource->SharedWaiters);
+ return TRUE;
+}
+
+/*++
+ * @name ExAcquireSharedWaitForExclusive
+ * @implemented NT4
+ *
+ * The ExAcquireSharedWaitForExclusive routine acquires the given resource
+ * for shared access if shared access can be granted and there are no
+ * exclusive waiters.
+ *
+ * @param Resource
+ * Pointer to the resource to acquire.
+ *
+ * @param Wait
+ * Specifies the routine's behavior whenever the resource cannot be
+ * acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ * and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ * Normal kernel APC delivery must be disabled before calling this
+ * routine. Disable normal kernel APC delivery by calling
+ * KeEnterCriticalRegion. Delivery must remain disabled until the
+ * resource is released, at which point it can be reenabled by calling
+ * KeLeaveCriticalRegion.
+ *
+ * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ * DISPATCH_LEVEL.
+ *
+ *--*/
BOOLEAN
-STDCALL
-ExAcquireSharedWaitForExclusive (
- PERESOURCE Resource,
- BOOLEAN Wait
- )
+NTAPI
+ExAcquireSharedWaitForExclusive(PERESOURCE Resource,
+ BOOLEAN Wait)
{
- return(ExAcquireResourceSharedLite(Resource,Wait));
+ KIRQL OldIrql;
+ ERESOURCE_THREAD Thread;
+ POWNER_ENTRY Owner;
+
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+
+ /* Sanity check and validation */
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+
+ /* Acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* 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 */
+ Resource->ActiveCount = 1;
+ Resource->OwnerThreads[1].OwnerThread = Thread;
+ Resource->OwnerThreads[1].OwnerCount = 1;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* Check if it's exclusively owned */
+ if (IsOwnedExclusive(Resource))
+ {
+ /* Check if we own it */
+ if (Resource->OwnerThreads[0].OwnerThread == Thread)
+ {
+ /* Increase the owning count */
+ Resource->OwnerThreads[0].OwnerCount++;
+
+ /* Release the lock and return */
+ 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? */
+ 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;
+ }
+
+ /* 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);
+ ExpWaitForResource(Resource, Resource->SharedWaiters);
+
+ /* Get the lock back */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* Find who owns it now */
+ Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+
+ /* Sanity checks */
+ ASSERT(IsOwnedExclusive(Resource) == FALSE);
+ ASSERT(Resource->ActiveCount > 0);
+ ASSERT(Owner->OwnerThread != Thread);
+
+ /* Take control */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+ else
+ {
+ /* Resource is shared, find who owns it */
+ Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+ if (!Owner) goto TryAcquire;
+
+ /* Is it us? */
+ if (Owner->OwnerThread == Thread)
+ {
+ /* Increase acquire count and return */
+ Owner->OwnerCount++;
+ ASSERT(Owner->OwnerCount != 0);
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+
+ /* No exclusive waiters, so acquire it */
+ Owner->OwnerThread = Thread;
+ Owner->OwnerCount = 1;
+ Resource->ActiveCount++;
+
+ /* Release the lock and return */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return TRUE;
+ }
+ }
}
+/*++
+ * @name ExConvertExclusiveToSharedLite
+ * @implemented NT4
+ *
+ * The ExConvertExclusiveToSharedLite routine converts an exclusively
+ * acquired resource into a resource that can be acquired shared.
+ *
+ * @param Resource
+ * Pointer to the resource to convert.
+ *
+ * @return None.
+ *
+ * @remarks Callers of ExConvertExclusiveToSharedLite must be running at IRQL <
+ * DISPATCH_LEVEL.
+ *
+ *--*/
+VOID
+NTAPI
+ExConvertExclusiveToSharedLite(PERESOURCE Resource)
+{
+ ULONG OldWaiters;
+ KIRQL OldIrql;
+ DPRINT("ExConvertExclusiveToSharedLite(Resource 0x%p)\n", Resource);
+
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
-#ifdef ExDeleteResource
-#undef ExDeleteResource
-#endif
+ /* Sanity checks */
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+ ASSERT(IsOwnedExclusive(Resource));
+ ASSERT(Resource->OwnerThreads[0].OwnerThread == (ERESOURCE_THREAD)PsGetCurrentThread());
+ /* Erase the exclusive flag */
+ Resource->Flag &= ~ResourceOwnedExclusive;
-/*
- * @implemented
- */
+ /* Check if we have shared waiters */
+ OldWaiters = Resource->NumberOfSharedWaiters;
+ if (OldWaiters)
+ {
+ /* Make the waiters active owners */
+ Resource->ActiveCount = Resource->ActiveCount + (USHORT)OldWaiters;
+ Resource->NumberOfSharedWaiters = 0;
+
+ /* Release lock and wake the waiters */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ KeReleaseSemaphore(Resource->SharedWaiters, 0, OldWaiters, FALSE);
+ }
+ else
+ {
+ /* Release lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ }
+}
+
+/*++
+ * @name ExDeleteResourceLite
+ * @implemented NT4
+ *
+ * The ExConvertExclusiveToSharedLite routine deletes a given resource
+ * from the system\92s resource list.
+ *
+ * @param Resource
+ * Pointer to the resource to delete.
+ *
+ * @return STATUS_SUCCESS if the resource was deleted.
+ *
+ * @remarks Callers of ExDeleteResourceLite must be running at IRQL <
+ * DISPATCH_LEVEL.
+ *
+ *--*/
NTSTATUS
-STDCALL
-ExDeleteResource (
- PERESOURCE Resource
- )
+NTAPI
+ExDeleteResourceLite(PERESOURCE Resource)
{
- return(ExDeleteResourceLite(Resource));
+ KIRQL OldIrql;
+ DPRINT("ExDeleteResourceLite(Resource 0x%p)\n", Resource);
+
+ /* Sanity checks */
+ ASSERT(IsSharedWaiting(Resource) == FALSE);
+ ASSERT(IsExclusiveWaiting(Resource) == FALSE);
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+
+ /* Lock the resource */
+ KeAcquireSpinLock(&ExpResourceSpinLock, &OldIrql);
+
+ /* Remove the resource */
+ RemoveEntryList(&Resource->SystemResourcesList);
+
+ /* Release the lock */
+ KeReleaseSpinLock(&ExpResourceSpinLock, OldIrql);
+
+ /* Free every structure */
+ if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
+ if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
+ if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
+
+ /* Return success */
+ return STATUS_SUCCESS;
}
-/*
- * @implemented
- */
-NTSTATUS
-STDCALL
-ExDeleteResourceLite (
- PERESOURCE Resource
- )
+/*++
+ * @name ExDisableResourceBoostLite
+ * @implemented NT4
+ *
+ * The ExDisableResourceBoostLite routine disables thread boosting for
+ * the given resource.
+ *
+ * @param Resource
+ * Pointer to the resource whose thread boosting will be disabled.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+ExDisableResourceBoostLite(PERESOURCE Resource)
{
- DPRINT("ExDeleteResourceLite(Resource %x)\n", Resource);
- if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
- if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
- if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
- return(STATUS_SUCCESS);;
+ KIRQL OldIrql;
+
+ /* Sanity check */
+ ExpVerifyResource(Resource);
+
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* Remove the flag */
+ Resource->Flag |= ResourceHasDisabledPriorityBoost;
+
+ /* Release the lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
}
-/*
- * @implemented
- */
+/*++
+ * @name ExGetExclusiveWaiterCount
+ * @implemented NT4
+ *
+ * The ExGetExclusiveWaiterCount routine returns the number of exclusive
+ * waiters for the given resource.
+ *
+ * @param Resource
+ * Pointer to the resource to check.
+ *
+ * @return The number of exclusive waiters.
+ *
+ * @remarks None.
+ *
+ *--*/
ULONG
-STDCALL
-ExGetSharedWaiterCount (
- PERESOURCE Resource
- )
+NTAPI
+ExGetExclusiveWaiterCount(PERESOURCE Resource)
{
- return(Resource->NumberOfSharedWaiters);
+ /* Return the count */
+ return Resource->NumberOfExclusiveWaiters;
}
-
-#ifdef ExInitializeResource
-#undef ExInitializeResource
-#endif
-
-/*
- * @implemented
- */
-NTSTATUS
-STDCALL
-ExInitializeResource (
- PERESOURCE Resource
- )
+/*++
+ * @name ExGetSharedWaiterCount
+ * @implemented NT4
+ *
+ * The ExGetSharedWaiterCount routine returns the number of shared
+ * waiters for the given resource.
+ *
+ * @param Resource
+ * Pointer to the resource to check.
+ *
+ * @return The number of shared waiters.
+ *
+ * @remarks None.
+ *
+ *--*/
+ULONG
+NTAPI
+ExGetSharedWaiterCount(PERESOURCE Resource)
{
- return(ExInitializeResourceLite(Resource));
+ /* Return the count */
+ return Resource->NumberOfSharedWaiters;
}
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-ExInitializeResourceLite (PERESOURCE Resource)
+/*++
+ * @name ExInitializeResourceLite
+ * @implemented NT4
+ *
+ * The ExInitializeResourceLite routine initializes a resource variable.
+ *
+ * @param Resource
+ * Pointer to the resource to check.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks The storage for ERESOURCE must not be allocated from paged pool.
+ *
+ * The storage must be 8-byte aligned.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+ExInitializeResourceLite(PERESOURCE Resource)
{
- DPRINT("ExInitializeResourceLite(Resource %x)\n", Resource);
- memset(Resource,0,sizeof(ERESOURCE));
- Resource->NumberOfSharedWaiters = 0;
- Resource->NumberOfExclusiveWaiters = 0;
- KeInitializeSpinLock(&Resource->SpinLock);
- Resource->Flag = 0;
- Resource->ExclusiveWaiters =
- ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_EXCLUSIVE_LOCK);
- KeInitializeEvent(Resource->ExclusiveWaiters,
- SynchronizationEvent,
- FALSE);
- Resource->SharedWaiters =
- ExAllocatePoolWithTag(NonPagedPool ,sizeof(KSEMAPHORE), TAG_SHARED_SEM);
- KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
- Resource->ActiveCount = 0;
- return(0);
+ DPRINT("ExInitializeResourceLite(Resource 0x%p)\n", Resource);
+
+ /* Clear the structure */
+ RtlZeroMemory(Resource, sizeof(ERESOURCE));
+
+ /* Initialize the lock */
+ KeInitializeSpinLock(&Resource->SpinLock);
+
+ /* Add it into the system list */
+ ExInterlockedInsertTailList(&ExpSystemResourcesList,
+ &Resource->SystemResourcesList,
+ &ExpResourceSpinLock);
+
+ /* Return success */
+ return STATUS_SUCCESS;
}
-/*
- * @implemented
- */
+/*++
+ * @name ExIsResourceAcquiredExclusiveLite
+ * @implemented NT4
+ *
+ * The ExIsResourceAcquiredExclusiveLite routine returns whether the
+ * current thread has exclusive access to a given resource.
+ *
+ * @param Resource
+ * Pointer to the resource to check.
+ *
+ * @return TRUE if the caller already has exclusive access to the given resource.
+ *
+ * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
+ * IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
BOOLEAN
-STDCALL
-ExIsResourceAcquiredExclusiveLite (
- PERESOURCE Resource
- )
-/*
- * FUNCTION: Returns whether the current thread has exclusive access to
- * a given resource
- * ARGUMENTS:
- * Resource = Points to the resource to be queried
- * RETURNS: TRUE if the caller has exclusive access to the resource,
- * FALSE otherwise
- */
+NTAPI
+ExIsResourceAcquiredExclusiveLite(PERESOURCE Resource)
{
- return((Resource->Flag & ResourceOwnedExclusive)
- && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
+ ERESOURCE_THREAD Thread = ExGetCurrentResourceThread();
+ BOOLEAN IsAcquired = FALSE;
+
+ /* Sanity check */
+ ExpVerifyResource(Resource);
+
+ /* Check if it's exclusively acquired */
+ if ((IsOwnedExclusive(Resource)) &&
+ (Resource->OwnerThreads[0].OwnerThread == Thread))
+ {
+ /* It is acquired */
+ IsAcquired = TRUE;
+ }
+
+ /* Return if it's acquired */
+ return IsAcquired;
}
+/*++
+ * @name ExIsResourceAcquiredSharedLite
+ * @implemented NT4
+ *
+ * The ExIsResourceAcquiredSharedLite routine returns whether the
+ * current thread has has access (either shared or exclusive) to a
+ * given resource.
+ *
+ * @param Resource
+ * Pointer to the resource to check.
+ *
+ * @return Number of times the caller has acquired the given resource for
+ * shared or exclusive access.
+ *
+ * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
+ * IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
+ULONG
+NTAPI
+ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
+{
+ ERESOURCE_THREAD Thread;
+ ULONG i, Size;
+ ULONG Count = 0;
+ KIRQL OldIrql;
+ POWNER_ENTRY Owner;
+ /* Sanity check */
+ ExpVerifyResource(Resource);
-#ifdef ExIsResourceAcquiredSharedLite
-#undef ExIsResourceAcquiredSharedLite
-#endif
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+ /* Check if we are in the thread list */
+ if (Resource->OwnerThreads[0].OwnerThread == Thread)
+ {
+ /* Found it, return count */
+ Count = Resource->OwnerThreads[0].OwnerCount;
+ }
+ else if (Resource->OwnerThreads[1].OwnerThread == Thread)
+ {
+ /* Found it on the second list, return count */
+ Count = Resource->OwnerThreads[1].OwnerCount;
+ }
+ else
+ {
+ /* Not in the list, do a full table look up */
+ Owner = Resource->OwnerTable;
+ if (Owner)
+ {
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
-/*
- * @implemented
- */
-
-
-//NTOSAPI
-//DDKAPI
-USHORT STDCALL
-ExIsResourceAcquiredSharedLite(
- IN PERESOURCE Resource)
-/*
- * FUNCTION: Returns whether the current thread has shared access to a given
- * resource
- * ARGUMENTS:
- * Resource = Points to the resource to be queried
- * RETURNS: The number of times the caller has acquired shared access to the
- * given resource
- */
-{
- ULONG i;
- if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
- {
- return (USHORT)(Resource->OwnerThreads[0].OwnerCount);
- }
- if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
- {
- return (USHORT)(Resource->OwnerThreads[1].OwnerCount);
- }
- if (!Resource->OwnerThreads[1].TableSize)
- {
- return(0);
- }
- for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
- {
- if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
- {
- return (USHORT)Resource->OwnerTable[i].OwnerCount;
- }
- }
- return(0);
+ /* Get the resource index */
+ i = ((PKTHREAD)Thread)->ResourceIndex;
+ Size = Owner->TableSize;
+
+ /* Check if the index is valid and check if we don't match */
+ if ((i >= Size) || (Owner[i].OwnerThread != Thread))
+ {
+ /* Sh*t! We need to do a full search */
+ for (i = 1; i < Size; i++)
+ {
+ /* Move to next owner */
+ Owner++;
+
+ /* Try to find a match */
+ if (Owner->OwnerThread == Thread)
+ {
+ /* Finally! */
+ Count = Owner->OwnerCount;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* We found the match directlry */
+ Count = Owner[i].OwnerCount;
+ }
+
+ /* Release the lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ }
+ }
+
+ /* Return count */
+ return Count;
}
-/*
- * @implemented
- */
-VOID
-STDCALL
-ExReinitializeResourceLite (
- PERESOURCE Resource
- )
+/*++
+ * @name ExReinitializeResourceLite
+ * @implemented NT4
+ *
+ * The ExReinitializeResourceLite routine routine reinitializes
+ * an existing resource variable.
+ *
+ * @param Resource
+ * Pointer to the resource to be reinitialized.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks With a single call to ExReinitializeResource, a driver writer can
+ * replace three calls: one to ExDeleteResourceLite, another to
+ * ExAllocatePool, and a third to ExInitializeResourceLite. As
+ * contention for a resource variable increases, memory is dynamically
+ * allocated and attached to the resource in order to track this
+ * contention. As an optimization, ExReinitializeResourceLite retains
+ * and zeroes this previously allocated memory.
+ *
+ * Callers of ExReinitializeResourceLite must be running at
+ * IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+ExReinitializeResourceLite(PERESOURCE Resource)
{
- Resource->NumberOfSharedWaiters = 0;
- Resource->NumberOfExclusiveWaiters = 0;
- KeInitializeSpinLock(&Resource->SpinLock);
- Resource->Flag=0;
- KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
- FALSE);
- KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
- Resource->ActiveCount = 0;
- if (Resource->OwnerTable)
- {
- ExFreePool(Resource->OwnerTable);
- }
- Resource->OwnerThreads[0].OwnerThread=0;
- Resource->OwnerThreads[0].OwnerCount=0;
- Resource->OwnerThreads[1].OwnerThread=0;
- Resource->OwnerThreads[1].OwnerCount=0;
+ PKEVENT Event;
+ PKSEMAPHORE Semaphore;
+ ULONG i, Size;
+ POWNER_ENTRY Owner;
+
+ /* Get the owner table */
+ Owner = Resource->OwnerTable;
+ if (Owner)
+ {
+ /* Get the size and loop it */
+ Size = Owner->TableSize;
+ for (i = 0; i < Size; i++)
+ {
+ /* Zero the table */
+ Owner[i].OwnerThread = 0;
+ Owner[i].OwnerCount = 0;
+ }
+ }
+
+ /* Zero the flags and count */
+ Resource->Flag = 0;
+ Resource->ActiveCount = 0;
+
+ /* Reset the semaphore */
+ Semaphore = Resource->SharedWaiters;
+ if (Semaphore) KeInitializeSemaphore(Semaphore, 0, MAXLONG);
+
+ /* Reset the event */
+ Event = Resource->ExclusiveWaiters;
+ if (Event) KeInitializeEvent(Event, SynchronizationEvent, FALSE);
+
+ /* Clear the resource data */
+ Resource->OwnerThreads[0].OwnerThread = 0;
+ Resource->OwnerThreads[1].OwnerThread = 0;
+ Resource->OwnerThreads[0].OwnerCount = 0;
+ Resource->OwnerThreads[1].OwnerCount = 0;
+ Resource->ContentionCount = 0;
+ Resource->NumberOfSharedWaiters = 0;
+ Resource->NumberOfExclusiveWaiters = 0;
+
+ /* Reset the spinlock */
+ KeInitializeSpinLock(&Resource->SpinLock);
+ return STATUS_SUCCESS;
}
-/*
- * @implemented
- */
+/*++
+ * @name ExReleaseResourceLite
+ * @implemented NT4
+ *
+ * The ExReleaseResourceLite routine routine releases
+ * a specified executive resource owned by the current thread.
+ *
+ * @param Resource
+ * Pointer to the resource to be released.
+ *
+ * @return None.
+ *
+ * @remarks Callers of ExReleaseResourceLite must be running at
+ * IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
VOID
FASTCALL
-ExReleaseResourceLite (
- PERESOURCE Resource
- )
+ExReleaseResourceLite(PERESOURCE Resource)
{
- ExReleaseResourceForThreadLite(Resource,
- ExGetCurrentResourceThread());
-}
+ ERESOURCE_THREAD Thread;
+ ULONG Count, i;
+ KIRQL OldIrql;
+ POWNER_ENTRY Owner, Limit;
+ DPRINT("ExReleaseResourceLite: %p\n", Resource);
+ /* Sanity check */
+ ExpVerifyResource(Resource);
+ /* Get the thread and lock the resource */
+ Thread = ExGetCurrentResourceThread();
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+ ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread);
-#ifdef ExReleaseResourceForThread
-#undef ExReleaseResourceForThread
-#endif
+ /* Check if it's exclusively owned */
+ if (IsOwnedExclusive(Resource))
+ {
+ /* Decrement owner count and check if we're done */
+ ASSERT(Resource->OwnerThreads[0].OwnerCount > 0);
+ ASSERT(Resource->ActiveCount == 1);
+ if (--Resource->OwnerThreads[0].OwnerCount)
+ {
+ /* Done, release lock! */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return;
+ }
+ /* Clear the owner */
+ Resource->OwnerThreads[0].OwnerThread = 0;
-/*
- * @implemented
- */
+ /* 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;
+ }
+
+ /* Remove the exclusive flag */
+ Resource->Flag &= ~ResourceOwnedExclusive;
+
+ Resource->ActiveCount = 0;
+ }
+ else
+ {
+ /* Check if we are in the thread list */
+ if (Resource->OwnerThreads[1].OwnerThread == Thread)
+ {
+ /* Found it, get owner */
+ Owner = &Resource->OwnerThreads[1];
+ }
+ else
+ {
+ /* Not in the list, do a full table look up */
+ i = ((PKTHREAD)Thread)->ResourceIndex;
+ Owner = Resource->OwnerTable;
+ if (!Owner)
+ {
+ /* Nobody owns us, bugcheck! */
+ KEBUGCHECKEX(RESOURCE_NOT_OWNED,
+ (ULONG_PTR)Resource,
+ Thread,
+ (ULONG_PTR)Resource->OwnerTable,
+ (ULONG_PTR)2);
+ }
+
+ /* Check if we're out of the size and don't match */
+ if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread))
+ {
+ /* Get the last entry */
+ Limit = &Owner[Owner->TableSize];
+ for (;;)
+ {
+ /* Move to the next entry */
+ Owner++;
+
+ /* Check if we don't match */
+ if (Owner >= Limit)
+ {
+ /* Nobody owns us, bugcheck! */
+ KEBUGCHECKEX(RESOURCE_NOT_OWNED,
+ (ULONG_PTR)Resource,
+ Thread,
+ (ULONG_PTR)Resource->OwnerTable,
+ 2);
+ }
+
+ /* Check for a match */
+ if (Owner->OwnerThread == Thread) break;
+ }
+ }
+ else
+ {
+ /* Get the entry directly */
+ Owner = &Owner[i];
+ }
+ }
+
+ /* Sanity checks */
+ ASSERT(Owner->OwnerThread == Thread);
+ ASSERT(Owner->OwnerCount > 0);
+
+ /* Check if we are the last owner */
+ if (--Owner->OwnerCount)
+ {
+ /* Release lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return;
+ }
+
+ /* Clear owner */
+ Owner->OwnerThread = 0;
+
+ /* See if the resource isn't being owned anymore */
+ ASSERT(Resource->ActiveCount > 0);
+ if (!(--Resource->ActiveCount))
+ {
+ /* Check if there's an exclusive waiter */
+ if (IsExclusiveWaiting(Resource))
+ {
+ /* Give exclusive access */
+ Resource->Flag |= ResourceOwnedExclusive;
+ 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;
+ }
+ }
+ }
+
+ /* Release lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return;
+}
+
+/*++
+ * @name ExReleaseResourceForThreadLite
+ * @implemented NT4
+ *
+ * The ExReleaseResourceForThreadLite routine routine releases
+ * the input resource of the indicated thread.
+ *
+ * @param Resource
+ * Pointer to the resource to be released.
+ *
+ * @param Thread
+ * Identifies the thread that originally acquired the resource.
+ *
+ * @return None.
+ *
+ * @remarks Callers of ExReleaseResourceForThreadLite must be running at
+ * IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
VOID
-STDCALL
-ExReleaseResourceForThread (
- PERESOURCE Resource,
- ERESOURCE_THREAD ResourceThreadId
- )
+NTAPI
+ExReleaseResourceForThreadLite(PERESOURCE Resource,
+ ERESOURCE_THREAD Thread)
{
- ExReleaseResourceForThreadLite(Resource,ResourceThreadId);
-}
+ ULONG i;
+ ULONG Count;
+ KIRQL OldIrql;
+ POWNER_ENTRY Owner;
+ ASSERT(Thread != 0);
+ DPRINT("ExReleaseResourceForThreadLite: %p\n", Resource);
+ /* Get the thread and lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
-/*
- * @unimplemented
- */
+ /* Sanity check */
+ ExpVerifyResource(Resource);
+
+ /* Check if it's exclusively owned */
+ if (IsOwnedExclusive(Resource))
+ {
+ /* Decrement owner count and check if we're done */
+ ASSERT(Resource->OwnerThreads[0].OwnerThread == Thread);
+ ASSERT(Resource->OwnerThreads[0].OwnerCount > 0);
+ if (--Resource->OwnerThreads[0].OwnerCount)
+ {
+ /* Done, release lock! */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return;
+ }
+
+ /* Clear the owner */
+ Resource->OwnerThreads[0].OwnerThread = 0;
+
+ /* See if the resource isn't being owned anymore */
+ 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 = (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;
+ }
+
+ /* Remove the exclusive flag */
+ Resource->Flag &= ~ResourceOwnedExclusive;
+ }
+ }
+ else
+ {
+ /* Check if we are in the thread list */
+ if (Resource->OwnerThreads[0].OwnerThread == Thread)
+ {
+ /* Found it, get owner */
+ Owner = &Resource->OwnerThreads[0];
+ }
+ else if (Resource->OwnerThreads[1].OwnerThread == Thread)
+ {
+ /* Found it on the second list, get owner */
+ Owner = &Resource->OwnerThreads[1];
+ }
+ else
+ {
+ /* Assume no valid index */
+ i = 1;
+
+ /* If we got a valid pointer, try to get the resource index */
+ if (!((ULONG)Thread & 3)) i = ((PKTHREAD)Thread)->ResourceIndex;
+
+ /* Do a table lookup */
+ Owner = Resource->OwnerTable;
+ ASSERT(Owner != NULL);
+
+ /* Check if we're out of the size and don't match */
+ if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread))
+ {
+ /* Get the last entry */
+ for (;;)
+ {
+ /* Move to the next entry */
+ Owner++;
+
+ /* Check for a match */
+ if (Owner->OwnerThread == Thread) break;
+ }
+ }
+ else
+ {
+ /* Get the entry directly */
+ Owner = &Owner[i];
+ }
+ }
+
+ /* Sanity checks */
+ ASSERT(Owner->OwnerThread == Thread);
+ ASSERT(Owner->OwnerCount > 0);
+
+ /* Check if we are the last owner */
+ if (!(--Owner->OwnerCount))
+ {
+ /* Release lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return;
+ }
+
+ /* Clear owner */
+ Owner->OwnerThread = 0;
+
+ /* See if the resource isn't being owned anymore */
+ ASSERT(Resource->ActiveCount > 0);
+ if (!(--Resource->ActiveCount))
+ {
+ /* Check if there's an exclusive waiter */
+ 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;
+ }
+ }
+ }
+
+ /* Release lock */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return;
+}
+
+/*++
+ * @name ExSetResourceOwnerPointer
+ * @implemented NT4
+ *
+ * The ExSetResourceOwnerPointer routine routine sets the owner thread
+ * thread pointer for an executive resource.
+ *
+ * @param Resource
+ * Pointer to the resource whose owner to change.
+ *
+ * @param OwnerPointer
+ * Pointer to an owner thread pointer of type ERESOURCE_THREAD.
+ *
+ * @return None.
+ *
+ * @remarks ExSetResourceOwnerPointer, used in conjunction with
+ * ExReleaseResourceForThreadLite, provides a means for one thread
+ * (acting as an resource manager thread) to acquire and release
+ * resources for use by another thread (acting as a resource user
+ * thread).
+ *
+ * After calling ExSetResourceOwnerPointer for a specific resource,
+ * the only other routine that can be called for that resource is
+ * ExReleaseResourceForThreadLite.
+ *
+ * Callers of ExSetResourceOwnerPointer must be running at
+ * IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
VOID
-STDCALL
-ExReleaseResourceForThreadLite (
- PERESOURCE Resource,
- ERESOURCE_THREAD ResourceThreadId
- )
-/*
- * FUNCTION: Releases a resource for the given thread
- * ARGUMENTS:
- * Resource = Points to the release to release
- * ResourceThreadId = Identifies the thread that originally acquired
- * the resource
- * NOTES: Must be running at IRQL < DISPATCH_LEVEL
- * BUG: We don't support starving exclusive waiters
- */
+NTAPI
+ExSetResourceOwnerPointer(IN PERESOURCE Resource,
+ IN PVOID OwnerPointer)
+{
+ ERESOURCE_THREAD Thread;
+ KIRQL OldIrql;
+ POWNER_ENTRY Owner, ThisOwner;
+
+ /* Sanity check */
+ ASSERT((OwnerPointer != 0) && (((ULONG_PTR)OwnerPointer & 3) == 3));
+
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+
+ /* Sanity check */
+ ExpVerifyResource(Resource);
+
+ /* Lock the resource */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* Check if it's exclusive */
+ if (IsOwnedExclusive(Resource))
+ {
+ /* If it's exclusive, set the first entry no matter what */
+ ASSERT(Resource->OwnerThreads[0].OwnerThread == Thread);
+ ASSERT(Resource->OwnerThreads[0].OwnerCount > 0);
+ Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer;
+ }
+ else
+ {
+ /* Set the thread in both entries */
+ ThisOwner = ExpFindEntryForThread(Resource,
+ (ERESOURCE_THREAD)OwnerPointer,
+ 0);
+ Owner = ExpFindEntryForThread(Resource, Thread, 0);
+ if (!Owner)
+ {
+ /* Nobody owns it, crash */
+ KEBUGCHECKEX(RESOURCE_NOT_OWNED,
+ (ULONG_PTR)Resource,
+ Thread,
+ (ULONG_PTR)Resource->OwnerTable,
+ 3);
+ }
+
+ /* Set if we are the owner */
+ if (ThisOwner)
+ {
+ /* Update data */
+ ThisOwner->OwnerCount += Owner->OwnerCount;
+ Owner->OwnerCount = 0;
+ Owner->OwnerThread = 0;
+ ASSERT(Resource->ActiveCount >= 2);
+ Resource->ActiveCount--;
+ }
+ }
+
+ /* Release the resource */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+}
+
+/*++
+ * @name ExTryToAcquireResourceExclusiveLite
+ * @implemented NT4
+ *
+ * The ExTryToAcquireResourceExclusiveLite routine routine attemps to
+ * acquire the given resource for exclusive access.
+ *
+ * @param Resource
+ * Pointer to the resource to be acquired.
+ *
+ * @return TRUE if the given resource has been acquired for the caller.
+ *
+ * @remarks Callers of ExTryToAcquireResourceExclusiveLite must be running at
+ * IRQL < DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExTryToAcquireResourceExclusiveLite(PERESOURCE Resource)
{
- KIRQL oldIrql;
-
- DPRINT("ExReleaseResourceForThreadLite(Resource %x, ResourceThreadId %x)\n",
- Resource, ResourceThreadId);
-
- KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
- if (Resource->Flag & ResourceOwnedExclusive)
- {
- DPRINT("Releasing from exclusive access\n");
-
- Resource->OwnerThreads[0].OwnerCount--;
- if (Resource->OwnerThreads[0].OwnerCount > 0)
- {
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExReleaseResourceForThreadLite() finished\n");
- return;
- }
-
- Resource->OwnerThreads[0].OwnerThread = 0;
- Resource->ActiveCount--;
- Resource->Flag &=(~ResourceOwnedExclusive);
- assert(Resource->ActiveCount == 0);
- DPRINT("Resource->NumberOfExclusiveWaiters %d\n",
- Resource->NumberOfExclusiveWaiters);
- if (Resource->NumberOfExclusiveWaiters)
- {
- /* get resource to first exclusive waiter */
- KeSetEvent(Resource->ExclusiveWaiters,
- IO_NO_INCREMENT,
- FALSE);
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExReleaseResourceForThreadLite() finished\n");
- return;
- }
- DPRINT("Resource->NumberOfSharedWaiters %d\n",
- Resource->NumberOfSharedWaiters);
- if (Resource->NumberOfSharedWaiters)
- {
- DPRINT("Releasing semaphore\n");
- KeReleaseSemaphore(Resource->SharedWaiters,
- IO_NO_INCREMENT,
- Resource->NumberOfSharedWaiters,
- FALSE);
- }
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExReleaseResourceForThreadLite() finished\n");
- return;
- }
-
- EiRemoveSharedOwner(Resource, ResourceThreadId);
-
- if (Resource->ActiveCount == 0)
- {
- if (Resource->NumberOfExclusiveWaiters)
- {
- /* get resource to first exclusive waiter */
- KeSetEvent(Resource->ExclusiveWaiters,
- IO_NO_INCREMENT,
- FALSE);
- }
- }
-
- KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
- DPRINT("ExReleaseResourceForThreadLite() finished\n");
+ ERESOURCE_THREAD Thread;
+ KIRQL OldIrql;
+ BOOLEAN Acquired = FALSE;
+ DPRINT("ExTryToAcquireResourceExclusiveLite: %p\n", Resource);
+
+ /* Sanity check */
+ ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
+
+ /* Get the thread */
+ Thread = ExGetCurrentResourceThread();
+
+ /* Sanity check and validation */
+ ASSERT(KeIsExecutingDpc() == FALSE);
+ ExpVerifyResource(Resource);
+
+ /* Acquire the lock */
+ ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+ /* Check if there is an owner */
+ if (!Resource->ActiveCount)
+ {
+ /* No owner, give exclusive access */
+ Resource->Flag |= ResourceOwnedExclusive;
+ Resource->OwnerThreads[0].OwnerThread = Thread;
+ Resource->OwnerThreads[0].OwnerCount = 1;
+ Resource->ActiveCount = 1;
+ Acquired = TRUE;
+ }
+ else if ((IsOwnedExclusive(Resource)) &&
+ (Resource->OwnerThreads[0].OwnerThread == Thread))
+ {
+ /* Do a recursive acquire */
+ Resource->OwnerThreads[0].OwnerCount++;
+ Acquired = TRUE;
+ }
+
+ /* Release the resource */
+ ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+ return Acquired;
}
+/*++
+ * @name ExEnterCriticalRegionAndAcquireResourceExclusive
+ * @implemented NT5.1
+ *
+ * The ExEnterCriticalRegionAndAcquireResourceExclusive enters a critical
+ * region and then exclusively acquires a resource.
+ *
+ * @param Resource
+ * Pointer to the resource to acquire.
+ *
+ * @return Pointer to the Win32K thread pointer of the current thread.
+ *
+ * @remarks See ExAcquireResourceExclusiveLite.
+ *
+ *--*/
+PVOID
+NTAPI
+ExEnterCriticalRegionAndAcquireResourceExclusive(PERESOURCE Resource)
+{
+ /* Enter critical region */
+ KeEnterCriticalRegion();
-/*
- * @unimplemented
- */
+ /* Acquire the resource */
+ ExAcquireResourceExclusiveLite(Resource, TRUE);
+
+ /* Return the Win32 Thread */
+ return KeGetCurrentThread()->Win32Thread;
+}
+
+/*++
+ * @name ExReleaseResourceAndLeaveCriticalRegion
+ * @implemented NT5.1
+ *
+ * The ExReleaseResourceAndLeaveCriticalRegion release a resource and
+ * then leaves a critical region.
+ *
+ * @param Resource
+ * Pointer to the resource to release.
+ *
+ * @return None
+ *
+ * @remarks See ExReleaseResourceLite.
+ *
+ *--*/
VOID
-STDCALL
-ExSetResourceOwnerPointer (
- IN PERESOURCE Resource,
- IN PVOID OwnerPointer
- )
+FASTCALL
+ExReleaseResourceAndLeaveCriticalRegion(PERESOURCE Resource)
{
+ /* Release the resource */
+ ExReleaseResourceLite(Resource);
+ /* Leave critical region */
+ KeLeaveCriticalRegion();
}
/* EOF */
+