From e469a583cac1623ac19debeafcadf8742d3b9cbb Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Sat, 27 Mar 1999 16:45:57 +0000 Subject: [PATCH] Fixed sequence of DLL_PROCESS_DETACH notification calls. Moved PE_MODREF flags to WINE_MODREF level. Better handling of LoadLibraryEx flags. PE_InitTls() changed to work only on the current thread. --- include/module.h | 14 +++- include/pe_image.h | 9 +-- include/thread.h | 1 - loader/module.c | 182 +++++++++++++++++++++++++++++++++++--------- loader/pe_image.c | 77 +++++++++---------- scheduler/process.c | 6 +- scheduler/thread.c | 28 +++---- 7 files changed, 208 insertions(+), 109 deletions(-) diff --git a/include/module.h b/include/module.h index 9a81bd7f591..4ae9d7b612c 100644 --- a/include/module.h +++ b/include/module.h @@ -111,6 +111,7 @@ typedef enum { MODULE32_PE=1, MODULE32_ELF /* ,... */ } MODULE32_TYPE; typedef struct _wine_modref { struct _wine_modref *next; + struct _wine_modref *prev; MODULE32_TYPE type; union { PE_MODREF pe; @@ -121,13 +122,24 @@ typedef struct _wine_modref int nDeps; struct _wine_modref **deps; - int initDone; + + int flags; + int refCount; char *modname; char *shortname; char *longname; } WINE_MODREF; +#define WINE_MODREF_INTERNAL 0x00000001 +#define WINE_MODREF_NO_DLL_CALLS 0x00000002 +#define WINE_MODREF_PROCESS_ATTACHED 0x00000004 +#define WINE_MODREF_PROCESS_DETACHED 0x00000008 +#define WINE_MODREF_LOAD_AS_DATAFILE 0x00000010 +#define WINE_MODREF_DONT_RESOLVE_REFS 0x00000020 +#define WINE_MODREF_MARKER 0x80000000 + + /* Resource types */ typedef struct resource_typeinfo_s NE_TYPEINFO; diff --git a/include/pe_image.h b/include/pe_image.h index 7ba71f5f4a0..9ce289fe003 100644 --- a/include/pe_image.h +++ b/include/pe_image.h @@ -11,12 +11,6 @@ typedef struct { PIMAGE_IMPORT_DESCRIPTOR pe_import; PIMAGE_EXPORT_DIRECTORY pe_export; PIMAGE_RESOURCE_DIRECTORY pe_resource; - int flags; -#define PE_MODREF_PROCESS_ATTACHED 0x00000001 -#define PE_MODREF_NO_DLL_CALLS 0x00000002 -#define PE_MODREF_RELOCS_DONE 0x00000004 -#define PE_MODREF_TLS_ALLOCED 0x00000008 -#define PE_MODREF_INTERNAL 0x00000010 int tlsindex; } PE_MODREF; @@ -41,8 +35,7 @@ extern BOOL PE_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmd_line, LPCST BOOL inherit, LPSTARTUPINFOA startup, LPPROCESS_INFORMATION info ); -struct _THDB; /* forward definition */ -extern void PE_InitTls(struct _THDB*); +extern void PE_InitTls(void); extern void PE_InitDLL(struct _wine_modref *wm, DWORD type, LPVOID lpReserved); extern PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA(PIMAGE_RESOURCE_DIRECTORY,LPCSTR,DWORD,BOOL); diff --git a/include/thread.h b/include/thread.h index 7bb63a08b24..4c275cff2e4 100644 --- a/include/thread.h +++ b/include/thread.h @@ -123,7 +123,6 @@ extern THDB *THREAD_Create( struct _PDB *pdb, DWORD flags, extern THDB *THREAD_Current(void); extern BOOL THREAD_IsWin16( THDB *thdb ); extern THDB *THREAD_IdToTHDB( DWORD id ); -extern DWORD THREAD_TlsAlloc( THDB *thread ); /* scheduler/sysdeps.c */ extern int SYSDEPS_SpawnThread( THDB *thread ); diff --git a/loader/module.c b/loader/module.c index 86cc727d487..9d1008eb425 100644 --- a/loader/module.c +++ b/loader/module.c @@ -73,37 +73,84 @@ WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod ) static void MODULE_DoInitializeDLLs( WINE_MODREF *wm, DWORD type, LPVOID lpReserved ) { - int i; + WINE_MODREF *xwm; + int i, skip = FALSE; - assert( wm && !wm->initDone ); - TRACE( module, "(%08x,%ld,%p) - START\n", - wm->module, type, lpReserved ); + assert( wm && !(wm->flags & WINE_MODREF_MARKER) ); + TRACE( module, "(%s,%08x,%ld,%p) - START\n", + wm->modname, wm->module, type, lpReserved ); /* Tag current MODREF to prevent recursive loop */ - wm->initDone = TRUE; + wm->flags |= WINE_MODREF_MARKER; - /* Recursively initialize all child DLLs */ - for ( i = 0; i < wm->nDeps; i++ ) - if ( wm->deps[i] && !wm->deps[i]->initDone ) - MODULE_DoInitializeDLLs( wm->deps[i], type, lpReserved ); - - /* Now we can call the initialization routine */ - switch ( wm->type ) + switch ( type ) { - case MODULE32_PE: - PE_InitDLL( wm, type, lpReserved ); + default: + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + /* Recursively attach all DLLs this one depends on */ + for ( i = 0; i < wm->nDeps; i++ ) + if ( wm->deps[i] && !(wm->deps[i]->flags & WINE_MODREF_MARKER) ) + MODULE_DoInitializeDLLs( wm->deps[i], type, lpReserved ); break; - case MODULE32_ELF: - /* no need to do that, dlopen() already does */ - break; - default: - ERR(module, "wine_modref type %d not handled.\n", wm->type); + case DLL_PROCESS_DETACH: + case DLL_THREAD_DETACH: + /* Recursively detach all DLLs that depend on this one */ + for ( xwm = PROCESS_Current()->modref_list; xwm; xwm = xwm->next ) + if ( !(xwm->flags & WINE_MODREF_MARKER) ) + for ( i = 0; i < xwm->nDeps; i++ ) + if ( xwm->deps[i] == wm ) + { + MODULE_DoInitializeDLLs( xwm, type, lpReserved ); + break; + } break; } - TRACE( module, "(%08x,%ld,%p) - END\n", - wm->module, type, lpReserved ); + /* Evaluate module flags */ + + if ( ( wm->flags & WINE_MODREF_NO_DLL_CALLS ) + || ( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) + || ( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) ) + skip = TRUE; + + if ( type == DLL_PROCESS_ATTACH ) + if ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) + skip = TRUE; + else + wm->flags |= WINE_MODREF_PROCESS_ATTACHED; + + if ( type == DLL_PROCESS_DETACH ) + if ( wm->flags & WINE_MODREF_PROCESS_DETACHED ) + skip = TRUE; + else + wm->flags |= WINE_MODREF_PROCESS_DETACHED; + + if ( !skip ) + { + /* Now we can call the initialization routine */ + TRACE( module, "(%s,%08x,%ld,%p) - CALL\n", + wm->modname, wm->module, type, lpReserved ); + + switch ( wm->type ) + { + case MODULE32_PE: + PE_InitDLL( wm, type, lpReserved ); + break; + + case MODULE32_ELF: + /* no need to do that, dlopen() already does */ + break; + + default: + ERR(module, "wine_modref type %d not handled.\n", wm->type); + break; + } + } + + TRACE( module, "(%s,%08x,%ld,%p) - END\n", + wm->modname, wm->module, type, lpReserved ); } void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved ) @@ -119,7 +166,7 @@ void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved ) /* First, check whether initialization is currently in progress */ for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next ) - if ( wm->initDone ) + if ( wm->flags & WINE_MODREF_MARKER ) { inProgress = TRUE; break; @@ -135,7 +182,7 @@ void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved ) if ( root ) { wm = MODULE32_LookupHMODULE( root ); - if ( wm && !wm->initDone ) + if ( wm && !(wm->flags & WINE_MODREF_MARKER) ) MODULE_DoInitializeDLLs( wm, type, lpReserved ); } else @@ -147,9 +194,26 @@ void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved ) if ( !root ) { /* If called for main EXE, initialize all DLLs */ - for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next ) - if ( !wm->initDone ) - MODULE_DoInitializeDLLs( wm, type, lpReserved ); + switch ( type ) + { + default: /* Hmmm. */ + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next ) + if ( !wm->next ) + break; + for ( ; wm; wm = wm->prev ) + if ( !(wm->flags & WINE_MODREF_MARKER) ) + MODULE_DoInitializeDLLs( wm, type, lpReserved ); + break; + + case DLL_PROCESS_DETACH: + case DLL_THREAD_DETACH: + for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next ) + if ( !(wm->flags & WINE_MODREF_MARKER) ) + MODULE_DoInitializeDLLs( wm, type, lpReserved ); + break; + } } else { @@ -160,7 +224,7 @@ void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved ) /* We're finished, so we reset all recursion flags */ for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next ) - wm->initDone = FALSE; + wm->flags &= ~WINE_MODREF_MARKER; } TRACE( module, "(%08x,%ld,%p) - END\n", root, type, lpReserved ); @@ -169,6 +233,49 @@ void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved ) LeaveCriticalSection( &PROCESS_Current()->crit_section ); } +/**************************************************************************** + * DisableThreadLibraryCalls (KERNEL32.74) + * + * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set. + */ +BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule ) +{ + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + if ( !wm ) return FALSE; + + wm->flags |= WINE_MODREF_NO_DLL_CALLS; + return TRUE; +} + +/**************************************************************************** + * MODULE_IncRefCount + */ +static void MODULE_IncRefCount( HMODULE hModule ) +{ + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + if ( !wm ) return; + + EnterCriticalSection( &PROCESS_Current()->crit_section ); + wm->refCount++; + LeaveCriticalSection( &PROCESS_Current()->crit_section ); +} + +/**************************************************************************** + * MODULE_DecRefCount + */ +static int MODULE_DecRefCount( HMODULE hModule ) +{ + int retv; + WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule ); + if ( !wm ) return 0; + + EnterCriticalSection( &PROCESS_Current()->crit_section ); + if ( ( retv = wm->refCount ) > 0 ) wm->refCount--; + LeaveCriticalSection( &PROCESS_Current()->crit_section ); + + return retv; +} + /*********************************************************************** * MODULE_CreateDummyModule @@ -1103,15 +1210,14 @@ HMODULE WINAPI LoadLibraryExA(LPCSTR libname,HFILE hfile,DWORD flags) HMODULE hmod; hmod = MODULE_LoadLibraryExA( libname, hfile, flags ); - /* at least call not the dllmain...*/ - if ( DONT_RESOLVE_DLL_REFERENCES==flags || LOAD_LIBRARY_AS_DATAFILE==flags ) - { FIXME(module,"flag not properly supported %lx\n", flags); - return hmod; - } + if ( hmod >= 32 ) + { + /* Increment RefCount */ + MODULE_IncRefCount( hmod ); - /* initialize DLL just loaded */ - if ( hmod >= 32 ) - MODULE_InitializeDLLs( hmod, DLL_PROCESS_ATTACH, (LPVOID)-1 ); + /* Initialize DLL just loaded */ + MODULE_InitializeDLLs( hmod, DLL_PROCESS_ATTACH, NULL ); + } return hmod; } @@ -1159,8 +1265,10 @@ HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HFILE hfile,DWORD flags) */ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) { - FIXME(module,"(0x%08x): stub\n", hLibModule); - return TRUE; /* FIXME */ + if ( MODULE_DecRefCount( hLibModule ) != 1 ) return TRUE; + + FIXME(module,"(0x%08x): should unload now\n", hLibModule); + return TRUE; /* FIXME */ } /*********************************************************************** diff --git a/loader/pe_image.c b/loader/pe_image.c index b6e046648f0..4982dc4877b 100644 --- a/loader/pe_image.c +++ b/loader/pe_image.c @@ -740,11 +740,18 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, HEAP_ZERO_MEMORY, sizeof(*wm) ); wm->module = hModule; + if ( builtin ) + wm->flags |= WINE_MODREF_INTERNAL; + if ( flags & DONT_RESOLVE_DLL_REFERENCES ) + wm->flags |= WINE_MODREF_DONT_RESOLVE_REFS; + if ( flags & LOAD_LIBRARY_AS_DATAFILE ) + wm->flags |= WINE_MODREF_LOAD_AS_DATAFILE; + wm->type = MODULE32_PE; - wm->binfmt.pe.flags = builtin? PE_MODREF_INTERNAL : 0; wm->binfmt.pe.pe_export = pe_export; wm->binfmt.pe.pe_import = pe_import; wm->binfmt.pe.pe_resource = pe_resource; + wm->binfmt.pe.tlsindex = -1; if ( pe_export ) modname = (char *)RVA( pe_export->Name ); @@ -753,8 +760,7 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, /* try to find out the name from the OFSTRUCT */ char *s; modname = ofs->szPathName; - while ((s=strchr(modname,'\\'))) - modname = s+1; + if ((s=strrchr(modname,'\\'))) modname = s+1; } wm->modname = HEAP_strdupA( GetProcessHeap(), 0, modname ); @@ -766,8 +772,11 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, /* Link MODREF into process list */ + EnterCriticalSection( &PROCESS_Current()->crit_section ); + wm->next = PROCESS_Current()->modref_list; PROCESS_Current()->modref_list = wm; + if ( wm->next ) wm->next->prev = wm; if ( !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ) { @@ -776,6 +785,9 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, PROCESS_Current()->exe_modref = wm; } + LeaveCriticalSection( &PROCESS_Current()->crit_section ); + + /* Dump Exports */ if ( pe_export ) @@ -783,16 +795,23 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, /* Fixup Imports */ - if ( pe_import && fixup_imports( wm ) ) + if ( pe_import && fixup_imports( wm ) + && !( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) + && !( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) ) { /* remove entry from modref chain */ - WINE_MODREF **xwm; - for ( xwm = &PROCESS_Current()->modref_list; *xwm; xwm = &(*xwm)->next ) - if ( *xwm == wm ) - { - *xwm = wm->next; - break; - } + EnterCriticalSection( &PROCESS_Current()->crit_section ); + + if ( !wm->prev ) + PROCESS_Current()->modref_list = wm->next; + else + wm->prev->next = wm->next; + + if ( wm->next ) wm->next->prev = wm->prev; + wm->next = wm->prev = NULL; + + LeaveCriticalSection( &PROCESS_Current()->crit_section ); + /* FIXME: there are several more dangling references * left. Including dlls loaded by this dll before the * failed one. Unrolling is rather difficult with the @@ -943,15 +962,6 @@ void PE_InitDLL(WINE_MODREF *wm, DWORD type, LPVOID lpReserved) { if (wm->type!=MODULE32_PE) return; - if (wm->binfmt.pe.flags & PE_MODREF_NO_DLL_CALLS) - return; - if (type==DLL_PROCESS_ATTACH) - { - if (wm->binfmt.pe.flags & PE_MODREF_PROCESS_ATTACHED) - return; - - wm->binfmt.pe.flags |= PE_MODREF_PROCESS_ATTACHED; - } /* DLL_ATTACH_PROCESS: * lpreserved is NULL for dynamic loads, not-NULL for static loads @@ -979,7 +989,7 @@ void PE_InitDLL(WINE_MODREF *wm, DWORD type, LPVOID lpReserved) * Pointers in those structs are not RVAs but real pointers which have been * relocated by do_relocations() already. */ -void PE_InitTls(THDB *thdb) +void PE_InitTls( void ) { WINE_MODREF *wm; PE_MODREF *pem; @@ -987,10 +997,9 @@ void PE_InitTls(THDB *thdb) DWORD size,datasize; LPVOID mem; PIMAGE_TLS_DIRECTORY pdir; - PDB *pdb = thdb->process; int delta; - for (wm = pdb->modref_list;wm;wm=wm->next) { + for (wm = PROCESS_Current()->modref_list;wm;wm=wm->next) { if (wm->type!=MODULE32_PE) continue; pem = &(wm->binfmt.pe); @@ -1002,11 +1011,10 @@ void PE_InitTls(THDB *thdb) DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress); - if (!(pem->flags & PE_MODREF_TLS_ALLOCED)) { - pem->tlsindex = THREAD_TlsAlloc(thdb); + if ( pem->tlsindex == -1 ) { + pem->tlsindex = TlsAlloc(); *pdir->AddressOfIndex=pem->tlsindex; } - pem->flags |= PE_MODREF_TLS_ALLOCED; datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData; size = datasize + pdir->SizeOfZeroFill; mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE); @@ -1018,21 +1026,8 @@ void PE_InitTls(THDB *thdb) if (*cbs) FIXME(win32, "TLS Callbacks aren't going to be called\n"); } - /* Don't use TlsSetValue, we are in the wrong thread */ - thdb->tls_array[pem->tlsindex] = mem; + + TlsSetValue( pem->tlsindex, mem ); } } -/**************************************************************************** - * DisableThreadLibraryCalls (KERNEL32.74) - * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set. - */ -BOOL WINAPI DisableThreadLibraryCalls(HMODULE hModule) -{ - WINE_MODREF *wm; - - for (wm=PROCESS_Current()->modref_list;wm;wm=wm->next) - if ((wm->module == hModule) && (wm->type==MODULE32_PE)) - wm->binfmt.pe.flags|=PE_MODREF_NO_DLL_CALLS; - return TRUE; -} diff --git a/scheduler/process.c b/scheduler/process.c index fa96c6f9912..b1450f32e7a 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -363,14 +363,14 @@ void PROCESS_Start(void) /* Initialize thread-local storage */ - PE_InitTls( thdb ); + PE_InitTls(); if (PE_HEADER(pModule->module32)->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI) AllocConsole(); /* Now call the entry point */ - MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)-1 ); + MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)1 ); entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32, OptionalHeader.AddressOfEntryPoint); TRACE(relay, "(entryproc=%p)\n", entry ); @@ -509,7 +509,7 @@ error: */ void WINAPI ExitProcess( DWORD status ) { - MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, NULL ); + MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, (LPVOID)1 ); if ( THREAD_IsWin16( THREAD_Current() ) ) TASK_KillCurrentTask( status ); diff --git a/scheduler/thread.c b/scheduler/thread.c index b9c6ee202ec..28c8a1ff2d5 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -261,7 +261,6 @@ THDB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16 if (!THREAD_InitTHDB( thdb, stack_size, alloc_stack16, sa )) goto error; thdb->next = THREAD_First; THREAD_First = thdb; - PE_InitTls( thdb ); return thdb; error: @@ -282,6 +281,7 @@ static void THREAD_Start(void) { THDB *thdb = THREAD_Current(); LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point; + PE_InitTls(); MODULE_InitializeDLLs( 0, DLL_THREAD_ATTACH, NULL ); ExitThread( func( thdb->entry_arg ) ); } @@ -412,10 +412,17 @@ void WINAPI SetLastErrorEx( /********************************************************************** - * THREAD_TlsAlloc + * TlsAlloc [KERNEL32.530] Allocates a TLS index. + * + * Allocates a thread local storage index + * + * RETURNS + * Success: TLS Index + * Failure: 0xFFFFFFFF */ -DWORD THREAD_TlsAlloc(THDB *thread) +DWORD WINAPI TlsAlloc( void ) { + THDB *thread = THREAD_Current(); DWORD i, mask, ret = 0; DWORD *bits = thread->process->tls_bits; EnterCriticalSection( &thread->process->crit_section ); @@ -437,21 +444,6 @@ DWORD THREAD_TlsAlloc(THDB *thread) } -/********************************************************************** - * TlsAlloc [KERNEL32.530] Allocates a TLS index. - * - * Allocates a thread local storage index - * - * RETURNS - * Success: TLS Index - * Failure: 0xFFFFFFFF - */ -DWORD WINAPI TlsAlloc(void) -{ - return THREAD_TlsAlloc(THREAD_Current()); -} - - /********************************************************************** * TlsFree [KERNEL32.531] Releases a TLS index. *