Commit 3e9f8c87 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Move the threading initialization functions to the Unix library.

parent 3e59649c
......@@ -69,10 +69,12 @@ static LDT_ENTRY ldt_make_entry( const void *base, unsigned int limit, unsigned
*/
void init_selectors(void)
{
const struct ldt_copy **ldt_copy_ptr;
if (!is_gdt_sel( get_gs() )) first_ldt_entry += 512;
if (!is_gdt_sel( get_fs() )) first_ldt_entry += 512;
RtlSetBits( &ldt_bitmap, 0, first_ldt_entry );
ldt_copy = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "__wine_ldt_copy" );
ldt_copy_ptr = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "__wine_ldt_copy" );
if (ldt_copy_ptr) ldt_copy = *ldt_copy_ptr;
}
/***********************************************************************
......
......@@ -53,6 +53,12 @@ C_SRCS = \
unix/debug.c \
unix/loader.c \
unix/server.c \
unix/signal_arm.c \
unix/signal_arm64.c \
unix/signal_i386.c \
unix/signal_powerpc.c \
unix/signal_x86_64.c \
unix/thread.c \
unix/virtual.c \
version.c \
virtual.c \
......
......@@ -66,7 +66,6 @@ extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC
extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN;
extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN;
extern LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr ) DECLSPEC_HIDDEN;
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
......@@ -80,15 +79,9 @@ extern LPCSTR debugstr_ObjectAttributes(const OBJECT_ATTRIBUTES *oa) DECLSPEC_HI
/* init routines */
extern SIZE_T signal_stack_size DECLSPEC_HIDDEN;
extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN;
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_process(void) DECLSPEC_HIDDEN;
extern void signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend ) DECLSPEC_HIDDEN;
extern void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN signal_exit_thread( int status ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN signal_exit_process( int status ) DECLSPEC_HIDDEN;
extern void version_init(void) DECLSPEC_HIDDEN;
extern void debug_init(void) DECLSPEC_HIDDEN;
extern TEB *thread_init(void) DECLSPEC_HIDDEN;
......@@ -116,8 +109,6 @@ extern BOOL is_wow64 DECLSPEC_HIDDEN;
extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN;
extern void server_init_process(void) DECLSPEC_HIDDEN;
extern void server_init_process_done(void) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN;
extern sigset_t server_block_set DECLSPEC_HIDDEN;
extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
......
......@@ -127,7 +127,7 @@ static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
vfprintf( stderr, err, args );
va_end( args );
abort_thread(1);
for (;;) unix_funcs->abort_thread(1);
}
......@@ -138,7 +138,7 @@ static DECLSPEC_NORETURN void server_protocol_perror( const char *err )
{
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
perror( err );
abort_thread(1);
for (;;) unix_funcs->abort_thread(1);
}
......@@ -205,7 +205,7 @@ static int wait_select_reply( void *cookie )
ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) );
if (ret == sizeof(reply))
{
if (!reply.cookie) abort_thread( reply.signaled ); /* thread got killed */
if (!reply.cookie) unix_funcs->abort_thread( reply.signaled ); /* thread got killed */
if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled;
/* we stole another reply, wait for the real one */
signaled = wait_select_reply( cookie );
......@@ -714,7 +714,7 @@ void server_init_process(void)
void server_init_process_done(void)
{
#ifdef __i386__
extern struct ldt_copy __wine_ldt_copy;
extern struct ldt_copy *__wine_ldt_copy;
#endif
PEB *peb = NtCurrentTeb()->Peb;
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress );
......@@ -737,7 +737,7 @@ void server_init_process_done(void)
{
req->module = wine_server_client_ptr( peb->ImageBaseAddress );
#ifdef __i386__
req->ldt_copy = wine_server_client_ptr( &__wine_ldt_copy );
req->ldt_copy = wine_server_client_ptr( __wine_ldt_copy );
#endif
req->entry = wine_server_client_ptr( entry );
req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI);
......
......@@ -55,7 +55,6 @@
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h"
#include "ntdll_misc.h"
#include "wine/debug.h"
......@@ -64,8 +63,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh);
WINE_DECLARE_DEBUG_CHANNEL(relay);
static pthread_key_t teb_key;
/***********************************************************************
* signal context platform-specific definitions
*/
......@@ -921,7 +918,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
abort_thread(0);
unix_funcs->abort_thread(0);
}
......@@ -953,46 +950,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__)
/* Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register. */
__asm__ __volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb) );
#endif
pthread_setspecific( teb_key, teb );
}
/**********************************************************************
* signal_init_process
*/
void signal_init_process(void)
......@@ -1163,16 +1120,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"mov r0, sp\n\t"
"b " __ASM_NAME("set_cpu_context") )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
".arm\n\t"
"ldr r3, [r2, #0x1d4]\n\t" /* teb->SystemReserved2 */
"mov ip, #0\n\t"
"str ip, [r2, #0x1d4]\n\t"
"cmp r3, ip\n\t"
"movne sp, r3\n\t"
"blx r1" )
/***********************************************************************
* init_thread_context
*/
......@@ -1239,39 +1186,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() );
}
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread, NtCurrentTeb() );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit, NtCurrentTeb() );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* DbgBreakPoint (NTDLL.@)
*/
......@@ -1293,7 +1207,7 @@ void WINAPI DbgUserBreakPoint(void)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
return unix_funcs->NtCurrentTeb();
}
#endif /* __arm__ */
......@@ -58,7 +58,6 @@
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h"
#include "ntdll_misc.h"
#include "wine/debug.h"
......@@ -67,8 +66,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh);
WINE_DECLARE_DEBUG_CHANNEL(relay);
static pthread_key_t teb_key;
/* layering violation: the setjmp buffer is defined in msvcrt, but used by RtlUnwindEx */
struct MSVCRT_JUMP_BUFFER
{
......@@ -1261,7 +1258,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
abort_thread(0);
unix_funcs->abort_thread(0);
}
......@@ -1308,51 +1305,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
stack_t ss;
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack( &ss, NULL ) == -1) perror( "sigaltstack" );
/* Win64/ARM applications expect the TEB pointer to be in the x18 platform register. */
__asm__ __volatile__( "mov x18, %0" : : "r" (teb) );
pthread_setspecific( teb_key, teb );
}
/**********************************************************************
* signal_init_process
*/
void signal_init_process(void)
......@@ -2208,14 +2160,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"ldr x0, [x0, #0x8]\n\t" /* context->X0 */
"br x17" )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
"ldr x3, [x2, #0x300]\n\t" /* arm64_thread_data()->exit_frame */
"str xzr, [x2, #0x300]\n\t"
"cbz x3, 1f\n\t"
"mov sp, x3\n"
"1:\tblr x1" )
/***********************************************************************
* init_thread_context
*/
......@@ -2281,39 +2225,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() );
}
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread, NtCurrentTeb() );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit, NtCurrentTeb() );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* DbgBreakPoint (NTDLL.@)
*/
......@@ -2329,7 +2240,7 @@ __ASM_STDCALL_FUNC( DbgUserBreakPoint, 0, "brk #0; ret")
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
return unix_funcs->NtCurrentTeb();
}
#endif /* __aarch64__ */
......@@ -53,7 +53,6 @@
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h"
#include "ntdll_misc.h"
#include "wine/debug.h"
......@@ -61,8 +60,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(seh);
WINE_DECLARE_DEBUG_CHANNEL(relay);
static pthread_key_t teb_key;
/***********************************************************************
* signal context platform-specific definitions
*/
......@@ -982,7 +979,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
abort_thread(0);
unix_funcs->abort_thread(0);
}
......@@ -1014,41 +1011,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
pthread_setspecific( teb_key, teb );
}
/**********************************************************************
* signal_init_process
*/
void signal_init_process(void)
......@@ -1218,39 +1180,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
switch_to_stack( thread_startup, &info, NtCurrentTeb()->Tib.StackBase );
}
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
exit_thread( status );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
exit( status );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* DbgBreakPoint (NTDLL.@)
*/
......@@ -1272,7 +1201,7 @@ void WINAPI DbgUserBreakPoint(void)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
return unix_funcs->NtCurrentTeb();
}
#endif /* __powerpc__ */
......@@ -65,7 +65,6 @@
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h"
#include "wine/list.h"
#include "ntdll_misc.h"
......@@ -123,9 +122,6 @@ struct MSVCRT_JUMP_BUFFER
*/
#ifdef linux
#include <asm/prctl.h>
static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
#define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX])
#define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX])
#define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX])
......@@ -2646,7 +2642,7 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n",
GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext),
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
unix_funcs->abort_thread(1);
}
if (stack - 1 > stack || /* check for overflow in subtraction */
......@@ -2665,7 +2661,7 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
unix_funcs->abort_thread(1);
}
else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit)
{
......@@ -2679,7 +2675,7 @@ static struct stack_layout *setup_exception( ucontext_t *sigcontext )
diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext),
(ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
abort_thread(1);
unix_funcs->abort_thread(1);
}
case -1: /* overflow */
exception_code = EXCEPTION_STACK_OVERFLOW;
......@@ -3075,7 +3071,7 @@ static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
*/
static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext )
{
abort_thread(0);
unix_funcs->abort_thread(0);
}
......@@ -3107,145 +3103,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
#ifdef __APPLE__
/**********************************************************************
* mac_thread_gsbase
*/
static void *mac_thread_gsbase(void)
{
struct thread_identifier_info tiinfo;
unsigned int info_count = THREAD_IDENTIFIER_INFO_COUNT;
static int gsbase_offset = -1;
void *ret;
kern_return_t kr = thread_info(mach_thread_self(), THREAD_IDENTIFIER_INFO, (thread_info_t) &tiinfo, &info_count);
if (kr == KERN_SUCCESS)
{
TRACE("pthread_self() %p thread ID %llx gsbase %llx\n", pthread_self(), tiinfo.thread_id, tiinfo.thread_handle);
return (void*)tiinfo.thread_handle;
}
if (gsbase_offset < 0)
{
/* Search for the array of TLS slots within the pthread data structure.
That's what the macOS pthread implementation uses for gsbase. */
const void* const sentinel1 = (const void*)0x2bffb6b4f11228ae;
const void* const sentinel2 = (const void*)0x0845a7ff6ab76707;
int rc;
pthread_key_t key;
const void** p = (const void**)pthread_self();
int i;
gsbase_offset = 0;
if ((rc = pthread_key_create(&key, NULL)))
{
ERR("failed to create sentinel key for gsbase search: %d\n", rc);
return NULL;
}
pthread_setspecific(key, sentinel1);
for (i = key + 1; i < 2000; i++) /* arbitrary limit */
{
if (p[i] == sentinel1)
{
pthread_setspecific(key, sentinel2);
if (p[i] == sentinel2)
{
gsbase_offset = (i - key) * sizeof(*p);
break;
}
pthread_setspecific(key, sentinel1);
}
}
pthread_key_delete(key);
}
if (gsbase_offset)
{
ret = (char*)pthread_self() + gsbase_offset;
TRACE("pthread_self() %p + offset 0x%08x -> gsbase %p\n", pthread_self(), gsbase_offset, ret);
}
else
{
ret = NULL;
ERR("failed to locate gsbase; won't be able to poke ThreadLocalStoragePointer into pthread TLS; expect crashes\n");
}
return ret;
}
#endif
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
const WORD fpu_cw = 0x27f;
stack_t ss;
#if defined __linux__
arch_prctl( ARCH_SET_GS, teb );
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
amd64_set_gsbase( teb );
#elif defined(__NetBSD__)
sysarch( X86_64_SET_GSBASE, &teb );
#elif defined (__APPLE__)
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->Tib.Self), "n" (FIELD_OFFSET(TEB, Tib.Self)));
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->ThreadLocalStoragePointer), "n" (FIELD_OFFSET(TEB, ThreadLocalStoragePointer)));
/* alloc_tls_slot() needs to poke a value to an address relative to each
thread's gsbase. Have each thread record its gsbase pointer into its
TEB so alloc_tls_slot() can find it. */
teb->Reserved5[0] = mac_thread_gsbase();
#else
# error Please define setting %gs for your architecture
#endif
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
#ifdef __GNUC__
__asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
/**********************************************************************
* signal_init_process
*/
void signal_init_process(void)
......@@ -4150,27 +4007,6 @@ __ASM_GLOBAL_FUNC( start_thread,
"movq %rsp,%rdi\n\t"
"call " __ASM_NAME("set_cpu_context") )
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int) );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
/* fetch exit frame */
"movq %gs:0x30,%rax\n\t"
"movq 0x330(%rax),%rdx\n\t" /* amd64_thread_data()->exit_frame */
"testq %rdx,%rdx\n\t"
"jnz 1f\n\t"
"jmp *%rsi\n"
/* switch to exit frame stack */
"1:\tmovq $0,0x330(%rax)\n\t"
"movq %rdx,%rsp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 56\n\t")
__ASM_CFI(".cfi_rel_offset %rbp,48\n\t")
__ASM_CFI(".cfi_rel_offset %rbx,40\n\t")
__ASM_CFI(".cfi_rel_offset %r12,32\n\t")
__ASM_CFI(".cfi_rel_offset %r13,24\n\t")
__ASM_CFI(".cfi_rel_offset %r14,16\n\t")
__ASM_CFI(".cfi_rel_offset %r15,8\n\t")
"call *%rsi" )
/***********************************************************************
* init_thread_context
*/
......@@ -4245,39 +4081,6 @@ void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
}
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status )
{
call_thread_exit_func( status, exit_thread );
}
/***********************************************************************
* signal_exit_process
*/
void signal_exit_process( int status )
{
call_thread_exit_func( status, exit );
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* DbgBreakPoint (NTDLL.@)
*/
......
......@@ -71,6 +71,8 @@ static RTL_BITMAP tls_expansion_bitmap;
static RTL_BITMAP fls_bitmap;
static int nb_threads = 1;
struct ldt_copy *__wine_ldt_copy = NULL;
static RTL_CRITICAL_SECTION peb_lock;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
......@@ -243,6 +245,10 @@ TEB *thread_init(void)
/* allocate and initialize the PEB and initial TEB */
teb = virtual_alloc_first_teb();
unix_funcs->init_threading( &nb_threads, &__wine_ldt_copy );
unix_funcs->alloc_thread( teb );
unix_funcs->init_thread( teb );
peb = teb->Peb;
peb->FastPebLock = &peb_lock;
peb->TlsBitmap = &tls_bitmap;
......@@ -287,30 +293,6 @@ TEB *thread_init(void)
/***********************************************************************
* abort_thread
*/
void abort_thread( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
if (InterlockedDecrement( &nb_threads ) <= 0) _exit( get_unix_exit_code( status ));
signal_exit_thread( status );
}
/***********************************************************************
* exit_thread
*/
void exit_thread( int status )
{
close( ntdll_get_thread_data()->wait_fd[0] );
close( ntdll_get_thread_data()->wait_fd[1] );
close( ntdll_get_thread_data()->reply_fd );
close( ntdll_get_thread_data()->request_fd );
pthread_exit( UIntToPtr(status) );
}
/***********************************************************************
* RtlExitUserThread (NTDLL.@)
*/
void WINAPI RtlExitUserThread( ULONG status )
......@@ -332,8 +314,7 @@ void WINAPI RtlExitUserThread( ULONG status )
if (InterlockedDecrement( &nb_threads ) <= 0)
{
LdrShutdownProcess();
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
signal_exit_process( get_unix_exit_code( status ));
unix_funcs->exit_process( status );
}
LdrShutdownThread();
......@@ -352,7 +333,7 @@ void WINAPI RtlExitUserThread( ULONG status )
}
}
signal_exit_thread( status );
for (;;) unix_funcs->exit_thread( status );
}
......@@ -372,7 +353,7 @@ static void start_thread( struct startup_info *info )
thread_data->debug_info = &debug_info;
thread_data->pthread_id = pthread_self();
signal_init_thread( teb );
unix_funcs->init_thread( teb );
unix_funcs->server_init_thread( info->entry_point, &suspend, NULL, NULL, NULL );
signal_start_thread( (LPTHREAD_START_ROUTINE)info->entry_point, info->entry_arg, suspend );
}
......@@ -667,7 +648,7 @@ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
}
SERVER_END_REQ;
}
if (self) abort_thread( exit_code );
if (self) unix_funcs->abort_thread( exit_code );
return ret;
}
......@@ -787,6 +768,16 @@ NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int fla
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return unix_funcs->NtSetLdtEntries( sel1, entry1, sel2, entry2 );
}
/******************************************************************************
* NtQueryInformationThread (NTDLL.@)
* ZwQueryInformationThread (NTDLL.@)
*/
......@@ -894,7 +885,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
return status;
case ThreadDescriptorTableEntry:
return get_thread_ldt_entry( handle, data, length, ret_len );
return unix_funcs->get_thread_ldt_entry( handle, data, length, ret_len );
case ThreadAmILastThread:
{
......
......@@ -984,7 +984,9 @@ static HMODULE load_ntdll(void)
static struct unix_funcs unix_funcs =
{
NtClose,
NtCurrentTeb,
NtDuplicateObject,
NtSetLdtEntries,
get_main_args,
get_paths,
get_dll_path,
......@@ -998,6 +1000,14 @@ static struct unix_funcs unix_funcs =
mmap_remove_reserved_area,
mmap_is_in_reserved_area,
mmap_enum_reserved_areas,
init_threading,
alloc_thread,
free_thread,
init_thread,
abort_thread,
exit_thread,
exit_process,
get_thread_ldt_entry,
server_call_unlocked,
wine_server_call,
server_send_fd,
......
......@@ -190,7 +190,7 @@ static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
vfprintf( stderr, err, args );
va_end( args );
exit(1);
abort_thread(1);
}
......@@ -201,7 +201,7 @@ static DECLSPEC_NORETURN void server_protocol_perror( const char *err )
{
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
perror( err );
exit(1);
abort_thread(1);
}
......@@ -237,7 +237,7 @@ static unsigned int send_request( const struct __server_request_info *req )
}
if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
if (errno == EPIPE) NtTerminateThread( GetCurrentThread(), 0 );
if (errno == EPIPE) abort_thread(0);
if (errno == EFAULT) return STATUS_ACCESS_VIOLATION;
server_protocol_perror( "write" );
}
......@@ -266,7 +266,7 @@ static void read_reply_data( void *buffer, size_t size )
server_protocol_perror("read");
}
/* the server closed the connection; time to die... */
for (;;) NtTerminateThread( GetCurrentThread(), 0 );
abort_thread(0);
}
......@@ -379,7 +379,7 @@ void CDECL server_send_fd( int fd )
if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return;
if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
if (errno == EINTR) continue;
if (errno == EPIPE) NtTerminateThread( GetCurrentThread(), 0 );
if (errno == EPIPE) abort_thread(0);
server_protocol_perror( "sendmsg" );
}
}
......@@ -441,7 +441,7 @@ static int receive_fd( obj_handle_t *handle )
server_protocol_perror("recvmsg");
}
/* the server closed the connection; time to die... */
for (;;) NtTerminateThread( GetCurrentThread(), 0 );
abort_thread(0);
}
......
/*
* ARM signal handling routines
*
* Copyright 2002 Marcus Meissner, SuSE Linux AG
* Copyright 2010-2013, 2015 André Hentschel
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __arm__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winnt.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
static pthread_key_t teb_key;
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__)
/* Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register. */
__asm__ __volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb) );
#endif
pthread_setspecific( teb_key, teb );
}
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
".arm\n\t"
"ldr r3, [r2, #0x1d4]\n\t" /* teb->SystemReserved2 */
"mov ip, #0\n\t"
"str ip, [r2, #0x1d4]\n\t"
"cmp r3, ip\n\t"
"movne sp, r3\n\t"
"blx r1" )
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status, void (*func)(int) )
{
call_thread_exit_func( status, func, NtCurrentTeb() );
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
}
#endif /* __arm__ */
/*
* ARM64 signal handling routines
*
* Copyright 2010-2013 André Hentschel
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __aarch64__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
# include <libunwind.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winnt.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
static pthread_key_t teb_key;
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
stack_t ss;
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack( &ss, NULL ) == -1) perror( "sigaltstack" );
/* Win64/ARM applications expect the TEB pointer to be in the x18 platform register. */
__asm__ __volatile__( "mov x18, %0" : : "r" (teb) );
pthread_setspecific( teb_key, teb );
}
extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
__ASM_GLOBAL_FUNC( call_thread_exit_func,
"ldr x3, [x2, #0x300]\n\t" /* arm64_thread_data()->exit_frame */
"str xzr, [x2, #0x300]\n\t"
"cbz x3, 1f\n\t"
"mov sp, x3\n"
"1:\tblr x1" )
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status, void (*func)(int) )
{
call_thread_exit_func( status, func, NtCurrentTeb() );
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
}
#endif /* __aarch64__ */
/*
* PowerPC signal handling routines
*
* Copyright 2002 Marcus Meissner, SuSE Linux AG
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __powerpc__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
static pthread_key_t teb_key;
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
pthread_key_create( &teb_key, NULL );
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
pthread_setspecific( teb_key, teb );
}
/***********************************************************************
* signal_exit_thread
*/
void signal_exit_thread( int status, void (*func)(int) )
{
func( status );
}
/**********************************************************************
* NtCurrentTeb (NTDLL.@)
*/
TEB * WINAPI NtCurrentTeb(void)
{
return pthread_getspecific( teb_key );
}
#endif /* __powerpc__ */
/*
* x86-64 signal handling routines
*
* Copyright 1999, 2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __x86_64__
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_MACHINE_SYSARCH_H
# include <machine/sysarch.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
# include <libunwind.h>
#endif
#ifdef __APPLE__
# include <mach/mach.h>
#endif
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"
#include "wine/exception.h"
#include "wine/list.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
/***********************************************************************
* signal context platform-specific definitions
*/
#ifdef linux
#include <asm/prctl.h>
static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); }
#endif
enum i386_trap_code
{
TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
TRAP_x86_DIVIDE = 0, /* Division by zero exception */
TRAP_x86_TRCTRAP = 1, /* Single-step exception */
TRAP_x86_NMI = 2, /* NMI interrupt */
TRAP_x86_BPTFLT = 3, /* Breakpoint exception */
TRAP_x86_OFLOW = 4, /* Overflow exception */
TRAP_x86_BOUND = 5, /* Bound range exception */
TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */
TRAP_x86_DNA = 7, /* Device not available exception */
TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */
TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */
TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */
TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */
TRAP_x86_STKFLT = 12, /* Stack fault */
TRAP_x86_PROTFLT = 13, /* General protection fault */
TRAP_x86_PAGEFLT = 14, /* Page fault */
TRAP_x86_ARITHTRAP = 16, /* Floating point exception */
TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */
TRAP_x86_MCHK = 18, /* Machine check exception */
TRAP_x86_CACHEFLT = 19 /* Cache flush exception */
};
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
#ifdef __APPLE__
/**********************************************************************
* mac_thread_gsbase
*/
static void *mac_thread_gsbase(void)
{
struct thread_identifier_info tiinfo;
unsigned int info_count = THREAD_IDENTIFIER_INFO_COUNT;
static int gsbase_offset = -1;
kern_return_t kr = thread_info(mach_thread_self(), THREAD_IDENTIFIER_INFO, (thread_info_t) &tiinfo, &info_count);
if (kr == KERN_SUCCESS) return (void*)tiinfo.thread_handle;
if (gsbase_offset < 0)
{
/* Search for the array of TLS slots within the pthread data structure.
That's what the macOS pthread implementation uses for gsbase. */
const void* const sentinel1 = (const void*)0x2bffb6b4f11228ae;
const void* const sentinel2 = (const void*)0x0845a7ff6ab76707;
int rc;
pthread_key_t key;
const void** p = (const void**)pthread_self();
int i;
gsbase_offset = 0;
if ((rc = pthread_key_create(&key, NULL))) return NULL;
pthread_setspecific(key, sentinel1);
for (i = key + 1; i < 2000; i++) /* arbitrary limit */
{
if (p[i] == sentinel1)
{
pthread_setspecific(key, sentinel2);
if (p[i] == sentinel2)
{
gsbase_offset = (i - key) * sizeof(*p);
break;
}
pthread_setspecific(key, sentinel1);
}
}
pthread_key_delete(key);
}
if (gsbase_offset) return (char*)pthread_self() + gsbase_offset;
return NULL;
}
#endif
/**********************************************************************
* signal_init_thread
*/
void signal_init_thread( TEB *teb )
{
const WORD fpu_cw = 0x27f;
stack_t ss;
#if defined __linux__
arch_prctl( ARCH_SET_GS, teb );
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
amd64_set_gsbase( teb );
#elif defined(__NetBSD__)
sysarch( X86_64_SET_GSBASE, &teb );
#elif defined (__APPLE__)
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->Tib.Self), "n" (FIELD_OFFSET(TEB, Tib.Self)));
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (teb->ThreadLocalStoragePointer), "n" (FIELD_OFFSET(TEB, ThreadLocalStoragePointer)));
/* alloc_tls_slot() needs to poke a value to an address relative to each
thread's gsbase. Have each thread record its gsbase pointer into its
TEB so alloc_tls_slot() can find it. */
teb->Reserved5[0] = mac_thread_gsbase();
#else
# error Please define setting %gs for your architecture
#endif
ss.ss_sp = (char *)teb + teb_size;
ss.ss_size = signal_stack_size;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) perror( "sigaltstack" );
#ifdef __GNUC__
__asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw));
#else
FIXME("FPU setup not implemented for this platform.\n");
#endif
}
/***********************************************************************
* signal_exit_thread
*/
__ASM_GLOBAL_FUNC( signal_exit_thread,
/* fetch exit frame */
"movq %gs:0x30,%rax\n\t"
"movq 0x330(%rax),%rdx\n\t" /* amd64_thread_data()->exit_frame */
"testq %rdx,%rdx\n\t"
"jnz 1f\n\t"
"jmp *%rsi\n"
/* switch to exit frame stack */
"1:\tmovq $0,0x330(%rax)\n\t"
"movq %rdx,%rsp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 56\n\t")
__ASM_CFI(".cfi_rel_offset %rbp,48\n\t")
__ASM_CFI(".cfi_rel_offset %rbx,40\n\t")
__ASM_CFI(".cfi_rel_offset %r12,32\n\t")
__ASM_CFI(".cfi_rel_offset %r13,24\n\t")
__ASM_CFI(".cfi_rel_offset %r14,16\n\t")
__ASM_CFI(".cfi_rel_offset %r15,8\n\t")
"call *%rsi" )
#endif /* __x86_64__ */
/*
* NT threads support
*
* Copyright 1996, 2003 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <limits.h>
#include <stdarg.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#define NONAMELESSUNION
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "winternl.h"
#include "ddk/wdm.h"
#include "wine/server.h"
#include "wine/debug.h"
#include "wine/exception.h"
#include "unix_private.h"
#ifndef PTHREAD_STACK_MIN
#define PTHREAD_STACK_MIN 16384
#endif
static int *nb_threads;
static inline int get_unix_exit_code( NTSTATUS status )
{
/* prevent a nonzero exit code to end up truncated to zero in unix */
if (status && !(status & 0xff)) return 1;
return status;
}
/***********************************************************************
* pthread_exit_wrapper
*/
static void pthread_exit_wrapper( int status )
{
close( ntdll_get_thread_data()->wait_fd[0] );
close( ntdll_get_thread_data()->wait_fd[1] );
close( ntdll_get_thread_data()->reply_fd );
close( ntdll_get_thread_data()->request_fd );
pthread_exit( UIntToPtr(status) );
}
/***********************************************************************
* init_threading
*/
void CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy )
{
#ifdef __i386__
extern struct ldt_copy __wine_ldt_copy;
*ldt_copy = &__wine_ldt_copy;
#endif
nb_threads = nb_threads_ptr;
signal_init_threading();
}
/***********************************************************************
* alloc_thread
*/
NTSTATUS CDECL alloc_thread( TEB *teb )
{
return signal_alloc_thread( teb );
}
/***********************************************************************
* free_thread
*/
void CDECL free_thread( TEB *teb )
{
signal_free_thread( teb );
}
/***********************************************************************
* init_thread
*/
void CDECL init_thread( TEB *teb )
{
signal_init_thread( teb );
}
/***********************************************************************
* abort_thread
*/
void CDECL abort_thread( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
if (InterlockedDecrement( nb_threads ) <= 0) _exit( get_unix_exit_code( status ));
signal_exit_thread( status, pthread_exit_wrapper );
}
/***********************************************************************
* exit_thread
*/
void CDECL exit_thread( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
signal_exit_thread( status, pthread_exit_wrapper );
}
/***********************************************************************
* exit_process
*/
void CDECL exit_process( int status )
{
pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
signal_exit_thread( get_unix_exit_code( status ), exit );
}
......@@ -75,11 +75,30 @@ extern void CDECL server_init_process(void) DECLSPEC_HIDDEN;
extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN;
extern size_t CDECL server_init_thread( void *entry_point, BOOL *suspend, unsigned int *cpus,
BOOL *wow64, timeout_t *start_time ) DECLSPEC_HIDDEN;
extern void CDECL init_threading( int *nb_threads, struct ldt_copy **ldt_copy ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void CDECL free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void CDECL init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN exit_process( int status ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN;
extern const char *data_dir DECLSPEC_HIDDEN;
extern const char *build_dir DECLSPEC_HIDDEN;
extern const char *config_dir DECLSPEC_HIDDEN;
extern sigset_t server_block_set DECLSPEC_HIDDEN;
extern SIZE_T signal_stack_size DECLSPEC_HIDDEN;
extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN;
extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
extern void start_server( BOOL debug ) DECLSPEC_HIDDEN;
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int) ) DECLSPEC_HIDDEN;
#endif /* __NTDLL_UNIX_PRIVATE_H */
......@@ -26,6 +26,7 @@
#include "wine/port.h"
#include <assert.h>
#include <signal.h>
#include <stdarg.h>
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
......@@ -62,9 +63,20 @@ struct reserved_area
static struct list reserved_areas = LIST_INIT(reserved_areas);
static const UINT page_shift = 12;
static const UINT_PTR page_mask = 0xfff;
static const unsigned int granularity_mask = 0xffff; /* reserved areas have 64k granularity */
extern IMAGE_NT_HEADERS __wine_spec_nt_header;
SIZE_T signal_stack_size = 0;
SIZE_T signal_stack_mask = 0;
static SIZE_T signal_stack_align;
#define ROUND_ADDR(addr,mask) \
((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask)))
#define ROUND_SIZE(addr,size) \
(((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0
......@@ -367,6 +379,7 @@ int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T si
void virtual_init(void)
{
const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" );
size_t size;
int i;
if (preload_info && *preload_info)
......@@ -374,4 +387,11 @@ void virtual_init(void)
mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size );
mmap_init( preload_info ? *preload_info : NULL );
size = ROUND_SIZE( 0, sizeof(TEB) ) + max( MINSIGSTKSZ, 8192 );
/* find the first power of two not smaller than size */
signal_stack_align = page_shift;
while ((1u << signal_stack_align) < size) signal_stack_align++;
signal_stack_mask = (1 << signal_stack_align) - 1;
signal_stack_size = (1 << signal_stack_align) - ROUND_SIZE( 0, sizeof(TEB) );
}
......@@ -24,16 +24,20 @@
#include "wine/server.h"
#include "wine/debug.h"
struct ldt_copy;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 11
#define NTDLL_UNIXLIB_VERSION 12
struct unix_funcs
{
/* Nt* functions */
NTSTATUS (WINAPI *NtClose)( HANDLE handle );
TEB * (WINAPI *NtCurrentTeb)(void);
NTSTATUS (WINAPI *NtDuplicateObject)( HANDLE source_process, HANDLE source,
HANDLE dest_process, HANDLE *dest,
ACCESS_MASK access, ULONG attributes, ULONG options );
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
/* environment functions */
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
......@@ -56,6 +60,16 @@ struct unix_funcs
int (CDECL *mmap_enum_reserved_areas)( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg),
void *arg, int top_down );
/* thread/process functions */
void (CDECL *init_threading)( int *nb_threads, struct ldt_copy **ldt_copy );
NTSTATUS (CDECL *alloc_thread)( TEB *teb );
void (CDECL *free_thread)( TEB *teb );
void (CDECL *init_thread)( TEB *teb );
void (CDECL *abort_thread)( int status );
void (CDECL *exit_thread)( int status );
void (CDECL *exit_process)( int status );
NTSTATUS (CDECL *get_thread_ldt_entry)( HANDLE handle, void *data, ULONG len, ULONG *ret_len );
/* server functions */
unsigned int (CDECL *server_call_unlocked)( void *req_ptr );
unsigned int (CDECL *server_call)( void *req_ptr );
......
......@@ -2284,9 +2284,6 @@ TEB *virtual_alloc_first_teb(void)
teb->Tib.StackBase = (void *)~0ul;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
signal_init_threading();
signal_alloc_thread( teb );
signal_init_thread( teb );
use_locks = TRUE;
return teb;
}
......@@ -2337,7 +2334,7 @@ NTSTATUS virtual_alloc_teb( TEB **ret_teb )
teb->Tib.ExceptionList = (void *)~0UL;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
if ((status = signal_alloc_thread( teb )))
if ((status = unix_funcs->alloc_thread( teb )))
{
server_enter_uninterrupted_section( &csVirtual, &sigset );
*(TEB **)teb = next_free_teb;
......@@ -2357,7 +2354,7 @@ void virtual_free_teb( TEB *teb )
SIZE_T size;
sigset_t sigset;
signal_free_thread( teb );
unix_funcs->free_thread( teb );
if (teb->DeallocationStack)
{
size = 0;
......
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