Rewrote module TLS support and moved it to ntdll.

This commit is contained in:
Alexandre Julliard 2003-05-14 19:51:14 +00:00
parent 0b34697abb
commit adb532903c
5 changed files with 120 additions and 78 deletions

View File

@ -63,6 +63,10 @@ static const char * const reason_names[] =
"THREAD_DETACH" "THREAD_DETACH"
}; };
static UINT tls_module_count; /* number of modules with TLS directory */
static UINT tls_total_size; /* total size of TLS storage */
static const IMAGE_TLS_DIRECTORY **tls_dirs; /* array of TLS directories */
static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" ); static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
static WINE_MODREF *cached_modref; static WINE_MODREF *cached_modref;
static WINE_MODREF *current_modref; static WINE_MODREF *current_modref;
@ -398,6 +402,92 @@ WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
} }
/*************************************************************************
* alloc_process_tls
*
* Allocate the process-wide structure for module TLS storage.
*/
static NTSTATUS alloc_process_tls(void)
{
WINE_MODREF *wm;
IMAGE_TLS_DIRECTORY *dir;
ULONG size, i;
for (wm = MODULE_modref_list; wm; wm = wm->next)
{
if (!(dir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_TLS, &size )))
continue;
size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
if (!size) continue;
tls_total_size += size;
tls_module_count++;
}
if (!tls_module_count) return STATUS_SUCCESS;
TRACE( "count %u size %u\n", tls_module_count, tls_total_size );
tls_dirs = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_module_count * sizeof(*tls_dirs) );
if (!tls_dirs) return STATUS_NO_MEMORY;
for (i = 0, wm = MODULE_modref_list; wm; wm = wm->next)
{
if (!(dir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_TLS, &size )))
continue;
tls_dirs[i] = dir;
*dir->AddressOfIndex = i;
wm->ldr.TlsIndex = i;
wm->ldr.LoadCount = -1; /* can't unload it */
i++;
}
return STATUS_SUCCESS;
}
/*************************************************************************
* alloc_thread_tls
*
* Allocate the per-thread structure for module TLS storage.
*/
static NTSTATUS alloc_thread_tls(void)
{
void **pointers;
char *data;
UINT i;
if (!tls_module_count) return STATUS_SUCCESS;
if (!(pointers = RtlAllocateHeap( ntdll_get_process_heap(), 0,
tls_module_count * sizeof(*pointers) )))
return STATUS_NO_MEMORY;
if (!(data = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_total_size )))
{
RtlFreeHeap( ntdll_get_process_heap(), 0, pointers );
return STATUS_NO_MEMORY;
}
for (i = 0; i < tls_module_count; i++)
{
const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
TRACE( "thread %04lx idx %d: %ld/%ld bytes from %p to %p\n",
GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
(void *)dir->StartAddressOfRawData, data );
pointers[i] = data;
memcpy( data, (void *)dir->StartAddressOfRawData, size );
data += size;
memset( data, 0, dir->SizeOfZeroFill );
data += dir->SizeOfZeroFill;
}
NtCurrentTeb()->tls_ptr = pointers;
return STATUS_SUCCESS;
}
/************************************************************************* /*************************************************************************
* call_tls_callbacks * call_tls_callbacks
*/ */
@ -492,9 +582,9 @@ static BOOL MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
* detach notifications are called in the reverse of the sequence the attach * detach notifications are called in the reverse of the sequence the attach
* notifications *returned*. * notifications *returned*.
*/ */
BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ) NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
{ {
BOOL retv = TRUE; NTSTATUS status = STATUS_SUCCESS;
int i; int i;
RtlEnterCriticalSection( &loader_section ); RtlEnterCriticalSection( &loader_section );
@ -502,7 +592,9 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
if (!wm) if (!wm)
{ {
wm = exe_modref; wm = exe_modref;
PE_InitTls(); wm->ldr.LoadCount = -1; /* can't unload main exe */
if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done;
if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
} }
assert( wm ); assert( wm );
@ -517,22 +609,26 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS; wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
/* Recursively attach all DLLs this one depends on */ /* Recursively attach all DLLs this one depends on */
for ( i = 0; retv && i < wm->nDeps; i++ ) for ( i = 0; i < wm->nDeps; i++ )
if ( wm->deps[i] ) {
retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved ); if (!wm->deps[i]) continue;
if ((status = MODULE_DllProcessAttach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
}
/* Call DLL entry point */ /* Call DLL entry point */
if ( retv ) if (status == STATUS_SUCCESS)
{ {
WINE_MODREF *prev = current_modref; WINE_MODREF *prev = current_modref;
current_modref = wm; current_modref = wm;
retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ); if (MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ))
if (retv) wm->ldr.Flags |= LDR_PROCESS_ATTACHED; wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
else
status = STATUS_DLL_INIT_FAILED;
current_modref = prev; current_modref = prev;
} }
/* Re-insert MODREF at head of list */ /* Re-insert MODREF at head of list */
if ( retv && wm->prev ) if (status == STATUS_SUCCESS && wm->prev )
{ {
wm->prev->next = wm->next; wm->prev->next = wm->next;
if ( wm->next ) wm->next->prev = wm->prev; if ( wm->next ) wm->next->prev = wm->prev;
@ -547,10 +643,9 @@ BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
TRACE("(%s,%p) - END\n", wm->modname, lpReserved ); TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
done: done:
RtlLeaveCriticalSection( &loader_section ); RtlLeaveCriticalSection( &loader_section );
return retv; return status;
} }
/************************************************************************* /*************************************************************************
@ -573,7 +668,7 @@ static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
/* Check whether to detach this DLL */ /* Check whether to detach this DLL */
if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) ) if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
continue; continue;
if ( wm->ldr.LoadCount > 0 && !bForceDetach ) if ( wm->ldr.LoadCount && !bForceDetach )
continue; continue;
/* Call detach notification */ /* Call detach notification */
@ -596,17 +691,18 @@ static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
* reverse sequence of process detach notification. * reverse sequence of process detach notification.
* *
*/ */
void MODULE_DllThreadAttach( LPVOID lpReserved ) NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved )
{ {
WINE_MODREF *wm; WINE_MODREF *wm;
NTSTATUS status;
/* don't do any attach calls if process is exiting */ /* don't do any attach calls if process is exiting */
if (process_detaching) return; if (process_detaching) return STATUS_SUCCESS;
/* FIXME: there is still a race here */ /* FIXME: there is still a race here */
RtlEnterCriticalSection( &loader_section ); RtlEnterCriticalSection( &loader_section );
PE_InitTls(); if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
for ( wm = MODULE_modref_list; wm; wm = wm->next ) for ( wm = MODULE_modref_list; wm; wm = wm->next )
if ( !wm->next ) if ( !wm->next )
@ -622,7 +718,9 @@ void MODULE_DllThreadAttach( LPVOID lpReserved )
MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved ); MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
} }
done:
RtlLeaveCriticalSection( &loader_section ); RtlLeaveCriticalSection( &loader_section );
return status;
} }
/****************************************************************** /******************************************************************
@ -922,8 +1020,8 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
} }
if (*pwm) if (*pwm)
{ {
(*pwm)->ldr.LoadCount++; if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) && if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
!(flags & DONT_RESOLVE_DLL_REFERENCES)) !(flags & DONT_RESOLVE_DLL_REFERENCES))
{ {
@ -1022,11 +1120,11 @@ NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libna
switch (nts = load_dll( str.Buffer, flags, &wm )) switch (nts = load_dll( str.Buffer, flags, &wm ))
{ {
case STATUS_SUCCESS: case STATUS_SUCCESS:
if ( !MODULE_DllProcessAttach( wm, NULL ) ) nts = MODULE_DllProcessAttach( wm, NULL );
if (nts != STATUS_SUCCESS)
{ {
WARN("Attach failed for module '%s'.\n", str.Buffer); WARN("Attach failed for module '%s'.\n", str.Buffer);
LdrUnloadDll(wm->ldr.BaseAddress); LdrUnloadDll(wm->ldr.BaseAddress);
nts = STATUS_DLL_INIT_FAILED;
wm = NULL; wm = NULL;
} }
break; break;

View File

@ -181,8 +181,8 @@ enum binary_type
}; };
/* module.c */ /* module.c */
extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ); extern NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
extern void MODULE_DllThreadAttach( LPVOID lpReserved ); extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );
extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ); extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 );
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
@ -224,7 +224,6 @@ extern NTSTATUS PE_LoadLibraryExA(LPCSTR, DWORD, WINE_MODREF**);
extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags ); extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags );
extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename,
DWORD flags, HANDLE hFile, BOOL builtin ); DWORD flags, HANDLE hFile, BOOL builtin );
extern void PE_InitTls(void);
extern DWORD PE_fixup_imports(WINE_MODREF *wm); extern DWORD PE_fixup_imports(WINE_MODREF *wm);
/* loader/loadorder.c */ /* loader/loadorder.c */

View File

@ -371,56 +371,3 @@ NTSTATUS PE_LoadLibraryExA (LPCSTR name, DWORD flags, WINE_MODREF** pwm)
CloseHandle( hFile ); CloseHandle( hFile );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/************************************************************************
* PE_InitTls (internal)
*
* If included, initialises the thread local storages of modules.
* Pointers in those structs are not RVAs but real pointers which have been
* relocated by do_relocations() already.
*/
static LPVOID
_fixup_address(PIMAGE_OPTIONAL_HEADER opt,int delta,LPVOID addr) {
if ( ((DWORD)addr>opt->ImageBase) &&
((DWORD)addr<opt->ImageBase+opt->SizeOfImage)
)
/* the address has not been relocated! */
return (LPVOID)(((DWORD)addr)+delta);
else
/* the address has been relocated already */
return addr;
}
void PE_InitTls( void )
{
WINE_MODREF *wm;
IMAGE_NT_HEADERS *peh;
DWORD size,datasize,dirsize;
LPVOID mem;
PIMAGE_TLS_DIRECTORY pdir;
int delta;
for (wm = MODULE_modref_list;wm;wm=wm->next) {
peh = RtlImageNtHeader(wm->ldr.BaseAddress);
pdir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
if (!pdir) continue;
delta = (char *)wm->ldr.BaseAddress - (char *)peh->OptionalHeader.ImageBase;
if ( wm->ldr.TlsIndex == -1 ) {
LPDWORD xaddr;
wm->ldr.TlsIndex = TlsAlloc();
xaddr = _fixup_address(&(peh->OptionalHeader),delta,
pdir->AddressOfIndex
);
*xaddr=wm->ldr.TlsIndex;
}
datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
size = datasize + pdir->SizeOfZeroFill;
NtAllocateVirtualMemory( GetCurrentProcess(), &mem, NULL, &size,
MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
memcpy(mem,_fixup_address(&(peh->OptionalHeader),delta,(LPVOID)pdir->StartAddressOfRawData),datasize);
TlsSetValue( wm->ldr.TlsIndex, mem );
}
}

View File

@ -539,7 +539,6 @@ static void start_process(void)
/* create the main modref and load dependencies */ /* create the main modref and load dependencies */
if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE ))) if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE )))
goto error; goto error;
wm->ldr.LoadCount++;
if (main_exe_file) CloseHandle( main_exe_file ); /* we no longer need it */ if (main_exe_file) CloseHandle( main_exe_file ); /* we no longer need it */

View File

@ -96,7 +96,6 @@ static BOOL THREAD_InitTEB( TEB *teb )
teb->except = (void *)~0UL; teb->except = (void *)~0UL;
teb->self = teb; teb->self = teb;
teb->tibflags = TEBF_WIN32; teb->tibflags = TEBF_WIN32;
teb->tls_ptr = teb->tls_array;
teb->exit_code = STILL_ACTIVE; teb->exit_code = STILL_ACTIVE;
teb->request_fd = -1; teb->request_fd = -1;
teb->reply_fd = -1; teb->reply_fd = -1;