From 0a7df47900ff847f137836341d086dc5690f97d7 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 29 Jan 2019 21:35:44 -0600 Subject: [PATCH 02/13] ntoskrnl.exe: Implement ExAcquireResourceExclusiveLite(). Signed-off-by: Zebediah Figura --- dlls/ntoskrnl.exe/ntoskrnl.c | 9 ----- dlls/ntoskrnl.exe/sync.c | 73 ++++++++++++++++++++++++++++++++++++ include/ddk/wdm.h | 1 + 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 93ba89be..d6c35d1c 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -3038,15 +3038,6 @@ NTSTATUS WINAPI IoCsqInitialize(PIO_CSQ csq, PIO_CSQ_INSERT_IRP insert_irp, PIO_ return STATUS_SUCCESS; } -/*********************************************************************** - * ExAcquireResourceExclusiveLite (NTOSKRNL.EXE.@) - */ -BOOLEAN WINAPI ExAcquireResourceExclusiveLite( PERESOURCE resource, BOOLEAN wait ) -{ - FIXME( ":%p %u stub\n", resource, wait ); - return TRUE; -} - /*********************************************************************** * ExDeleteResourceLite (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index 56d46a86..205914a7 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -30,6 +30,7 @@ #include "ddk/wdm.h" #include "wine/debug.h" +#include "wine/heap.h" #include "ntoskrnl_private.h" @@ -664,6 +665,18 @@ void WINAPI ExReleaseFastMutexUnsafe( FAST_MUTEX *mutex ) KeSetEvent( &mutex->Event, IO_NO_INCREMENT, FALSE ); } +/* Use of the fields of an ERESOURCE structure seems to vary wildly between + * Windows versions. The below implementation uses them as follows: + * + * OwnerTable - contains a list of shared owners (TID and recursion count), + * including threads which do not currently own the resource + * (recursion count == 0) + * OwnerEntry.OwnerThread - the owner TID if exclusively owned + * OwnerEntry.TableSize - the number of entries in OwnerTable, including threads + * which do not currently own the resource + * ActiveEntries - total number of acquisitions (incl. recursive ones) + */ + /*********************************************************************** * ExInitializeResourceLite (NTOSKRNL.EXE.@) */ @@ -673,3 +686,63 @@ NTSTATUS WINAPI ExInitializeResourceLite( ERESOURCE *resource ) memset(resource, 0, sizeof(*resource)); return STATUS_SUCCESS; } + +/*********************************************************************** + * ExAcquireResourceExclusiveLite (NTOSKRNL.EXE.@) + */ +BOOLEAN WINAPI ExAcquireResourceExclusiveLite( ERESOURCE *resource, BOOLEAN wait ) +{ + KIRQL irql; + + TRACE("resource %p, wait %u.\n", resource, wait); + + KeAcquireSpinLock( &resource->SpinLock, &irql ); + + FIXME("%#lx/%d/%d/%d\n", resource->OwnerEntry.OwnerThread, resource->ActiveEntries, + resource->NumberOfExclusiveWaiters, resource->NumberOfSharedWaiters); + + if (resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)KeGetCurrentThread()) + { + resource->ActiveEntries++; + KeReleaseSpinLock( &resource->SpinLock, irql ); + return TRUE; + } + else if (!resource->ActiveEntries && !resource->NumberOfExclusiveWaiters && !resource->NumberOfSharedWaiters) + { + /* In order to avoid a race between waiting for the ExclusiveWaiters + * event and grabbing the lock, do not grab the resource if it is + * unclaimed but has waiters; instead queue ourselves. */ + resource->Flag |= ResourceOwnedExclusive; + resource->OwnerEntry.OwnerThread = (ERESOURCE_THREAD)KeGetCurrentThread(); + resource->ActiveEntries++; + KeReleaseSpinLock( &resource->SpinLock, irql ); + return TRUE; + } + else if (!wait) + { + KeReleaseSpinLock( &resource->SpinLock, irql ); + return FALSE; + } + + if (!resource->ExclusiveWaiters) + { + resource->ExclusiveWaiters = heap_alloc( sizeof(*resource->ExclusiveWaiters) ); + KeInitializeEvent( resource->ExclusiveWaiters, SynchronizationEvent, FALSE ); + } + resource->NumberOfExclusiveWaiters++; + + KeReleaseSpinLock( &resource->SpinLock, irql ); + + KeWaitForSingleObject( resource->ExclusiveWaiters, Executive, KernelMode, FALSE, NULL ); + + KeAcquireSpinLock( &resource->SpinLock, &irql ); + + resource->Flag |= ResourceOwnedExclusive; + resource->OwnerEntry.OwnerThread = (ERESOURCE_THREAD)KeGetCurrentThread(); + resource->ActiveEntries++; + resource->NumberOfExclusiveWaiters--; + + KeReleaseSpinLock( &resource->SpinLock, irql ); + + return TRUE; +} diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index f76444f1..a8cbdc2e 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1512,6 +1512,7 @@ static inline void IoSetCompletionRoutine(IRP *irp, PIO_COMPLETION_ROUTINE routi NTSTATUS WINAPI DbgQueryDebugFilterState(ULONG, ULONG); void WINAPI ExAcquireFastMutexUnsafe(PFAST_MUTEX); +BOOLEAN WINAPI ExAcquireResourceExclusiveLite(ERESOURCE*,BOOLEAN); PVOID WINAPI ExAllocatePool(POOL_TYPE,SIZE_T); PVOID WINAPI ExAllocatePoolWithQuota(POOL_TYPE,SIZE_T); PVOID WINAPI ExAllocatePoolWithTag(POOL_TYPE,SIZE_T,ULONG); -- 2.20.1