Commit 4fac95df authored by Alexandre Julliard's avatar Alexandre Julliard

Fixed a couple of race conditions in the wine_pthread routines at

thread startup and exit.
parent a5f816c6
...@@ -115,6 +115,22 @@ static void CALLBACK THREAD_Start( void *ptr ) ...@@ -115,6 +115,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.@) * CreateThread (KERNEL32.@)
*/ */
HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack, HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
...@@ -213,6 +229,7 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */ ...@@ -213,6 +229,7 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
info.stack_base = NtCurrentTeb()->DeallocationStack; info.stack_base = NtCurrentTeb()->DeallocationStack;
info.teb_base = NtCurrentTeb(); info.teb_base = NtCurrentTeb();
info.teb_sel = wine_get_fs(); info.teb_sel = wine_get_fs();
info.cleanup = cleanup_teb;
info.exit_status = code; info.exit_status = code;
size = 0; size = 0;
...@@ -234,11 +251,6 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */ ...@@ -234,11 +251,6 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
sigaddset( &block_set, SIGTERM ); sigaddset( &block_set, SIGTERM );
sigprocmask( SIG_BLOCK, &block_set, NULL ); 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 ); wine_pthread_exit_thread( &info );
} }
} }
......
...@@ -129,6 +129,7 @@ void thread_init(void) ...@@ -129,6 +129,7 @@ void thread_init(void)
thread_info.teb_base = teb; thread_info.teb_base = teb;
thread_info.teb_size = size; thread_info.teb_size = size;
thread_info.teb_sel = teb->teb_sel; thread_info.teb_sel = teb->teb_sel;
wine_pthread_init_current_teb( &thread_info );
wine_pthread_init_thread( &thread_info ); wine_pthread_init_thread( &thread_info );
debug_info.str_pos = debug_info.strings; debug_info.str_pos = debug_info.strings;
...@@ -171,9 +172,10 @@ static void start_thread( struct wine_pthread_thread_info *info ) ...@@ -171,9 +172,10 @@ static void start_thread( struct wine_pthread_thread_info *info )
debug_info.out_pos = debug_info.output; debug_info.out_pos = debug_info.output;
teb->debug_info = &debug_info; teb->debug_info = &debug_info;
wine_pthread_init_thread( info ); wine_pthread_init_current_teb( info );
SIGNAL_Init(); SIGNAL_Init();
server_init_thread( info->pid, info->tid, func ); server_init_thread( info->pid, info->tid, func );
wine_pthread_init_thread( info );
/* allocate a memory view for the stack */ /* allocate a memory view for the stack */
size = info->stack_size; size = info->stack_size;
......
...@@ -94,12 +94,14 @@ struct wine_pthread_thread_info ...@@ -94,12 +94,14 @@ struct wine_pthread_thread_info
int pid; /* Unix process id */ int pid; /* Unix process id */
int tid; /* Unix thread id */ int tid; /* Unix thread id */
void (*entry)( struct wine_pthread_thread_info *info ); /* thread entry point */ 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 */ 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_process( const struct wine_pthread_functions *functions );
extern void wine_pthread_init_thread( struct wine_pthread_thread_info *info ); 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 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 *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_exit_thread( struct wine_pthread_thread_info *info );
extern void DECLSPEC_NORETURN wine_pthread_abort_thread( int status ); extern void DECLSPEC_NORETURN wine_pthread_abort_thread( int status );
......
...@@ -67,6 +67,13 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info ) ...@@ -67,6 +67,13 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
} }
/*********************************************************************** /***********************************************************************
* wine_pthread_init_current_teb
*/
void wine_pthread_init_current_teb( struct wine_pthread_thread_info *info )
{
}
/***********************************************************************
* wine_pthread_get_current_teb * wine_pthread_get_current_teb
*/ */
void *wine_pthread_get_current_teb(void) void *wine_pthread_get_current_teb(void)
......
...@@ -59,6 +59,7 @@ EXPORTS ...@@ -59,6 +59,7 @@ EXPORTS
wine_pthread_abort_thread wine_pthread_abort_thread
wine_pthread_create_thread wine_pthread_create_thread
wine_pthread_exit_thread wine_pthread_exit_thread
wine_pthread_init_current_teb
wine_pthread_init_process wine_pthread_init_process
wine_pthread_init_thread wine_pthread_init_thread
wine_set_fs wine_set_fs
......
...@@ -189,6 +189,7 @@ static void cleanup_thread( void *ptr ) ...@@ -189,6 +189,7 @@ static void cleanup_thread( void *ptr )
{ {
/* copy the info structure since it is on the stack we will free */ /* 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; 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 ); wine_ldt_free_fs( info.teb_sel );
munmap( info.stack_base, info.stack_size ); munmap( info.stack_base, info.stack_size );
munmap( info.teb_base, info.teb_size ); munmap( info.teb_base, info.teb_size );
...@@ -220,34 +221,6 @@ void wine_pthread_init_thread( struct wine_pthread_thread_info *info ) ...@@ -220,34 +221,6 @@ void wine_pthread_init_thread( struct wine_pthread_thread_info *info )
{ {
struct pthread_descr_struct *descr; 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) if (funcs.ptr_set_thread_data)
{ {
descr = calloc( 1, sizeof(*descr) ); descr = calloc( 1, sizeof(*descr) );
...@@ -319,6 +292,43 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info ) ...@@ -319,6 +292,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 * wine_pthread_get_current_teb
*/ */
void *wine_pthread_get_current_teb(void) void *wine_pthread_get_current_teb(void)
......
...@@ -62,20 +62,6 @@ void wine_pthread_init_process( const struct wine_pthread_functions *functions ) ...@@ -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 ) 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) */ /* retrieve the stack info (except for main thread) */
if (funcs.ptr_set_thread_data) if (funcs.ptr_set_thread_data)
{ {
...@@ -91,10 +77,6 @@ void wine_pthread_init_thread( struct wine_pthread_thread_info *info ) ...@@ -91,10 +77,6 @@ void wine_pthread_init_thread( struct wine_pthread_thread_info *info )
info->stack_base = stack_top - info->stack_size; info->stack_base = stack_top - info->stack_size;
#endif #endif
} }
/* set pid and tid */
info->pid = getpid();
info->tid = gettid();
} }
...@@ -116,6 +98,33 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info ) ...@@ -116,6 +98,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 * wine_pthread_get_current_teb
*/ */
void *wine_pthread_get_current_teb(void) void *wine_pthread_get_current_teb(void)
...@@ -153,6 +162,7 @@ void wine_pthread_exit_thread( struct wine_pthread_thread_info *info ) ...@@ -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) if ((free_info = interlocked_xchg_ptr( (void **)&previous_info, cleanup_info )) != NULL)
{ {
pthread_join( free_info->self, &ptr ); 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 ); wine_ldt_free_fs( free_info->thread_info.teb_sel );
munmap( free_info->thread_info.teb_base, free_info->thread_info.teb_size ); munmap( free_info->thread_info.teb_base, free_info->thread_info.teb_size );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment