[PATCH 13/22] ntdll: Use shared loader locking in LdrUnloadDll() when possible.

Paul Gofman pgofman at codeweavers.com
Fri Oct 1 13:20:58 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ntdll/loader.c | 48 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index a8222ec30df..766a3108425 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -172,6 +172,7 @@ static RTL_CONDITION_VARIABLE exclusive_lock_released_cv;
 
 static unsigned int lock_exclusive_recursion_count[MAX_DOWNGRADE_RECURSION_COUNT];
 static unsigned int lock_exclusive_recursion_stack;
+static RTL_SRWLOCK loader_module_info_lock;
 
 static CRITICAL_SECTION dlldir_section;
 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
@@ -472,6 +473,29 @@ static void lock_loader_restore_exclusive(void)
     locked_exclusive = TRUE;
 }
 
+/*************************************************************************
+ *		lock_module_info
+ *
+ * Lock module info data for performing modifications not resulting in module
+ * unload with only shared loader internal lock held.
+ * The lock is supposed to be very short lived. Only calls to ntdll loader
+ * functions which do not lock anything themselves are allowed with this lock held.
+ */
+static void lock_module_info(void)
+{
+    RtlAcquireSRWLockExclusive( &loader_module_info_lock );
+}
+
+/*************************************************************************
+ *		unlock_module_info
+ *
+ * Unlock module info data.
+ */
+static void unlock_module_info(void)
+{
+    RtlReleaseSRWLockExclusive( &loader_module_info_lock );
+}
+
 /*************************************************************************
  *		get_cached_modref
  *
@@ -3850,7 +3874,7 @@ static void free_modref( WINE_MODREF *wm )
  * Remove all unused modrefs and call the internal unloading routines
  * for the library type.
  *
- * The loader must be locked while calling this function.
+ * The loader must be exclusively locked while calling this function.
  */
 static void MODULE_FlushModrefs(void)
 {
@@ -3881,7 +3905,7 @@ static void MODULE_FlushModrefs(void)
 /***********************************************************************
  *           MODULE_DecRefCount
  *
- * The loader must be locked while calling this function.
+ * The loader must be exclusively locked while calling this function.
  */
 static void MODULE_DecRefCount( WINE_MODREF *wm )
 {
@@ -3913,17 +3937,34 @@ static void MODULE_DecRefCount( WINE_MODREF *wm )
 /******************************************************************
  *		LdrUnloadDll (NTDLL.@)
  *
- *
+ * The loader must be unlocked or exclusively locked while calling this function.
  */
 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
 {
     WINE_MODREF *wm;
     NTSTATUS retv = STATUS_SUCCESS;
+    BOOL need_exclusive = FALSE;
 
     if (process_detaching) return retv;
 
     TRACE("(%p)\n", hModule);
 
+    lock_loader_shared();
+    if ((wm = get_modref( hModule )))
+    {
+        lock_module_info();
+        if (wm->ldr.LoadCount && wm->ldr.LoadCount != 1)
+        {
+            if (wm->ldr.LoadCount != -1) --wm->ldr.LoadCount;
+        }
+        else if (wm->ldr.LoadCount) need_exclusive = TRUE;
+        /* If the module is already being unloaded LdrUnloadDll() succeeds and doesn't wait. */
+        unlock_module_info();
+    }
+    else retv = STATUS_DLL_NOT_FOUND;
+    unlock_loader();
+    if (!need_exclusive) return retv;
+
     lock_loader_exclusive();
 
     free_lib_count++;
@@ -4170,6 +4211,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
         TRACE( "Initializing loader locks.\n" );
         RtlInitializeSRWLock( &ldr_data_srw_lock );
         RtlInitializeSRWLock( &loader_srw_lock );
+        RtlInitializeSRWLock( &loader_module_info_lock );
         RtlInitializeConditionVariable( &exclusive_lock_released_cv );
     }
 
-- 
2.31.1




More information about the wine-devel mailing list