diff --git a/reactos/include/ndk/extypes.h b/reactos/include/ndk/extypes.h index 64557d4817b..bd7c6f17946 100644 --- a/reactos/include/ndk/extypes.h +++ b/reactos/include/ndk/extypes.h @@ -117,6 +117,11 @@ extern ULONG NTSYSAPI NtBuildNumber; #define EX_PUSH_LOCK_FLAGS_EXCLUSIVE 1 #define EX_PUSH_LOCK_FLAGS_WAIT 2 +// +// Resource (ERESOURCE) Flags +// +#define ResourceHasDisabledPriorityBoost 0x08 + // // Shutdown types for NtShutdownSystem // diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 2847aaf9b56..82df1cf0f6d 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -489,7 +489,7 @@ ExpLoadInitialProcess(PHANDLE ProcessHandle, DPRINT("Process created successfully\n"); return STATUS_SUCCESS; } - + VOID INIT_FUNCTION STDCALL @@ -543,6 +543,9 @@ ExpInitializeExecutive(VOID) InitializeListHead(&KiProfileSourceListHead); KeInitializeSpinLock(&KiProfileLock); + /* Initialize resources */ + ExpResourceInitialization(); + /* Load basic Security for other Managers */ if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED); diff --git a/reactos/ntoskrnl/ex/resource.c b/reactos/ntoskrnl/ex/resource.c index 1d673261680..2b87a4b39fa 100644 --- a/reactos/ntoskrnl/ex/resource.c +++ b/reactos/ntoskrnl/ex/resource.c @@ -1,38 +1,20 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ex/resource.c - * PURPOSE: Resource synchronization construct - * - * PROGRAMMERS: No programmer listed. - */ - - /* - * 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. - * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Kernel + * FILE: ntoskrnl/ex/resource.c + * PURPOSE: ERESOURCE Implementation + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ -#define ResourceDisableBoost 0x08 +/* 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. + */ /* INCLUDES *****************************************************************/ @@ -40,916 +22,2294 @@ #define NDEBUG #include -/* FUNCTIONS *****************************************************************/ - - -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 - */ -{ - return(ExAcquireResourceExclusiveLite(Resource,FALSE)); -} - -#ifdef ExAcquireResourceExclusive -#undef ExAcquireResourceExclusive +#if defined (ALLOC_PRAGMA) +#pragma alloc_text(INIT, ExpResourceInitialization) #endif -/* - * @implemented - */ -BOOLEAN -STDCALL -ExAcquireResourceExclusive ( - PERESOURCE Resource, - BOOLEAN Wait - ) +/* Macros for reading resource flags */ +#define IsExclusiveWaiting(r) (r->NumberOfExclusiveWaiters) +#define IsSharedWaiting(r) (r->NumberOfSharedWaiters) +#define IsOwnedExclusive(r) (r->Flag & ResourceOwnedExclusive) + +/* DATA***********************************************************************/ + +LARGE_INTEGER ExpTimeout; +ULONG ExpResourceTimeoutCount = 90 * 3600 / 2; +KSPIN_LOCK ExpResourceSpinLock; +LIST_ENTRY ExpSystemResourcesList; +BOOLEAN ExResourceStrict = FALSE; /* FIXME */ + +/* 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,Wait)); + /* 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))); } - -/* - * @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 - */ +/*++ + * @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) { - KIRQL oldIrql; - - DPRINT("ExAcquireResourceExclusiveLite(Resource 0x%p, Wait %d)\n", - Resource, Wait); - - ASSERT_IRQL_LESS(DISPATCH_LEVEL); - -/* undefed for now, since cdfs must be fixed first */ -#if 0 - /* At least regular kmode APC's must be disabled - * Note that this requirement is missing in old DDK's */ - ASSERT(KeGetCurrentThread() == NULL || /* <-Early in the boot process the current thread is obseved to be NULL */ - KeGetCurrentThread()->KernelApcDisable || - KeGetCurrentIrql() == APC_LEVEL); + /* 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 - 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); -} - -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 - */ -{ - 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; iOwnerThreads[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); -} - -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 - */ -{ - ERESOURCE_THREAD CurrentThread = ExGetCurrentResourceThread(); - POWNER_ENTRY freeEntry; - ULONG i = 0; - - DPRINT("EiAddSharedOwner(Resource 0x%p)\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; iOwnerThreads[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 0x%p\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); -} - -/* - * @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 - */ -{ - KIRQL oldIrql; - - DPRINT("ExAcquireResourceSharedLite(Resource 0x%p, Wait %d)\n", - Resource, Wait); - - ASSERT_IRQL_LESS(DISPATCH_LEVEL); - -/* undefed for now, since cdfs must be fixed first */ -#if 0 - /* At least regular kmode APC's must be disabled - * Note that this requirement is missing in old DDK's - */ - ASSERT(KeGetCurrentThread() == NULL || /* <-Early in the boot process the current thread is obseved to be NULL */ - KeGetCurrentThread()->KernelApcDisable || - KeGetCurrentIrql() == APC_LEVEL); -#endif - - 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); -} - -/* - * @implemented - */ +/*++ + * @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 -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 - */ +NTAPI +INIT_FUNCTION +ExpResourceInitialization(VOID) { - ULONG oldWaiters; - KIRQL oldIrql; - - DPRINT("ExConvertExclusiveToSharedLite(Resource 0x%p)\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"); + /* Setup the timeout */ + ExpTimeout.QuadPart = Int32x32To64(4, -10000000); + InitializeListHead(&ExpSystemResourcesList); + KeInitializeSpinLock(&ExpResourceSpinLock); } -/* - * @implemented - */ +/*++ + * @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 -STDCALL -ExDisableResourceBoostLite ( - PERESOURCE Resource - ) +NTAPI +ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource, + IN PKIRQL OldIrql) { - Resource->Flag |= ResourceDisableBoost; + PKEVENT Event; + + /* 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); } -/* - * @implemented - */ -ULONG -STDCALL -ExGetExclusiveWaiterCount ( - PERESOURCE Resource - ) -{ - return(Resource->NumberOfExclusiveWaiters); -} - -/* - * @implemented - */ -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 - */ -{ - KIRQL oldIrql; - - DPRINT("ExAcquireSharedStarveExclusive(Resource 0x%p, 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); -} - -/* - * @implemented - */ -BOOLEAN -STDCALL -ExAcquireSharedWaitForExclusive ( - PERESOURCE Resource, - BOOLEAN Wait - ) -{ - return(ExAcquireResourceSharedLite(Resource,Wait)); -} - - -#ifdef ExDeleteResource -#undef ExDeleteResource -#endif - - -/* - * @implemented - */ -NTSTATUS -STDCALL -ExDeleteResource ( - PERESOURCE Resource - ) -{ - return(ExDeleteResourceLite(Resource)); -} - -/* - * @implemented - */ -NTSTATUS -STDCALL -ExDeleteResourceLite ( - PERESOURCE Resource - ) -{ - DPRINT("ExDeleteResourceLite(Resource 0x%p)\n", Resource); - if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable); - if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters); - if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters); - return(STATUS_SUCCESS); -} - -/* - * @implemented - */ -ULONG -STDCALL -ExGetSharedWaiterCount ( - PERESOURCE Resource - ) -{ - return(Resource->NumberOfSharedWaiters); -} - - -#ifdef ExInitializeResource -#undef ExInitializeResource -#endif - -/* - * @implemented - */ -NTSTATUS -STDCALL -ExInitializeResource ( - PERESOURCE Resource - ) -{ - return(ExInitializeResourceLite(Resource)); -} - -/* - * @implemented - */ -NTSTATUS STDCALL -ExInitializeResourceLite (PERESOURCE Resource) -{ - DPRINT("ExInitializeResourceLite(Resource 0x%p)\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); -} - -/* - * @implemented - */ -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 - */ -{ - return((Resource->Flag & ResourceOwnedExclusive) - && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread()); -} - - - -#ifdef ExIsResourceAcquiredSharedLite -#undef ExIsResourceAcquiredSharedLite -#endif - - -/* - * @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; iOwnerThreads[1].TableSize; i++) - { - if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread()) - { - return (USHORT)Resource->OwnerTable[i].OwnerCount; - } - } - return(0); -} - -/* - * @implemented - */ +/*++ + * @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 -STDCALL -ExReinitializeResourceLite ( - PERESOURCE Resource - ) +NTAPI +ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource, + IN PKIRQL OldIrql) { - 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; + 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); } -/* - * @implemented - */ +/*++ + * @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 -FASTCALL -ExReleaseResourceLite ( - PERESOURCE Resource - ) +NTAPI +ExpExpandResourceOwnerTable(IN PERESOURCE Resource, + IN PKIRQL OldIrql) { - ExReleaseResourceForThreadLite(Resource, - ExGetCurrentResourceThread()); -} + 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); -#ifdef ExReleaseResourceForThread -#undef ExReleaseResourceForThread -#endif + /* Allocate memory for the table */ + Table = ExAllocatePoolWithTag(NonPagedPool, + NewSize * sizeof(OWNER_ENTRY), + TAG_RESOURCE_TABLE); - -/* - * @implemented - */ -VOID -STDCALL -ExReleaseResourceForThread ( - PERESOURCE Resource, - ERESOURCE_THREAD ResourceThreadId - ) -{ - ExReleaseResourceForThreadLite(Resource,ResourceThreadId); -} - - -/* - * @implemented - */ -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 - */ -{ - KIRQL oldIrql; - - DPRINT("ExReleaseResourceForThreadLite(Resource 0x%p, ResourceThreadId 0x%p)\n", - Resource, ResourceThreadId); - - ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); - - 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"); -} - - -/* - * @implemented - */ -VOID -STDCALL -ExSetResourceOwnerPointer ( - IN PERESOURCE Resource, - IN PVOID OwnerPointer - ) -{ - PKTHREAD CurrentThread; - KIRQL OldIrql; - POWNER_ENTRY OwnerEntry; - - CurrentThread = KeGetCurrentThread(); + /* Zero the table */ + RtlZeroMemory((PVOID)(Table + OldSize), + (NewSize - OldSize) * sizeof(OWNER_ENTRY)); /* Lock the resource */ - KeAcquireSpinLock(&Resource->SpinLock, &OldIrql); + ExAcquireResourceLock(&Resource->SpinLock, OldIrql); - /* Check if it's exclusive */ - if (Resource->Flag & ResourceOwnedExclusive) { + /* 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)); - /* If it's exclusive, set the first entry no matter what */ - Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer; + /* Acquire dispatcher lock to prevent thread boosting */ + //KeAcquireDispatcherDatabaseLockAtDpcLevel(); - } else { + /* Set the new table data */ + Table->TableSize = NewSize; + Resource->OwnerTable = Table; - /* Check both entries and see which one matches the current thread */ - if (Resource->OwnerThreads[0].OwnerThread == (ULONG_PTR)CurrentThread) { + /* Sanity check */ + ExpVerifyResource(Resource); - Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer; + /* Release locks */ + //KeReleaseDispatcherDatabaseLockFromDpcLevel(); + ExReleaseResourceLock(&Resource->SpinLock, *OldIrql); - } else if (Resource->OwnerThreads[1].OwnerThread == (ULONG_PTR)CurrentThread) { + /* Free the old table */ + if (Owner) ExFreePool(Owner); - Resource->OwnerThreads[1].OwnerThread = (ULONG_PTR)OwnerPointer; + /* Set the resource index */ + if (!OldSize) OldSize = 1; + } - } else { /* None of the entries match, so we need to do a lookup */ + /* Set the resource index */ + KeGetCurrentThread()->ResourceIndex = (UCHAR)OldSize; - /* Get the first Entry */ - OwnerEntry = Resource->OwnerTable; + /* Lock the resource again */ + ExAcquireResourceLock(&Resource->SpinLock, OldIrql); +} - /* Check if the Current Thread is in the Resource Table Entry */ - if ((CurrentThread->ResourceIndex >= OwnerEntry->TableSize) || - (OwnerEntry[CurrentThread->ResourceIndex].OwnerThread != (ULONG_PTR)CurrentThread)) { +/*++ + * @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) +{ + POWNER_ENTRY Owner, Limit; + ULONG Size; + POWNER_ENTRY FreeEntry = NULL; + DPRINT("ExpFindFreeEntry: %p\n", Resource); - /* Loop until we find the current thread in an entry */ - for (;OwnerEntry->OwnerThread == (ULONG_PTR)CurrentThread;OwnerEntry++); + /* Sanity check */ + ASSERT(OldIrql != 0); + ASSERT(Resource->OwnerThreads[0].OwnerThread != 0); - } else { + /* 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]; - /* It's in the current RTE, so set it */ - OwnerEntry = &OwnerEntry[CurrentThread->ResourceIndex]; + /* 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; +} + +/*++ + * @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) +{ + 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. + * + *--*/ +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)) + { + /* 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); + + /* Release Lock if needed */ + if (!Released) KeReleaseDispatcherDatabaseLockFromDpcLevel(); + + /* Make sure we're still at dispatch */ + ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); + } + } +} + +/*++ + * @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 +FASTCALL +ExpWaitForResource(IN PERESOURCE Resource, + IN PVOID Object) +{ + ULONG i; + ULONG Size, WaitCount = 0; + KIRQL OldIrql; + POWNER_ENTRY Owner; + PKTHREAD OwnerThread, Thread; + NTSTATUS Status; + LARGE_INTEGER Timeout; + + /* 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); + } } - /* Now that we went to the right entry, set the Owner Pointer */ - OwnerEntry->OwnerThread = (ULONG_PTR)OwnerPointer; + /* Break */ + DbgBreakPoint(); + DPRINT1("EX - Rewaiting\n"); + ExReleaseResourceLock(&Resource->SpinLock, OldIrql); +#endif + } + + /* Check if we can boost */ + if (!(Resource->Flag & ResourceHasDisabledPriorityBoost)) + { + /* 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); + } + } + } + } + } +} + +/* 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) +{ + 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; +} + +/*++ + * @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 +NTAPI +ExAcquireResourceSharedLite(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); + ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread); + + /* See if nobody owns us */ +TryAcquire: + DPRINT("ExAcquireResourceSharedLite(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; + } + 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 TRUE; + } + + /* 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; +} + +/*++ + * @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 +NTAPI +ExAcquireSharedWaitForExclusive(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("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); + + /* 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; + + /* 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’s 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 +NTAPI +ExDeleteResourceLite(PERESOURCE 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; +} + +/*++ + * @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) +{ + 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); +} + +/*++ + * @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 +NTAPI +ExGetExclusiveWaiterCount(PERESOURCE Resource) +{ + /* Return the count */ + return Resource->NumberOfExclusiveWaiters; +} + +/*++ + * @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 the count */ + return Resource->NumberOfSharedWaiters; +} + +/*++ + * @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 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; +} + +/*++ + * @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 +NTAPI +ExIsResourceAcquiredExclusiveLite(PERESOURCE Resource) +{ + 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); + + /* 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); + + /* 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; +} + +/*++ + * @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) +{ + 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; +} + +/*++ + * @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) +{ + 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); + + /* Check if it's exclusively owned */ + if (IsOwnedExclusive(Resource)) + { + /* Decrement owner count and check if we're done */ + 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[1].OwnerThread == Thread) + { + /* Found it, get owner */ + Owner = &Resource->OwnerThreads[1]; + } + else if (Resource->OwnerThreads[0].OwnerThread == Thread) + { + /* Found it on the second list, get owner */ + Owner = &Resource->OwnerThreads[0]; + } + 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 +NTAPI +ExReleaseResourceForThreadLite(PERESOURCE Resource, + ERESOURCE_THREAD Thread) +{ + 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); + + /* 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 +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 */ - KeReleaseSpinLock(&Resource->SpinLock, OldIrql); + 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) +{ + 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(); + + /* 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 +FASTCALL +ExReleaseResourceAndLeaveCriticalRegion(PERESOURCE Resource) +{ + /* Release the resource */ + ExReleaseResourceLite(Resource); + + /* Leave critical region */ + KeLeaveCriticalRegion(); } /* EOF */ + diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index 075fbbc6773..714b97c7ca8 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -15,6 +15,17 @@ extern POBJECT_TYPE ExEventPairObjectType; ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \ EX_HANDLE_ENTRY_AUDITONCLOSE))) +/* Note: we only use a spinlock on SMP. On UP, we cli/sti intead */ +#ifndef CONFIG_SMP +#define ExAcquireResourceLock(l, i) \ + UNREFERENCED_PARAMETER(*i); \ + Ke386DisableInterrupts(); +#define ExReleaseResourceLock(l, i) Ke386EnableInterrupts(); +#else +#define ExAcquireResourceLock(l, i) KeAcquireSpinLock(l, i); +#define ExReleaseResourceLock(l, i) KeReleaseSpinLock(l, i); +#endif + /* INITIALIZATION FUNCTIONS *************************************************/ VOID @@ -77,6 +88,10 @@ VOID STDCALL ExpInitializeProfileImplementation(VOID); +VOID +NTAPI +ExpResourceInitialization(VOID); + /* Rundown Functions ********************************************************/ VOID diff --git a/reactos/ntoskrnl/include/internal/tag.h b/reactos/ntoskrnl/include/internal/tag.h index 4d36fc9d4ac..a7d96d472f7 100644 --- a/reactos/ntoskrnl/include/internal/tag.h +++ b/reactos/ntoskrnl/include/internal/tag.h @@ -10,9 +10,9 @@ #define CALLBACK_TAG TAG('C','L','B','K') /* formerly located in ex/resource.c */ -#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') +#define TAG_RESOURCE_TABLE TAG('R', 'e', 'T', 'a') +#define TAG_RESOURCE_EVENT TAG('R', 'e', 'T', 'a') +#define TAG_RESOURCE_SEMAPHORE TAG('R', 'e', 'T', 'a') /* formerly located in fs/notify.c */ #define FSRTL_NOTIFY_TAG TAG('N','O','T','I') diff --git a/reactos/ntoskrnl/ntoskrnl.mc b/reactos/ntoskrnl/ntoskrnl.mc index e3cde5f3d6e..12987c73379 100644 --- a/reactos/ntoskrnl/ntoskrnl.mc +++ b/reactos/ntoskrnl/ntoskrnl.mc @@ -1003,14 +1003,6 @@ Language=English WORKER_THREAD_RETURNED_AT_BAD_IRQL . -MessageId=0xE4 -Severity=Success -Facility=System -SymbolicName=WORKER_INVALID -Language=English -WORKER_INVALID -. - MessageId=0xE2 Severity=Success Facility=System @@ -1019,6 +1011,22 @@ Language=English MANUALLY_INITIATED_CRASH . +MessageId=0xE3 +Severity=Success +Facility=System +SymbolicName=RESOURCE_NOT_OWNED +Language=English +RESOURCE_NOT_OWNED +. + +MessageId=0xE4 +Severity=Success +Facility=System +SymbolicName=WORKER_INVALID +Language=English +WORKER_INVALID +. + MessageId=0xFA Severity=Success Facility=System @@ -1085,4 +1093,4 @@ Language=English ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY . -; EOF \ No newline at end of file +; EOF diff --git a/reactos/w32api/include/ddk/winddk.h b/reactos/w32api/include/ddk/winddk.h index 8f5f16f553f..6cc7c8d7f7d 100644 --- a/reactos/w32api/include/ddk/winddk.h +++ b/reactos/w32api/include/ddk/winddk.h @@ -6601,7 +6601,7 @@ ExIsResourceAcquiredLite( IN PERESOURCE Resource); NTOSAPI -USHORT +ULONG DDKAPI ExIsResourceAcquiredSharedLite( IN PERESOURCE Resource); @@ -6648,7 +6648,7 @@ ExRegisterCallback( IN PVOID CallbackContext); NTOSAPI -VOID +NTSTATUS DDKAPI ExReinitializeResourceLite( IN PERESOURCE Resource);