Fixed a couple of race conditions in the wine_pthread routines at
thread startup and exit.
This commit is contained in:
parent
a5f816c6d3
commit
4fac95df3d
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue