Moved the module loading/unloading code and the remaining needed
static variables to ntdll.
This commit is contained in:
parent
500a2f95f7
commit
9b79d698b2
|
@ -1,4 +1,7 @@
|
|||
/*
|
||||
* Loader functions
|
||||
*
|
||||
* Copyright 1995 Alexandre Julliard
|
||||
* Copyright 2002 Dmitry Timoshkov for Codeweavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
|
@ -35,6 +38,10 @@ WINE_DECLARE_DEBUG_CHANNEL(module);
|
|||
WINE_DECLARE_DEBUG_CHANNEL(module);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
|
||||
|
||||
WINE_MODREF *MODULE_modref_list = NULL;
|
||||
|
||||
static WINE_MODREF *exe_modref;
|
||||
static int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */
|
||||
static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
|
||||
|
||||
/* filter for page-fault exceptions */
|
||||
|
@ -45,7 +52,7 @@ static WINE_EXCEPTION_FILTER(page_fault)
|
|||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
|
||||
static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE32_LookupHMODULE
|
||||
|
@ -131,6 +138,192 @@ WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
|
|||
return wm;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_InitDLL
|
||||
*/
|
||||
static BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
|
||||
{
|
||||
static const char * const typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
|
||||
"THREAD_ATTACH", "THREAD_DETACH" };
|
||||
BOOL retv = TRUE;
|
||||
|
||||
/* Skip calls for modules loaded with special load flags */
|
||||
|
||||
if (wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) return TRUE;
|
||||
|
||||
TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved );
|
||||
|
||||
/* Call the initialization routine */
|
||||
retv = PE_InitDLL( wm->module, type, lpReserved );
|
||||
|
||||
/* The state of the module list may have changed due to the call
|
||||
to PE_InitDLL. We cannot assume that this module has not been
|
||||
deleted. */
|
||||
TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv );
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllProcessAttach
|
||||
*
|
||||
* Send the process attach notification to all DLLs the given module
|
||||
* depends on (recursively). This is somewhat complicated due to the fact that
|
||||
*
|
||||
* - we have to respect the module dependencies, i.e. modules implicitly
|
||||
* referenced by another module have to be initialized before the module
|
||||
* itself can be initialized
|
||||
*
|
||||
* - the initialization routine of a DLL can itself call LoadLibrary,
|
||||
* thereby introducing a whole new set of dependencies (even involving
|
||||
* the 'old' modules) at any time during the whole process
|
||||
*
|
||||
* (Note that this routine can be recursively entered not only directly
|
||||
* from itself, but also via LoadLibrary from one of the called initialization
|
||||
* routines.)
|
||||
*
|
||||
* Furthermore, we need to rearrange the main WINE_MODREF list to allow
|
||||
* the process *detach* notifications to be sent in the correct order.
|
||||
* This must not only take into account module dependencies, but also
|
||||
* 'hidden' dependencies created by modules calling LoadLibrary in their
|
||||
* attach notification routine.
|
||||
*
|
||||
* The strategy is rather simple: we move a WINE_MODREF to the head of the
|
||||
* list after the attach notification has returned. This implies that the
|
||||
* detach notifications are called in the reverse of the sequence the attach
|
||||
* notifications *returned*.
|
||||
*/
|
||||
BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
|
||||
{
|
||||
BOOL retv = TRUE;
|
||||
int i;
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
if (!wm)
|
||||
{
|
||||
wm = exe_modref;
|
||||
PE_InitTls();
|
||||
}
|
||||
assert( wm );
|
||||
|
||||
/* prevent infinite recursion in case of cyclical dependencies */
|
||||
if ( ( wm->flags & WINE_MODREF_MARKER )
|
||||
|| ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) )
|
||||
goto done;
|
||||
|
||||
TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
|
||||
|
||||
/* Tag current MODREF to prevent recursive loop */
|
||||
wm->flags |= WINE_MODREF_MARKER;
|
||||
|
||||
/* Recursively attach all DLLs this one depends on */
|
||||
for ( i = 0; retv && i < wm->nDeps; i++ )
|
||||
if ( wm->deps[i] )
|
||||
retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
|
||||
|
||||
/* Call DLL entry point */
|
||||
if ( retv )
|
||||
{
|
||||
retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
|
||||
if ( retv )
|
||||
wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
|
||||
}
|
||||
|
||||
/* Re-insert MODREF at head of list */
|
||||
if ( retv && wm->prev )
|
||||
{
|
||||
wm->prev->next = wm->next;
|
||||
if ( wm->next ) wm->next->prev = wm->prev;
|
||||
|
||||
wm->prev = NULL;
|
||||
wm->next = MODULE_modref_list;
|
||||
MODULE_modref_list = wm->next->prev = wm;
|
||||
}
|
||||
|
||||
/* Remove recursion flag */
|
||||
wm->flags &= ~WINE_MODREF_MARKER;
|
||||
|
||||
TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
|
||||
|
||||
done:
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
return retv;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllProcessDetach
|
||||
*
|
||||
* Send DLL process detach notifications. See the comment about calling
|
||||
* sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
|
||||
* is set, only DLLs with zero refcount are notified.
|
||||
*/
|
||||
void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
if (bForceDetach) process_detaching = 1;
|
||||
do
|
||||
{
|
||||
for ( wm = MODULE_modref_list; wm; wm = wm->next )
|
||||
{
|
||||
/* Check whether to detach this DLL */
|
||||
if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
|
||||
continue;
|
||||
if ( wm->refCount > 0 && !bForceDetach )
|
||||
continue;
|
||||
|
||||
/* Call detach notification */
|
||||
wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED;
|
||||
MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
|
||||
|
||||
/* Restart at head of WINE_MODREF list, as entries might have
|
||||
been added and/or removed while performing the call ... */
|
||||
break;
|
||||
}
|
||||
} while ( wm );
|
||||
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllThreadAttach
|
||||
*
|
||||
* Send DLL thread attach notifications. These are sent in the
|
||||
* reverse sequence of process detach notification.
|
||||
*
|
||||
*/
|
||||
void MODULE_DllThreadAttach( LPVOID lpReserved )
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
|
||||
/* don't do any attach calls if process is exiting */
|
||||
if (process_detaching) return;
|
||||
/* FIXME: there is still a race here */
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
PE_InitTls();
|
||||
|
||||
for ( wm = MODULE_modref_list; wm; wm = wm->next )
|
||||
if ( !wm->next )
|
||||
break;
|
||||
|
||||
for ( ; wm; wm = wm->prev )
|
||||
{
|
||||
if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
|
||||
continue;
|
||||
if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
|
||||
continue;
|
||||
|
||||
MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
|
||||
}
|
||||
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* LdrDisableThreadCalloutsForDll (NTDLL.@)
|
||||
*
|
||||
|
|
|
@ -203,13 +203,6 @@ extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
|
|||
extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name );
|
||||
extern SEGPTR WINAPI HasGPHandler16( SEGPTR address );
|
||||
extern void MODULE_WalkModref( DWORD id );
|
||||
/* the following parts of module.c are temporary exported during move of code
|
||||
* from loader/module.c to dlls/ntdll/loader.c
|
||||
*/
|
||||
extern WINE_MODREF *exe_modref;
|
||||
extern CRITICAL_SECTION loader_section;
|
||||
extern int process_detaching;
|
||||
extern BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved );
|
||||
|
||||
/* loader/ne/module.c */
|
||||
extern NE_MODULE *NE_GetPtr( HMODULE16 hModule );
|
||||
|
|
193
loader/module.c
193
loader/module.c
|
@ -45,11 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(module);
|
|||
WINE_DECLARE_DEBUG_CHANNEL(win32);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
|
||||
|
||||
WINE_MODREF *MODULE_modref_list = NULL;
|
||||
|
||||
WINE_MODREF *exe_modref;
|
||||
int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */
|
||||
|
||||
inline static HMODULE get_exe_module(void)
|
||||
{
|
||||
HMODULE mod;
|
||||
|
@ -77,194 +72,6 @@ static DWORD wait_input_idle( HANDLE process, DWORD timeout )
|
|||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_InitDLL
|
||||
*/
|
||||
BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
|
||||
{
|
||||
BOOL retv = TRUE;
|
||||
|
||||
static LPCSTR typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
|
||||
"THREAD_ATTACH", "THREAD_DETACH" };
|
||||
assert( wm );
|
||||
|
||||
/* Skip calls for modules loaded with special load flags */
|
||||
|
||||
if (wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) return TRUE;
|
||||
|
||||
TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved );
|
||||
|
||||
/* Call the initialization routine */
|
||||
retv = PE_InitDLL( wm->module, type, lpReserved );
|
||||
|
||||
/* The state of the module list may have changed due to the call
|
||||
to PE_InitDLL. We cannot assume that this module has not been
|
||||
deleted. */
|
||||
TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv );
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllProcessAttach
|
||||
*
|
||||
* Send the process attach notification to all DLLs the given module
|
||||
* depends on (recursively). This is somewhat complicated due to the fact that
|
||||
*
|
||||
* - we have to respect the module dependencies, i.e. modules implicitly
|
||||
* referenced by another module have to be initialized before the module
|
||||
* itself can be initialized
|
||||
*
|
||||
* - the initialization routine of a DLL can itself call LoadLibrary,
|
||||
* thereby introducing a whole new set of dependencies (even involving
|
||||
* the 'old' modules) at any time during the whole process
|
||||
*
|
||||
* (Note that this routine can be recursively entered not only directly
|
||||
* from itself, but also via LoadLibrary from one of the called initialization
|
||||
* routines.)
|
||||
*
|
||||
* Furthermore, we need to rearrange the main WINE_MODREF list to allow
|
||||
* the process *detach* notifications to be sent in the correct order.
|
||||
* This must not only take into account module dependencies, but also
|
||||
* 'hidden' dependencies created by modules calling LoadLibrary in their
|
||||
* attach notification routine.
|
||||
*
|
||||
* The strategy is rather simple: we move a WINE_MODREF to the head of the
|
||||
* list after the attach notification has returned. This implies that the
|
||||
* detach notifications are called in the reverse of the sequence the attach
|
||||
* notifications *returned*.
|
||||
*/
|
||||
BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
|
||||
{
|
||||
BOOL retv = TRUE;
|
||||
int i;
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
if (!wm)
|
||||
{
|
||||
wm = exe_modref;
|
||||
PE_InitTls();
|
||||
}
|
||||
assert( wm );
|
||||
|
||||
/* prevent infinite recursion in case of cyclical dependencies */
|
||||
if ( ( wm->flags & WINE_MODREF_MARKER )
|
||||
|| ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) )
|
||||
goto done;
|
||||
|
||||
TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
|
||||
|
||||
/* Tag current MODREF to prevent recursive loop */
|
||||
wm->flags |= WINE_MODREF_MARKER;
|
||||
|
||||
/* Recursively attach all DLLs this one depends on */
|
||||
for ( i = 0; retv && i < wm->nDeps; i++ )
|
||||
if ( wm->deps[i] )
|
||||
retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
|
||||
|
||||
/* Call DLL entry point */
|
||||
if ( retv )
|
||||
{
|
||||
retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
|
||||
if ( retv )
|
||||
wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
|
||||
}
|
||||
|
||||
/* Re-insert MODREF at head of list */
|
||||
if ( retv && wm->prev )
|
||||
{
|
||||
wm->prev->next = wm->next;
|
||||
if ( wm->next ) wm->next->prev = wm->prev;
|
||||
|
||||
wm->prev = NULL;
|
||||
wm->next = MODULE_modref_list;
|
||||
MODULE_modref_list = wm->next->prev = wm;
|
||||
}
|
||||
|
||||
/* Remove recursion flag */
|
||||
wm->flags &= ~WINE_MODREF_MARKER;
|
||||
|
||||
TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
|
||||
|
||||
done:
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
return retv;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllProcessDetach
|
||||
*
|
||||
* Send DLL process detach notifications. See the comment about calling
|
||||
* sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
|
||||
* is set, only DLLs with zero refcount are notified.
|
||||
*/
|
||||
void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
if (bForceDetach) process_detaching = 1;
|
||||
do
|
||||
{
|
||||
for ( wm = MODULE_modref_list; wm; wm = wm->next )
|
||||
{
|
||||
/* Check whether to detach this DLL */
|
||||
if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
|
||||
continue;
|
||||
if ( wm->refCount > 0 && !bForceDetach )
|
||||
continue;
|
||||
|
||||
/* Call detach notification */
|
||||
wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED;
|
||||
MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
|
||||
|
||||
/* Restart at head of WINE_MODREF list, as entries might have
|
||||
been added and/or removed while performing the call ... */
|
||||
break;
|
||||
}
|
||||
} while ( wm );
|
||||
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MODULE_DllThreadAttach
|
||||
*
|
||||
* Send DLL thread attach notifications. These are sent in the
|
||||
* reverse sequence of process detach notification.
|
||||
*
|
||||
*/
|
||||
void MODULE_DllThreadAttach( LPVOID lpReserved )
|
||||
{
|
||||
WINE_MODREF *wm;
|
||||
|
||||
/* don't do any attach calls if process is exiting */
|
||||
if (process_detaching) return;
|
||||
/* FIXME: there is still a race here */
|
||||
|
||||
RtlEnterCriticalSection( &loader_section );
|
||||
|
||||
PE_InitTls();
|
||||
|
||||
for ( wm = MODULE_modref_list; wm; wm = wm->next )
|
||||
if ( !wm->next )
|
||||
break;
|
||||
|
||||
for ( ; wm; wm = wm->prev )
|
||||
{
|
||||
if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
|
||||
continue;
|
||||
if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
|
||||
continue;
|
||||
|
||||
MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
|
||||
}
|
||||
|
||||
RtlLeaveCriticalSection( &loader_section );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DisableThreadLibraryCalls (KERNEL32.@)
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue