[PATCH 05/22] ntdll: Only lock loader_section when calling application callbacks().
Paul Gofman
pgofman at codeweavers.com
Fri Oct 1 13:20:50 CDT 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/ntdll/loader.c | 59 ++++++++++++++++++++++++++++++++++++++++-----
include/winternl.h | 2 +-
2 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 3081bb31434..4eb1eac09ed 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -160,6 +160,8 @@ 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;
+
static CRITICAL_SECTION dlldir_section;
static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
{
@@ -217,24 +219,58 @@ static inline BOOL contains_path( LPCWSTR name )
return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
}
+/*************************************************************************
+ * inc_recursion_count
+ *
+ * Increment thread local internal loader lock recursion count and return the old value.
+ */
+static ULONG inc_recursion_count(void)
+{
+ return NtCurrentTeb()->Spare2++;
+}
+
+/*************************************************************************
+ * dec_recursion_count
+ *
+ * Decrement thread local internal loader lock recursion count and return the new value.
+ */
+static ULONG dec_recursion_count(void)
+{
+ return --NtCurrentTeb()->Spare2;
+}
+
/*************************************************************************
* lock_loader_exclusive
*
- * Take exclusive loader lock.
+ * Take exclusive ownership of internal loader lock.
+ * Recursive locking is allowed.
*/
static void lock_loader_exclusive(void)
{
- RtlEnterCriticalSection( &loader_section );
+ ULONG recursion_count = inc_recursion_count();
+
+ TRACE( "recursion_count %u.\n", recursion_count );
+ if (!recursion_count && !RtlDllShutdownInProgress())
+ RtlAcquireSRWLockExclusive( &loader_srw_lock );
}
/*************************************************************************
* unlock_loader
*
- * Release loader lock.
+ * Release internal loader lock.
*/
static void unlock_loader(void)
{
- RtlLeaveCriticalSection( &loader_section );
+ ULONG recursion_count = dec_recursion_count();
+
+ TRACE( "recursion_count %u.\n", recursion_count );
+
+ if (RtlDllShutdownInProgress()) return;
+
+ assert( recursion_count != ~0u );
+
+ if (!recursion_count)
+ RtlReleaseSRWLockExclusive( &loader_srw_lock );
}
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
@@ -494,6 +530,7 @@ static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
data.Loaded.DllBase = module->DllBase;
data.Loaded.SizeOfImage = module->SizeOfImage;
+ RtlEnterCriticalSection( &loader_section );
RtlEnterCriticalSection( &ldr_notifications_section );
LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
{
@@ -506,6 +543,7 @@ static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
notify->callback, reason, &data, notify->context );
}
RtlLeaveCriticalSection( &ldr_notifications_section );
+ RtlLeaveCriticalSection( &loader_section );
}
/*************************************************************************
@@ -1355,6 +1393,8 @@ static void call_tls_callbacks( HMODULE module, UINT reason )
dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
if (!dir || !dir->AddressOfCallBacks) return;
+ RtlEnterCriticalSection( &loader_section );
+
for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
{
TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
@@ -1373,6 +1413,8 @@ static void call_tls_callbacks( HMODULE module, UINT reason )
TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
*callback, module, reason_names[reason] );
}
+
+ RtlLeaveCriticalSection( &loader_section );
}
/*************************************************************************
@@ -1405,6 +1447,8 @@ static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved
else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
reason_names[reason], lpReserved );
+ RtlEnterCriticalSection( &loader_section );
+
__TRY
{
retv = call_dll_entry_point( entry, module, reason, lpReserved );
@@ -1419,6 +1463,8 @@ static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved
}
__ENDTRY
+ RtlLeaveCriticalSection( &loader_section );
+
/* The state of the module list may have changed due to the call
to the dll. We cannot assume that this module has not been
deleted. */
@@ -1658,7 +1704,7 @@ NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback,
return STATUS_INVALID_PARAMETER;
lock_loader_exclusive();
-
+ RtlEnterCriticalSection( &loader_section );
mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
{
@@ -1666,7 +1712,7 @@ NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback,
callback( mod, context, &stop );
if (stop) break;
}
-
+ RtlLeaveCriticalSection( &loader_section );
unlock_loader();
return STATUS_SUCCESS;
}
@@ -3901,6 +3947,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 );
}
lock_loader_exclusive();
diff --git a/include/winternl.h b/include/winternl.h
index b6f93c116d8..521454396b4 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -466,7 +466,7 @@ typedef struct _TEB
PVOID Instrumentation[16]; /* f2c/16b8 */
PVOID WinSockData; /* f6c/1738 */
ULONG GdiBatchCount; /* f70/1740 */
- ULONG Spare2; /* f74/1744 */
+ ULONG Spare2; /* f74/1744 used for ntdll loader data in Wine */
ULONG GuaranteedStackBytes; /* f78/1748 */
PVOID ReservedForPerf; /* f7c/1750 */
PVOID ReservedForOle; /* f80/1758 */
--
2.31.1
More information about the wine-devel
mailing list