Signed-off-by: Paul Gofman pgofman@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 ); }