[PATCH v2 06/22] ntdll: Use shared loader locking in LdrQueryProcessModuleInformation().

Paul Gofman pgofman at codeweavers.com
Tue Oct 5 17:49:12 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
    - remove redundant 'volatile' qualifier from locked_exclusive.

 dlls/kernel32/tests/loader.c | 46 ++++++++++++++++++++++++++++++++++++
 dlls/ntdll/loader.c          | 37 ++++++++++++++++++++++++++---
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 045338c1289..e97c114c5e9 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -4049,6 +4049,16 @@ static volatile LONG test_loader_lock_timeout_count;
 
 #define BLOCKING_TESTS_ENABLED 0
 
+static void CALLBACK test_loader_lock_module_enum_locking_callback(LDR_DATA_TABLE_ENTRY *mod,
+        void *context, BOOLEAN *stop)
+{
+    SetEvent(lock_ready_event);
+    if (WaitForSingleObject(next_test_event, 3000) == WAIT_TIMEOUT)
+        ++test_loader_lock_timeout_count;
+
+    *stop = TRUE;
+}
+
 static DWORD WINAPI test_loader_lock_thread(void *param)
 {
     ULONG_PTR magic;
@@ -4085,6 +4095,20 @@ static DWORD WINAPI test_loader_lock_thread(void *param)
     SetEvent(lock_ready_event);
     WaitForSingleObject(next_test_event, INFINITE);
 
+    /* 2. Test with the thread blocked in LdrEnumerateLoadedModules callback. */
+    do
+    {
+        pLdrEnumerateLoadedModules(NULL, test_loader_lock_module_enum_locking_callback, NULL);
+        if (test_loader_lock_timeout_count)
+        {
+            WaitForSingleObject(next_test_event, INFINITE);
+            test_loader_lock_timeout_count = 0;
+        }
+    } while (test_loader_lock_repeat_lock);
+
+    SetEvent(lock_ready_event);
+    WaitForSingleObject(next_test_event, INFINITE);
+
     SetEvent(lock_ready_event);
     return 0;
 }
@@ -4131,6 +4155,7 @@ static void test_loader_lock(void)
     static const WCHAR not_loaded_dll_name[] = L"authz.dll";
     static const WCHAR preloaded_dll_name[] = L"winmm.dll";
     HMODULE hmodule_preloaded, hmodule;
+    ULONG_PTR magic;
     NTSTATUS status;
     HANDLE thread;
     void *cookie;
@@ -4200,6 +4225,27 @@ static void test_loader_lock(void)
     LdrUnregisterDllNotification( cookie );
     check_timeout(FALSE);
 
+    /* 2. Test with the thread blocked in LdrEnumerateLoadedModules callback. */
+    trace("Test 2.\n");
+    test_loader_lock_next_test();
+
+    status = LdrRegisterDllNotification(0, test_loader_lock_ldr_notify, NULL, &cookie);
+    ok(!status, "Got unexpected status %#x.\n", status);
+    check_timeout(FALSE);
+
+    if (BLOCKING_TESTS_ENABLED)
+    {
+        status = pLdrLockLoaderLock(0, NULL, &magic);
+        ok(!status, "Got unexpected status %#x.\n", status);
+        status = pLdrUnlockLoaderLock(0, magic);
+        ok(!status, "Got unexpected status %#x.\n", status);
+
+        check_timeout(TRUE);
+    }
+
+    LdrUnregisterDllNotification( cookie );
+    check_timeout(FALSE);
+
     test_loader_lock_next_test();
 
 done:
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index d0d4e5448ed..092805cc945 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -161,6 +161,7 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 static RTL_SRWLOCK loader_srw_lock = RTL_SRWLOCK_INIT;
+static BOOL locked_exclusive;
 
 static CRITICAL_SECTION dlldir_section;
 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
@@ -250,8 +251,32 @@ static void lock_loader_exclusive(void)
     ULONG recursion_count = inc_recursion_count();
 
     TRACE( "recursion_count %u.\n", recursion_count );
+    if (!recursion_count)
+    {
+        if (!RtlDllShutdownInProgress())
+            RtlAcquireSRWLockExclusive( &loader_srw_lock );
+        locked_exclusive = TRUE;
+    }
+    else
+    {
+        assert( locked_exclusive );
+    }
+}
+
+/*************************************************************************
+ *		lock_loader_shared
+ *
+ * Take shared ownership of internal loader lock.
+ * If the thread already has exclusive lock it will stay exclusive.
+ */
+static void lock_loader_shared(void)
+{
+    ULONG recursion_count = inc_recursion_count();
+
+    TRACE("recursion_count %u, locked_exclusive %d.\n", recursion_count, locked_exclusive);
+
     if (!recursion_count && !RtlDllShutdownInProgress())
-        RtlAcquireSRWLockExclusive( &loader_srw_lock );
+        RtlAcquireSRWLockShared( &loader_srw_lock );
 }
 
 /*************************************************************************
@@ -269,8 +294,14 @@ static void unlock_loader(void)
 
     assert( recursion_count != ~0u );
 
-    if (!recursion_count)
+    if (recursion_count) return;
+
+    if (locked_exclusive)
+    {
+        locked_exclusive = FALSE;
         RtlReleaseSRWLockExclusive( &loader_srw_lock );
+    }
+    else RtlReleaseSRWLockShared( &loader_srw_lock );
 }
 
 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
@@ -3283,7 +3314,7 @@ NTSTATUS WINAPI LdrQueryProcessModuleInformation(RTL_PROCESS_MODULES *smi,
 
     smi->ModulesCount = 0;
 
-    lock_loader_exclusive();
+    lock_loader_shared();
     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
     {
-- 
2.31.1




More information about the wine-devel mailing list