Commit 50fba7ff authored by Alexandre Julliard's avatar Alexandre Julliard

Moved the remaining SYSDEPS_* functions to the wine_pthread interface.

Let the pthread library allocate the stack itself.
parent 8d0ac557
......@@ -551,6 +551,7 @@ static void wine_set_thread_data( void *data )
static const struct wine_pthread_functions functions =
{
sizeof(functions), /* size */
wine_get_thread_data, /* ptr_get_thread_data */
wine_set_thread_data, /* ptr_set_thread_data */
wine_pthread_self, /* ptr_pthread_self */
......
......@@ -36,7 +36,6 @@ C_SRCS = \
signal_sparc.c \
string.c \
sync.c \
sysdeps.c \
version.c \
thread.c \
time.c \
......
......@@ -52,7 +52,7 @@ extern void thread_init(void);
/* server support */
extern void server_init_process(void);
extern void server_init_thread(void);
extern void server_init_thread( int unix_pid, int unix_tid );
extern void DECLSPEC_NORETURN server_protocol_error( const char *err, ... );
extern void DECLSPEC_NORETURN server_protocol_perror( const char *err );
extern void DECLSPEC_NORETURN server_abort_thread( int status );
......
......@@ -666,7 +666,7 @@ void server_init_process(void)
*
* Send an init thread request. Return 0 if OK.
*/
void server_init_thread(void)
void server_init_thread( int unix_pid, int unix_tid )
{
TEB *teb = NtCurrentTeb();
int version, ret;
......@@ -700,8 +700,8 @@ void server_init_thread(void)
SERVER_START_REQ( init_thread )
{
req->unix_pid = getpid();
req->unix_tid = SYSDEPS_GetUnixTid();
req->unix_pid = unix_pid;
req->unix_tid = unix_tid;
req->teb = teb;
req->entry = teb->entry_point;
req->reply_fd = reply_pipe[1];
......
/*
* System-dependent scheduler support
*
* Copyright 1998 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <signal.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
#endif
#ifdef HAVE_SYS_LWP_H
# include <sys/lwp.h>
#endif
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#include "ntstatus.h"
#include "thread.h"
#include "wine/pthread.h"
#include "wine/server.h"
#include "winbase.h"
#include "wine/library.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(thread);
/***********************************************************************
* SYSDEPS_SetCurThread
*
* Make 'thread' the current thread.
*/
void SYSDEPS_SetCurThread( TEB *teb )
{
#if defined(__i386__)
/* On the i386, the current thread is in the %fs register */
LDT_ENTRY fs_entry;
wine_ldt_set_base( &fs_entry, teb );
wine_ldt_set_limit( &fs_entry, 0xfff );
wine_ldt_set_flags( &fs_entry, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
wine_ldt_init_fs( teb->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" (teb));
# else
__asm__ __volatile__("mr 2, %0" : : "r" (teb));
# endif
#elif defined(HAVE__LWP_CREATE)
/* On non-i386 Solaris, we use the LWP private pointer */
_lwp_setprivate( teb );
#endif
wine_pthread_init_thread();
}
/***********************************************************************
* SYSDEPS_GetUnixTid
*
* Get the Unix tid of the current thread.
*/
int SYSDEPS_GetUnixTid(void)
{
#ifdef HAVE__LWP_SELF
return _lwp_self();
#elif defined(__linux__) && defined(__i386__)
int ret;
__asm__("int $0x80" : "=a" (ret) : "0" (224) /* SYS_gettid */);
if (ret < 0) ret = -1;
return ret;
#else
return -1;
#endif
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*
* This will crash and burn if called before threading is initialized
*/
#if defined(__i386__) && defined(__GNUC__)
__ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
#elif defined(__i386__) && defined(_MSC_VER)
/* Nothing needs to be done. MS C "magically" exports the inline version from winnt.h */
#elif defined(HAVE__LWP_CREATE)
/***********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
struct _TEB * WINAPI NtCurrentTeb(void)
{
extern void *_lwp_getprivate(void);
return (struct _TEB *)_lwp_getprivate();
}
#elif defined(__powerpc__)
# ifdef __APPLE__
__ASM_GLOBAL_FUNC( NtCurrentTeb, "\n\tmr r3,r13\n\tblr" );
# else
__ASM_GLOBAL_FUNC( NtCurrentTeb, "\n\tmr 3,2\n\tblr" );
# endif
#else
# error NtCurrentTeb not defined for this architecture
#endif /* __i386__ */
......@@ -95,6 +95,7 @@ void thread_init(void)
TEB *teb;
void *addr;
ULONG size;
struct wine_pthread_thread_info thread_info;
static struct debug_info debug_info; /* debug info for initial thread */
debug_info.str_pos = debug_info.strings;
......@@ -118,11 +119,16 @@ void thread_init(void)
teb->debug_info = &debug_info;
InsertHeadList( &tls_links, &teb->TlsLinks );
SYSDEPS_SetCurThread( teb );
thread_info.stack_base = NULL;
thread_info.stack_size = 0;
thread_info.teb_base = teb;
thread_info.teb_size = size;
thread_info.teb_sel = teb->teb_sel;
wine_pthread_init_thread( &thread_info );
/* setup the server connection */
server_init_process();
server_init_thread();
server_init_thread( thread_info.pid, thread_info.tid );
/* create a memory view for the TEB */
NtAllocateVirtualMemory( GetCurrentProcess(), &addr, teb, &size,
......@@ -153,9 +159,9 @@ static void start_thread( struct wine_pthread_thread_info *info )
debug_info.out_pos = debug_info.output;
teb->debug_info = &debug_info;
SYSDEPS_SetCurThread( teb );
wine_pthread_init_thread( info );
SIGNAL_Init();
server_init_thread();
server_init_thread( info->pid, info->tid );
/* allocate a memory view for the stack */
size = info->stack_size;
......@@ -540,3 +546,18 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
return STATUS_NOT_IMPLEMENTED;
}
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
#if defined(__i386__) && defined(__GNUC__)
__ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
#elif defined(__i386__) && defined(_MSC_VER)
/* Nothing needs to be done. MS C "magically" exports the inline version from winnt.h */
#else
TEB * WINAPI NtCurrentTeb(void)
{
return wine_pthread_get_current_teb();
}
#endif /* __i386__ */
......@@ -143,8 +143,4 @@ typedef struct _TEB
/* scheduler/thread.c */
extern TEB *THREAD_InitStack( TEB *teb, DWORD stack_size );
/* scheduler/sysdeps.c */
extern void SYSDEPS_SetCurThread( TEB *teb );
extern int SYSDEPS_GetUnixTid(void);
#endif /* __WINE_THREAD_H */
......@@ -37,6 +37,7 @@ typedef void *pthread_rwlockattr_t;
struct wine_pthread_functions
{
size_t size;
void * (*ptr_get_thread_data)(void);
void (*ptr_set_thread_data)(void *data);
pthread_t (*ptr_pthread_self)(void);
......@@ -85,18 +86,21 @@ struct wine_pthread_functions
/* thread information used to creating and exiting threads */
struct wine_pthread_thread_info
{
void *stack_base;
size_t stack_size;
void *teb_base;
size_t teb_size;
unsigned short teb_sel;
void (*entry)( struct wine_pthread_thread_info *info );
int exit_status;
void *stack_base; /* base address of the stack */
size_t stack_size; /* size of the stack */
void *teb_base; /* base address of the TEB */
size_t teb_size; /* size of the TEB (possibly including signal stack) */
unsigned short teb_sel; /* selector to use for TEB */
int pid; /* Unix process id */
int tid; /* Unix thread id */
void (*entry)( struct wine_pthread_thread_info *info ); /* thread entry point */
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(void);
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_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 );
......
......@@ -54,7 +54,7 @@ void wine_pthread_init_process( const struct wine_pthread_functions *functions )
/***********************************************************************
* wine_pthread_init_thread
*/
void wine_pthread_init_thread(void)
void wine_pthread_init_thread( struct wine_pthread_thread_info *info )
{
}
......@@ -67,6 +67,14 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
}
/***********************************************************************
* wine_pthread_get_current_teb
*/
void *wine_pthread_get_current_teb(void)
{
return NULL;
}
/***********************************************************************
* wine_pthread_exit_thread
*/
void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
......
......@@ -206,7 +206,7 @@ static void cleanup_thread( void *ptr )
*/
void wine_pthread_init_process( const struct wine_pthread_functions *functions )
{
memcpy( &funcs, functions, sizeof(funcs) );
memcpy( &funcs, functions, min(functions->size,sizeof(funcs)) );
funcs.ptr_set_thread_data( &initial_descr );
}
......@@ -216,10 +216,38 @@ void wine_pthread_init_process( const struct wine_pthread_functions *functions )
*
* Initialization for a newly created thread.
*/
void wine_pthread_init_thread(void)
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) );
......@@ -291,6 +319,31 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
/***********************************************************************
* wine_pthread_get_current_teb
*/
void *wine_pthread_get_current_teb(void)
{
void *ret;
#ifdef __i386__
__asm__( ".byte 0x64\n\tmovl 0x18,%0" : "=r" (ret) );
#elif defined(HAVE__LWP_CREATE)
ret = _lwp_getprivate();
#elif defined(__powerpc__)
# ifdef __APPLE__
__asm__( "mr %0,r13" : "=r" (ret) );
# else
__asm__( "mr %0,2" : "=r" (ret) );
# endif
#else
# error wine_pthread_get_current_teb not defined for this architecture
#endif /* __i386__ */
return ret;
}
/***********************************************************************
* wine_pthread_exit_thread
*/
void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
......
......@@ -38,6 +38,25 @@
#include "wine/library.h"
#include "wine/pthread.h"
static struct wine_pthread_functions funcs;
#ifndef __i386__
static pthread_key_t teb_key;
#endif
static inline int gettid(void)
{
#if defined(__linux__) && defined(__i386__)
int ret;
__asm__("int $0x80" : "=a" (ret) : "0" (224) /* SYS_gettid */);
if (ret < 0) ret = -1;
return ret;
#else
return -1; /* FIXME */
#endif
}
/***********************************************************************
* wine_pthread_init_process
*
......@@ -45,6 +64,7 @@
*/
void wine_pthread_init_process( const struct wine_pthread_functions *functions )
{
memcpy( &funcs, functions, min(functions->size,sizeof(funcs)) );
}
......@@ -53,8 +73,33 @@ void wine_pthread_init_process( const struct wine_pthread_functions *functions )
*
* Initialization for a newly created thread.
*/
void wine_pthread_init_thread(void)
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)
{
pthread_attr_t attr;
pthread_getattr_np( pthread_self(), &attr );
pthread_attr_getstack( &attr, &info->stack_base, &info->stack_size );
}
/* set pid and tid */
info->pid = getpid();
info->tid = gettid();
}
......@@ -65,17 +110,28 @@ int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
{
pthread_t id;
pthread_attr_t attr;
int ret = 0;
if (!info->stack_base)
{
info->stack_base = wine_anon_mmap( NULL, info->stack_size,
PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
if (info->stack_base == (void *)-1) return -1;
}
pthread_attr_init( &attr );
pthread_attr_setstack( &attr, info->stack_base, info->stack_size );
if (pthread_create( &id, &attr, (void * (*)(void *))info->entry, info )) return -1;
return 0;
pthread_attr_setstacksize( &attr, info->stack_size );
if (pthread_create( &id, &attr, (void * (*)(void *))info->entry, info )) ret = -1;
pthread_attr_destroy( &attr );
return ret;
}
/***********************************************************************
* wine_pthread_get_current_teb
*/
void *wine_pthread_get_current_teb(void)
{
#ifdef __i386__
void *ret;
__asm__( ".byte 0x64\n\tmovl 0x18,%0" : "=r" (ret) );
return ret;
#else
return pthread_getspecific( teb_key );
#endif
}
......@@ -103,7 +159,6 @@ void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
{
pthread_join( free_info->self, &ptr );
wine_ldt_free_fs( free_info->thread_info.teb_sel );
munmap( free_info->thread_info.stack_base, free_info->thread_info.stack_size );
munmap( free_info->thread_info.teb_base, free_info->thread_info.teb_size );
}
pthread_exit( (void *)info->exit_status );
......@@ -115,6 +170,7 @@ void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
*/
void wine_pthread_abort_thread( int status )
{
pthread_detach( pthread_self() ); /* no one will be joining with us */
pthread_exit( (void *)status );
}
......
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