diff --git a/dlls/kernel/thread.c b/dlls/kernel/thread.c index 3c5bbd90fd1..0cbddd264ce 100644 --- a/dlls/kernel/thread.c +++ b/dlls/kernel/thread.c @@ -114,6 +114,22 @@ static void CALLBACK THREAD_Start( void *ptr ) } +/*********************************************************************** + * cleanup_teb + * + * Cleanup the TEB structure; might be called from a different thread. + */ +static void cleanup_teb( struct wine_pthread_thread_info *info ) +{ + TEB *teb = (TEB *)info->teb_base; + + close( teb->wait_fd[0] ); + close( teb->wait_fd[1] ); + close( teb->reply_fd ); + close( teb->request_fd ); +} + + /*********************************************************************** * CreateThread (KERNEL32.@) */ @@ -213,6 +229,7 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */ info.stack_base = NtCurrentTeb()->DeallocationStack; info.teb_base = NtCurrentTeb(); info.teb_sel = wine_get_fs(); + info.cleanup = cleanup_teb; info.exit_status = code; size = 0; @@ -234,11 +251,6 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */ sigaddset( &block_set, SIGTERM ); sigprocmask( SIG_BLOCK, &block_set, NULL ); - close( NtCurrentTeb()->wait_fd[0] ); - close( NtCurrentTeb()->wait_fd[1] ); - close( NtCurrentTeb()->reply_fd ); - close( NtCurrentTeb()->request_fd ); - wine_pthread_exit_thread( &info ); } } diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 8a0fcca8d62..1251fd3ba08 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -129,6 +129,7 @@ void thread_init(void) thread_info.teb_base = teb; thread_info.teb_size = size; thread_info.teb_sel = teb->teb_sel; + wine_pthread_init_current_teb( &thread_info ); wine_pthread_init_thread( &thread_info ); debug_info.str_pos = debug_info.strings; @@ -171,9 +172,10 @@ static void start_thread( struct wine_pthread_thread_info *info ) debug_info.out_pos = debug_info.output; teb->debug_info = &debug_info; - wine_pthread_init_thread( info ); + wine_pthread_init_current_teb( info ); SIGNAL_Init(); server_init_thread( info->pid, info->tid, func ); + wine_pthread_init_thread( info ); /* allocate a memory view for the stack */ size = info->stack_size; diff --git a/include/wine/pthread.h b/include/wine/pthread.h index 26aa78aa878..f94794f27db 100644 --- a/include/wine/pthread.h +++ b/include/wine/pthread.h @@ -94,12 +94,14 @@ struct wine_pthread_thread_info int pid; /* Unix process id */ int tid; /* Unix thread id */ void (*entry)( struct wine_pthread_thread_info *info ); /* thread entry point */ + void (*cleanup)( struct wine_pthread_thread_info *info ); /* thread cleanup function */ int exit_status; /* thread exit status when calling wine_pthread_exit_thread */ }; extern void wine_pthread_init_process( const struct wine_pthread_functions *functions ); extern void wine_pthread_init_thread( struct wine_pthread_thread_info *info ); extern int wine_pthread_create_thread( struct wine_pthread_thread_info *info ); +extern void wine_pthread_init_current_teb( struct wine_pthread_thread_info *info ); extern void *wine_pthread_get_current_teb(void); extern void DECLSPEC_NORETURN wine_pthread_exit_thread( struct wine_pthread_thread_info *info ); extern void DECLSPEC_NORETURN wine_pthread_abort_thread( int status ); diff --git a/libs/wine/port.c b/libs/wine/port.c index 6ba553756c8..35595c54a33 100644 --- a/libs/wine/port.c +++ b/libs/wine/port.c @@ -66,6 +66,13 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info ) return -1; } +/*********************************************************************** + * wine_pthread_init_current_teb + */ +void wine_pthread_init_current_teb( struct wine_pthread_thread_info *info ) +{ +} + /*********************************************************************** * wine_pthread_get_current_teb */ diff --git a/libs/wine/wine.def b/libs/wine/wine.def index 439ac0f89ac..bee9bc948d1 100644 --- a/libs/wine/wine.def +++ b/libs/wine/wine.def @@ -59,6 +59,7 @@ EXPORTS wine_pthread_abort_thread wine_pthread_create_thread wine_pthread_exit_thread + wine_pthread_init_current_teb wine_pthread_init_process wine_pthread_init_thread wine_set_fs diff --git a/loader/kthread.c b/loader/kthread.c index 7255f6b6823..436f059b701 100644 --- a/loader/kthread.c +++ b/loader/kthread.c @@ -189,6 +189,7 @@ static void cleanup_thread( void *ptr ) { /* copy the info structure since it is on the stack we will free */ struct wine_pthread_thread_info info = *(struct wine_pthread_thread_info *)ptr; + if (info.cleanup) info.cleanup( &info ); wine_ldt_free_fs( info.teb_sel ); munmap( info.stack_base, info.stack_size ); munmap( info.teb_base, info.teb_size ); @@ -220,34 +221,6 @@ void wine_pthread_init_thread( struct wine_pthread_thread_info *info ) { struct pthread_descr_struct *descr; -#ifdef __i386__ - /* On the i386, the current thread is in the %fs register */ - LDT_ENTRY fs_entry; - - wine_ldt_set_base( &fs_entry, info->teb_base ); - wine_ldt_set_limit( &fs_entry, info->teb_size - 1 ); - wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT ); - wine_ldt_init_fs( info->teb_sel, &fs_entry ); -#elif defined(__powerpc__) - /* On PowerPC, the current TEB is in the gpr13 register */ -# ifdef __APPLE__ - __asm__ __volatile__("mr r13, %0" : : "r" (info->teb_base)); -# else - __asm__ __volatile__("mr 2, %0" : : "r" (info->teb_base)); -# endif -#elif defined(HAVE__LWP_CREATE) - /* On non-i386 Solaris, we use the LWP private pointer */ - _lwp_setprivate( info->teb_base ); -#endif - - /* set pid and tid */ - info->pid = getpid(); -#ifdef HAVE__LWP_SELF - info->tid = _lwp_self(); -#else - info->tid = -1; -#endif - if (funcs.ptr_set_thread_data) { descr = calloc( 1, sizeof(*descr) ); @@ -318,6 +291,43 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info ) } +/*********************************************************************** + * wine_pthread_init_current_teb + * + * Set the current TEB for a new thread. + */ +void wine_pthread_init_current_teb( struct wine_pthread_thread_info *info ) +{ +#ifdef __i386__ + /* On the i386, the current thread is in the %fs register */ + LDT_ENTRY fs_entry; + + wine_ldt_set_base( &fs_entry, info->teb_base ); + wine_ldt_set_limit( &fs_entry, info->teb_size - 1 ); + wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT ); + wine_ldt_init_fs( info->teb_sel, &fs_entry ); +#elif defined(__powerpc__) + /* On PowerPC, the current TEB is in the gpr13 register */ +# ifdef __APPLE__ + __asm__ __volatile__("mr r13, %0" : : "r" (info->teb_base)); +# else + __asm__ __volatile__("mr 2, %0" : : "r" (info->teb_base)); +# endif +#elif defined(HAVE__LWP_CREATE) + /* On non-i386 Solaris, we use the LWP private pointer */ + _lwp_setprivate( info->teb_base ); +#endif + + /* set pid and tid */ + info->pid = getpid(); +#ifdef HAVE__LWP_SELF + info->tid = _lwp_self(); +#else + info->tid = -1; +#endif +} + + /*********************************************************************** * wine_pthread_get_current_teb */ diff --git a/loader/pthread.c b/loader/pthread.c index 835786d2c51..e8469c24db4 100644 --- a/loader/pthread.c +++ b/loader/pthread.c @@ -62,20 +62,6 @@ void wine_pthread_init_process( const struct wine_pthread_functions *functions ) */ void wine_pthread_init_thread( struct wine_pthread_thread_info *info ) { -#ifdef __i386__ - /* On the i386, the current thread is in the %fs register */ - LDT_ENTRY fs_entry; - - wine_ldt_set_base( &fs_entry, info->teb_base ); - wine_ldt_set_limit( &fs_entry, info->teb_size - 1 ); - wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT ); - wine_ldt_init_fs( info->teb_sel, &fs_entry ); -#else - if (!funcs.ptr_set_thread_data) /* first thread */ - pthread_key_create( &teb_key, NULL ); - pthread_setspecific( teb_key, info->teb_base ); -#endif - /* retrieve the stack info (except for main thread) */ if (funcs.ptr_set_thread_data) { @@ -91,10 +77,6 @@ void wine_pthread_init_thread( struct wine_pthread_thread_info *info ) info->stack_base = stack_top - info->stack_size; #endif } - - /* set pid and tid */ - info->pid = getpid(); - info->tid = gettid(); } @@ -115,6 +97,33 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info ) } +/*********************************************************************** + * wine_pthread_init_current_teb + * + * Set the current TEB for a new thread. + */ +void wine_pthread_init_current_teb( struct wine_pthread_thread_info *info ) +{ +#ifdef __i386__ + /* On the i386, the current thread is in the %fs register */ + LDT_ENTRY fs_entry; + + wine_ldt_set_base( &fs_entry, info->teb_base ); + wine_ldt_set_limit( &fs_entry, info->teb_size - 1 ); + wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT ); + wine_ldt_init_fs( info->teb_sel, &fs_entry ); +#else + if (!funcs.ptr_set_thread_data) /* first thread */ + pthread_key_create( &teb_key, NULL ); + pthread_setspecific( teb_key, info->teb_base ); +#endif + + /* set pid and tid */ + info->pid = getpid(); + info->tid = gettid(); +} + + /*********************************************************************** * wine_pthread_get_current_teb */ @@ -153,6 +162,7 @@ void wine_pthread_exit_thread( struct wine_pthread_thread_info *info ) if ((free_info = interlocked_xchg_ptr( (void **)&previous_info, cleanup_info )) != NULL) { pthread_join( free_info->self, &ptr ); + if (free_info->thread_info.cleanup) free_info->thread_info.cleanup( &free_info->thread_info ); wine_ldt_free_fs( free_info->thread_info.teb_sel ); munmap( free_info->thread_info.teb_base, free_info->thread_info.teb_size ); }