From 3e9f8c87e5a2acaa80f8bbb1d50fa82147942143 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 1 Jun 2020 12:52:05 +0200 Subject: [PATCH] ntdll: Move the threading initialization functions to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/krnl386.exe16/selector.c | 4 +- dlls/ntdll/Makefile.in | 6 + dlls/ntdll/ntdll_misc.h | 9 - dlls/ntdll/server.c | 10 +- dlls/ntdll/signal_arm.c | 90 +----- dlls/ntdll/signal_arm64.c | 93 +----- dlls/ntdll/signal_i386.c | 380 +---------------------- dlls/ntdll/signal_powerpc.c | 75 +---- dlls/ntdll/signal_x86_64.c | 205 +------------ dlls/ntdll/thread.c | 51 ++-- dlls/ntdll/unix/loader.c | 10 + dlls/ntdll/unix/server.c | 12 +- dlls/ntdll/unix/signal_arm.c | 157 ++++++++++ dlls/ntdll/unix/signal_arm64.c | 166 ++++++++++ dlls/ntdll/unix/signal_i386.c | 508 +++++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_powerpc.c | 140 +++++++++ dlls/ntdll/unix/signal_x86_64.c | 278 +++++++++++++++++ dlls/ntdll/unix/thread.c | 150 +++++++++ dlls/ntdll/unix/unix_private.h | 19 ++ dlls/ntdll/unix/virtual.c | 22 +- dlls/ntdll/unixlib.h | 16 +- dlls/ntdll/virtual.c | 7 +- 22 files changed, 1521 insertions(+), 887 deletions(-) create mode 100644 dlls/ntdll/unix/signal_arm.c create mode 100644 dlls/ntdll/unix/signal_arm64.c create mode 100644 dlls/ntdll/unix/signal_i386.c create mode 100644 dlls/ntdll/unix/signal_powerpc.c create mode 100644 dlls/ntdll/unix/signal_x86_64.c create mode 100644 dlls/ntdll/unix/thread.c diff --git a/dlls/krnl386.exe16/selector.c b/dlls/krnl386.exe16/selector.c index 94088276d69..26c86f06a9f 100644 --- a/dlls/krnl386.exe16/selector.c +++ b/dlls/krnl386.exe16/selector.c @@ -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; } /*********************************************************************** diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 643bcb64c38..ca195eba76a 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -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 \ diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 824e64f5122..264d9bd79c5 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -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; diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index ada5e16d4e0..3c3b0eb444c 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -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); diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 31280edce47..e66cf922f91 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -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); } @@ -952,46 +949,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 */ @@ -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__ */ diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index 7488b90d63a..c87f99f0c4c 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -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); } @@ -1307,51 +1304,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 */ @@ -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__ */ diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 5396037502f..2f2db70b57f 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -52,7 +52,6 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" -#include "wine/library.h" #include "ntdll_misc.h" #include "wine/exception.h" #include "wine/debug.h" @@ -182,30 +181,6 @@ __ASM_GLOBAL_FUNC( rt_sigreturn, "int $0x80" ); #endif -struct modify_ldt_s -{ - unsigned int entry_number; - void *base_addr; - unsigned int limit; - unsigned int seg_32bit : 1; - unsigned int contents : 2; - unsigned int read_exec_only : 1; - unsigned int limit_in_pages : 1; - unsigned int seg_not_present : 1; - unsigned int usable : 1; - unsigned int garbage : 25; -}; - -static inline int modify_ldt( int func, struct modify_ldt_s *ptr, unsigned long count ) -{ - return syscall( 123 /* SYS_modify_ldt */, func, ptr, count ); -} - -static inline int set_thread_area( struct modify_ldt_s *ptr ) -{ - return syscall( 243 /* SYS_set_thread_area */, ptr ); -} - #elif defined (__BSDI__) #include @@ -470,8 +445,6 @@ struct stack_layout typedef int (*wine_signal_handler)(unsigned int sig); -static const size_t teb_size = 4096; /* we reserve one page for the TEB */ - static ULONG first_ldt_entry = 32; static wine_signal_handler handlers[256]; @@ -1832,7 +1805,7 @@ static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), (unsigned int) ESP_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 */ @@ -1852,7 +1825,7 @@ static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), (unsigned int) ESP_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) { @@ -1866,7 +1839,7 @@ static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), (unsigned int) ESP_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; @@ -2264,7 +2237,7 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { WORD fs, gs; init_handler( sigcontext, &fs, &gs ); - abort_thread(0); + unix_funcs->abort_thread(0); } @@ -2297,314 +2270,6 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) } -/*********************************************************************** - * LDT support - */ - -#define LDT_SIZE 8192 - -#define LDT_FLAGS_DATA 0x13 /* Data segment */ -#define LDT_FLAGS_CODE 0x1b /* Code segment */ -#define LDT_FLAGS_32BIT 0x40 /* Segment is 32-bit (code or stack) */ -#define LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated */ - -struct ldt_copy -{ - void *base[LDT_SIZE]; - unsigned int limit[LDT_SIZE]; - unsigned char flags[LDT_SIZE]; -} __wine_ldt_copy; - -static WORD gdt_fs_sel; - -static RTL_CRITICAL_SECTION ldt_section; -static RTL_CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &ldt_section, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": ldt_section") } -}; -static RTL_CRITICAL_SECTION ldt_section = { &critsect_debug, -1, 0, 0, 0, 0 }; - -static const LDT_ENTRY null_entry; - -static inline void *ldt_get_base( LDT_ENTRY ent ) -{ - return (void *)(ent.BaseLow | - (ULONG_PTR)ent.HighWord.Bits.BaseMid << 16 | - (ULONG_PTR)ent.HighWord.Bits.BaseHi << 24); -} - -static inline unsigned int ldt_get_limit( LDT_ENTRY ent ) -{ - unsigned int limit = ent.LimitLow | (ent.HighWord.Bits.LimitHi << 16); - if (ent.HighWord.Bits.Granularity) limit = (limit << 12) | 0xfff; - return limit; -} - -static LDT_ENTRY ldt_make_entry( void *base, unsigned int limit, unsigned char flags ) -{ - LDT_ENTRY entry; - - entry.BaseLow = (WORD)(ULONG_PTR)base; - entry.HighWord.Bits.BaseMid = (BYTE)((ULONG_PTR)base >> 16); - entry.HighWord.Bits.BaseHi = (BYTE)((ULONG_PTR)base >> 24); - if ((entry.HighWord.Bits.Granularity = (limit >= 0x100000))) limit >>= 12; - entry.LimitLow = (WORD)limit; - entry.HighWord.Bits.LimitHi = limit >> 16; - entry.HighWord.Bits.Dpl = 3; - entry.HighWord.Bits.Pres = 1; - entry.HighWord.Bits.Type = flags; - entry.HighWord.Bits.Sys = 0; - entry.HighWord.Bits.Reserved_0 = 0; - entry.HighWord.Bits.Default_Big = (flags & LDT_FLAGS_32BIT) != 0; - return entry; -} - -static void ldt_set_entry( WORD sel, LDT_ENTRY entry ) -{ - int index = sel >> 3; - -#ifdef linux - struct modify_ldt_s ldt_info = { index }; - - ldt_info.base_addr = ldt_get_base( entry ); - ldt_info.limit = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16); - ldt_info.seg_32bit = entry.HighWord.Bits.Default_Big; - ldt_info.contents = (entry.HighWord.Bits.Type >> 2) & 3; - ldt_info.read_exec_only = !(entry.HighWord.Bits.Type & 2); - ldt_info.limit_in_pages = entry.HighWord.Bits.Granularity; - ldt_info.seg_not_present = !entry.HighWord.Bits.Pres; - ldt_info.usable = entry.HighWord.Bits.Sys; - if (modify_ldt( 0x11, &ldt_info, sizeof(ldt_info) ) < 0) perror( "modify_ldt" ); -#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) - /* The kernel will only let us set LDTs with user priority level */ - if (entry.HighWord.Bits.Pres && entry.HighWord.Bits.Dpl != 3) entry.HighWord.Bits.Dpl = 3; - if (i386_set_ldt(index, (union descriptor *)&entry, 1) < 0) - { - perror("i386_set_ldt"); - fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" ); - exit(1); - } -#elif defined(__svr4__) || defined(_SCO_DS) - struct ssd ldt_mod; - - ldt_mod.sel = sel; - ldt_mod.bo = (unsigned long)ldt_get_base( entry ); - ldt_mod.ls = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16); - ldt_mod.acc1 = entry.HighWord.Bytes.Flags1; - ldt_mod.acc2 = entry.HighWord.Bytes.Flags2 >> 4; - if (sysi86(SI86DSCR, &ldt_mod) == -1) perror("sysi86"); -#elif defined(__APPLE__) - if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt"); -#elif defined(__GNU__) - if (i386_set_ldt(mach_thread_self(), sel, (descriptor_list_t)&entry, 1) != KERN_SUCCESS) - perror("i386_set_ldt"); -#else - fprintf( stderr, "No LDT support on this platform\n" ); - exit(1); -#endif - - __wine_ldt_copy.base[index] = ldt_get_base( entry ); - __wine_ldt_copy.limit[index] = ldt_get_limit( entry ); - __wine_ldt_copy.flags[index] = (entry.HighWord.Bits.Type | - (entry.HighWord.Bits.Default_Big ? LDT_FLAGS_32BIT : 0) | - LDT_FLAGS_ALLOCATED); -} - -static void ldt_set_fs( WORD sel, TEB *teb ) -{ - if (sel == gdt_fs_sel) - { -#ifdef __linux__ - struct modify_ldt_s ldt_info = { sel >> 3 }; - - ldt_info.base_addr = teb; - ldt_info.limit = teb_size - 1; - ldt_info.seg_32bit = 1; - if (set_thread_area( &ldt_info ) < 0) perror( "set_thread_area" ); -#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__) - i386_set_fsbase( teb ); -#endif - } - set_fs( sel ); -} - - -/********************************************************************** - * get_thread_ldt_entry - */ -NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) -{ - THREAD_DESCRIPTOR_INFORMATION *info = data; - NTSTATUS status = STATUS_SUCCESS; - - if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH; - if (info->Selector >> 16) return STATUS_UNSUCCESSFUL; - - if (is_gdt_sel( info->Selector )) - { - if (!(info->Selector & ~3)) - info->Entry = null_entry; - else if ((info->Selector | 3) == get_cs()) - info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_CODE | LDT_FLAGS_32BIT ); - else if ((info->Selector | 3) == get_ds()) - info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_DATA | LDT_FLAGS_32BIT ); - else if ((info->Selector | 3) == get_fs()) - info->Entry = ldt_make_entry( NtCurrentTeb(), 0xfff, LDT_FLAGS_DATA | LDT_FLAGS_32BIT ); - else - return STATUS_UNSUCCESSFUL; - } - else - { - SERVER_START_REQ( get_selector_entry ) - { - req->handle = wine_server_obj_handle( handle ); - req->entry = info->Selector >> 3; - status = wine_server_call( req ); - if (!status) - { - if (reply->flags) - info->Entry = ldt_make_entry( (void *)reply->base, reply->limit, reply->flags ); - else - status = STATUS_UNSUCCESSFUL; - } - } - SERVER_END_REQ; - } - if (status == STATUS_SUCCESS && ret_len) - /* yes, that's a bit strange, but it's the way it is */ - *ret_len = sizeof(info->Entry); - - return status; -} - - -/****************************************************************************** - * NtSetLdtEntries (NTDLL.@) - * ZwSetLdtEntries (NTDLL.@) - */ -NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) -{ - sigset_t sigset; - - if (sel1 >> 16 || sel2 >> 16) return STATUS_INVALID_LDT_DESCRIPTOR; - if (sel1 && (sel1 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR; - if (sel2 && (sel2 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR; - - server_enter_uninterrupted_section( &ldt_section, &sigset ); - if (sel1) ldt_set_entry( sel1, entry1 ); - if (sel2) ldt_set_entry( sel2, entry2 ); - server_leave_uninterrupted_section( &ldt_section, &sigset ); - return STATUS_SUCCESS; -} - - -/********************************************************************** - * signal_init_threading - */ -void signal_init_threading(void) -{ -#ifdef __linux__ - /* the preloader may have allocated it already */ - gdt_fs_sel = get_fs(); - if (!gdt_fs_sel || !is_gdt_sel( gdt_fs_sel )) - { - struct modify_ldt_s ldt_info = { -1 }; - - ldt_info.seg_32bit = 1; - ldt_info.usable = 1; - if (set_thread_area( &ldt_info ) >= 0) gdt_fs_sel = (ldt_info.entry_number << 3) | 3; - else gdt_fs_sel = 0; - } -#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) - gdt_fs_sel = GSEL( GUFS_SEL, SEL_UPL ); -#endif -} - - -/********************************************************************** - * signal_alloc_thread - */ -NTSTATUS signal_alloc_thread( TEB *teb ) -{ - struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; - - if (!gdt_fs_sel) - { - static int first_thread = 1; - sigset_t sigset; - int idx; - LDT_ENTRY entry = ldt_make_entry( teb, teb_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT ); - - if (first_thread) /* no locking for first thread */ - { - /* leave some space if libc is using the LDT for %gs */ - if (!is_gdt_sel( get_gs() )) first_ldt_entry = 512; - idx = first_ldt_entry; - ldt_set_entry( (idx << 3) | 7, entry ); - first_thread = 0; - } - else - { - server_enter_uninterrupted_section( &ldt_section, &sigset ); - for (idx = first_ldt_entry; idx < LDT_SIZE; idx++) - { - if (__wine_ldt_copy.flags[idx]) continue; - ldt_set_entry( (idx << 3) | 7, entry ); - break; - } - server_leave_uninterrupted_section( &ldt_section, &sigset ); - if (idx == LDT_SIZE) return STATUS_TOO_MANY_THREADS; - } - thread_data->fs = (idx << 3) | 7; - } - else thread_data->fs = gdt_fs_sel; - - return STATUS_SUCCESS; -} - - -/********************************************************************** - * signal_free_thread - */ -void signal_free_thread( TEB *teb ) -{ - struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; - sigset_t sigset; - - if (gdt_fs_sel) return; - - server_enter_uninterrupted_section( &ldt_section, &sigset ); - __wine_ldt_copy.flags[thread_data->fs >> 3] = 0; - server_leave_uninterrupted_section( &ldt_section, &sigset ); -} - - -/********************************************************************** - * signal_init_thread - */ -void signal_init_thread( TEB *teb ) -{ - const WORD fpu_cw = 0x27f; - struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; - 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" ); - - ldt_set_fs( thread_data->fs, teb ); - thread_data->gs = get_gs(); - -#ifdef __GNUC__ - __asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw)); -#else - FIXME("FPU setup not implemented for this platform.\n"); -#endif -} - /********************************************************************** * signal_init_process */ @@ -2870,27 +2535,6 @@ __ASM_GLOBAL_FUNC( start_thread, "movl %esi,(%esp)\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, - "movl 8(%esp),%ecx\n\t" - /* fetch exit frame */ - "movl %fs:0x1f4,%edx\n\t" /* x86_thread_data()->exit_frame */ - "testl %edx,%edx\n\t" - "jnz 1f\n\t" - "jmp *%ecx\n\t" - /* switch to exit frame stack */ - "1:\tmovl 4(%esp),%eax\n\t" - "movl $0,%fs:0x1f4\n\t" - "movl %edx,%ebp\n\t" - __ASM_CFI(".cfi_def_cfa %ebp,4\n\t") - __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") - __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t") - __ASM_CFI(".cfi_rel_offset %esi,-8\n\t") - __ASM_CFI(".cfi_rel_offset %edi,-12\n\t") - "leal -20(%ebp),%esp\n\t" - "pushl %eax\n\t" - "call *%ecx" ) - extern void call_thread_entry(void) DECLSPEC_HIDDEN; __ASM_GLOBAL_FUNC( call_thread_entry, "pushl %ebp\n\t" @@ -3015,22 +2659,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 ); -} - /********************************************************************** * DbgBreakPoint (NTDLL.@) */ diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index 9df6eff31f4..a23f6b6e4d5 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -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); } @@ -1013,41 +1010,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 */ @@ -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__ */ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index e92470e9606..d42438f88af 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -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 -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); } @@ -3106,145 +3102,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 */ @@ -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.@) */ diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index fb5320603dc..785f3b99d47 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -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; @@ -286,30 +292,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.@) */ @@ -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; } @@ -786,6 +767,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: { diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index dfe6b6b1ad9..eeaa685d516 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -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, diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index d301da534ec..d5f2216fbdb 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -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); } diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c new file mode 100644 index 00000000000..de15851781b --- /dev/null +++ b/dlls/ntdll/unix/signal_arm.c @@ -0,0 +1,157 @@ +/* + * 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 +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYSCALL_H +# include +#else +# ifdef HAVE_SYS_SYSCALL_H +# include +# endif +#endif +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifdef HAVE_SYS_UCONTEXT_H +# include +#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__ */ diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c new file mode 100644 index 00000000000..0e69d77217a --- /dev/null +++ b/dlls/ntdll/unix/signal_arm64.c @@ -0,0 +1,166 @@ +/* + * 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 +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYSCALL_H +# include +#else +# ifdef HAVE_SYS_SYSCALL_H +# include +# endif +#endif +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifdef HAVE_SYS_UCONTEXT_H +# include +#endif +#ifdef HAVE_LIBUNWIND +# define UNW_LOCAL_ONLY +# include +#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__ */ diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c new file mode 100644 index 00000000000..9e56c99e547 --- /dev/null +++ b/dlls/ntdll/unix/signal_i386.c @@ -0,0 +1,508 @@ +/* + * i386 signal handling routines + * + * Copyright 1999 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 __i386__ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYSCALL_H +# include +#else +# ifdef HAVE_SYS_SYSCALL_H +# include +# endif +#endif +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifdef HAVE_SYS_UCONTEXT_H +# include +#endif + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "wine/asm.h" +#include "wine/exception.h" +#include "unix_private.h" +#include "wine/debug.h" + + +/*********************************************************************** + * signal context platform-specific definitions + */ + +#ifdef __linux__ + +struct modify_ldt_s +{ + unsigned int entry_number; + void *base_addr; + unsigned int limit; + unsigned int seg_32bit : 1; + unsigned int contents : 2; + unsigned int read_exec_only : 1; + unsigned int limit_in_pages : 1; + unsigned int seg_not_present : 1; + unsigned int usable : 1; + unsigned int garbage : 25; +}; + +static inline int modify_ldt( int func, struct modify_ldt_s *ptr, unsigned long count ) +{ + return syscall( 123 /* SYS_modify_ldt */, func, ptr, count ); +} + +static inline int set_thread_area( struct modify_ldt_s *ptr ) +{ + return syscall( 243 /* SYS_set_thread_area */, ptr ); +} + +#elif defined (__BSDI__) + +#include + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + +#include +#include +#include + +#elif defined (__OpenBSD__) + +#include +#include + +#elif defined(__svr4__) || defined(_SCO_DS) || defined(__sun) + +#if defined(_SCO_DS) || defined(__sun) +#include +#endif + +#elif defined (__APPLE__) + +#include + +#elif defined(__NetBSD__) + +#include +#include + +#elif defined(__GNU__) + +#include +#include + +#else +#error You must define the signal context functions for your platform +#endif /* linux */ + + +static const size_t teb_size = 4096; /* we reserve one page for the TEB */ +static ULONG first_ldt_entry = 32; + +struct x86_thread_data +{ + DWORD fs; /* 1d4 TEB selector */ + DWORD gs; /* 1d8 libc selector; update winebuild if you move this! */ + DWORD dr0; /* 1dc debug registers */ + DWORD dr1; /* 1e0 */ + DWORD dr2; /* 1e4 */ + DWORD dr3; /* 1e8 */ + DWORD dr6; /* 1ec */ + DWORD dr7; /* 1f0 */ + void *exit_frame; /* 1f4 exit frame pointer */ + /* the ntdll_thread_data structure follows here */ +}; + +C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct x86_thread_data, gs ) == 0x1d8 ); +C_ASSERT( offsetof( TEB, SystemReserved2 ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 ); + +static inline WORD get_cs(void) { WORD res; __asm__( "movw %%cs,%0" : "=r" (res) ); return res; } +static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; } +static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; } +static inline WORD get_gs(void) { WORD res; __asm__( "movw %%gs,%0" : "=r" (res) ); return res; } +static inline void set_fs( WORD val ) { __asm__( "mov %0,%%fs" :: "r" (val)); } + + +/*********************************************************************** + * is_gdt_sel + */ +static inline int is_gdt_sel( WORD sel ) +{ + return !(sel & 4); +} + + +/*********************************************************************** + * LDT support + */ + +#define LDT_SIZE 8192 + +#define LDT_FLAGS_DATA 0x13 /* Data segment */ +#define LDT_FLAGS_CODE 0x1b /* Code segment */ +#define LDT_FLAGS_32BIT 0x40 /* Segment is 32-bit (code or stack) */ +#define LDT_FLAGS_ALLOCATED 0x80 /* Segment is allocated */ + +struct ldt_copy +{ + void *base[LDT_SIZE]; + unsigned int limit[LDT_SIZE]; + unsigned char flags[LDT_SIZE]; +} __wine_ldt_copy; + +static WORD gdt_fs_sel; + +static RTL_CRITICAL_SECTION ldt_section; +static RTL_CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &ldt_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": ldt_section") } +}; +static RTL_CRITICAL_SECTION ldt_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static const LDT_ENTRY null_entry; + +static inline void *ldt_get_base( LDT_ENTRY ent ) +{ + return (void *)(ent.BaseLow | + (ULONG_PTR)ent.HighWord.Bits.BaseMid << 16 | + (ULONG_PTR)ent.HighWord.Bits.BaseHi << 24); +} + +static inline unsigned int ldt_get_limit( LDT_ENTRY ent ) +{ + unsigned int limit = ent.LimitLow | (ent.HighWord.Bits.LimitHi << 16); + if (ent.HighWord.Bits.Granularity) limit = (limit << 12) | 0xfff; + return limit; +} + +static LDT_ENTRY ldt_make_entry( void *base, unsigned int limit, unsigned char flags ) +{ + LDT_ENTRY entry; + + entry.BaseLow = (WORD)(ULONG_PTR)base; + entry.HighWord.Bits.BaseMid = (BYTE)((ULONG_PTR)base >> 16); + entry.HighWord.Bits.BaseHi = (BYTE)((ULONG_PTR)base >> 24); + if ((entry.HighWord.Bits.Granularity = (limit >= 0x100000))) limit >>= 12; + entry.LimitLow = (WORD)limit; + entry.HighWord.Bits.LimitHi = limit >> 16; + entry.HighWord.Bits.Dpl = 3; + entry.HighWord.Bits.Pres = 1; + entry.HighWord.Bits.Type = flags; + entry.HighWord.Bits.Sys = 0; + entry.HighWord.Bits.Reserved_0 = 0; + entry.HighWord.Bits.Default_Big = (flags & LDT_FLAGS_32BIT) != 0; + return entry; +} + +static void ldt_set_entry( WORD sel, LDT_ENTRY entry ) +{ + int index = sel >> 3; + +#ifdef linux + struct modify_ldt_s ldt_info = { index }; + + ldt_info.base_addr = ldt_get_base( entry ); + ldt_info.limit = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16); + ldt_info.seg_32bit = entry.HighWord.Bits.Default_Big; + ldt_info.contents = (entry.HighWord.Bits.Type >> 2) & 3; + ldt_info.read_exec_only = !(entry.HighWord.Bits.Type & 2); + ldt_info.limit_in_pages = entry.HighWord.Bits.Granularity; + ldt_info.seg_not_present = !entry.HighWord.Bits.Pres; + ldt_info.usable = entry.HighWord.Bits.Sys; + if (modify_ldt( 0x11, &ldt_info, sizeof(ldt_info) ) < 0) perror( "modify_ldt" ); +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__DragonFly__) + /* The kernel will only let us set LDTs with user priority level */ + if (entry.HighWord.Bits.Pres && entry.HighWord.Bits.Dpl != 3) entry.HighWord.Bits.Dpl = 3; + if (i386_set_ldt(index, (union descriptor *)&entry, 1) < 0) + { + perror("i386_set_ldt"); + fprintf( stderr, "Did you reconfigure the kernel with \"options USER_LDT\"?\n" ); + exit(1); + } +#elif defined(__svr4__) || defined(_SCO_DS) + struct ssd ldt_mod; + + ldt_mod.sel = sel; + ldt_mod.bo = (unsigned long)ldt_get_base( entry ); + ldt_mod.ls = entry.LimitLow | (entry.HighWord.Bits.LimitHi << 16); + ldt_mod.acc1 = entry.HighWord.Bytes.Flags1; + ldt_mod.acc2 = entry.HighWord.Bytes.Flags2 >> 4; + if (sysi86(SI86DSCR, &ldt_mod) == -1) perror("sysi86"); +#elif defined(__APPLE__) + if (i386_set_ldt(index, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt"); +#elif defined(__GNU__) + if (i386_set_ldt(mach_thread_self(), sel, (descriptor_list_t)&entry, 1) != KERN_SUCCESS) + perror("i386_set_ldt"); +#else + fprintf( stderr, "No LDT support on this platform\n" ); + exit(1); +#endif + + __wine_ldt_copy.base[index] = ldt_get_base( entry ); + __wine_ldt_copy.limit[index] = ldt_get_limit( entry ); + __wine_ldt_copy.flags[index] = (entry.HighWord.Bits.Type | + (entry.HighWord.Bits.Default_Big ? LDT_FLAGS_32BIT : 0) | + LDT_FLAGS_ALLOCATED); +} + +static void ldt_set_fs( WORD sel, TEB *teb ) +{ + if (sel == gdt_fs_sel) + { +#ifdef __linux__ + struct modify_ldt_s ldt_info = { sel >> 3 }; + + ldt_info.base_addr = teb; + ldt_info.limit = teb_size - 1; + ldt_info.seg_32bit = 1; + if (set_thread_area( &ldt_info ) < 0) perror( "set_thread_area" ); +#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__) + i386_set_fsbase( teb ); +#endif + } + set_fs( sel ); +} + + +/********************************************************************** + * get_thread_ldt_entry + */ +NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) +{ + THREAD_DESCRIPTOR_INFORMATION *info = data; + NTSTATUS status = STATUS_SUCCESS; + + if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH; + if (info->Selector >> 16) return STATUS_UNSUCCESSFUL; + + if (is_gdt_sel( info->Selector )) + { + if (!(info->Selector & ~3)) + info->Entry = null_entry; + else if ((info->Selector | 3) == get_cs()) + info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_CODE | LDT_FLAGS_32BIT ); + else if ((info->Selector | 3) == get_ds()) + info->Entry = ldt_make_entry( 0, ~0u, LDT_FLAGS_DATA | LDT_FLAGS_32BIT ); + else if ((info->Selector | 3) == get_fs()) + info->Entry = ldt_make_entry( NtCurrentTeb(), 0xfff, LDT_FLAGS_DATA | LDT_FLAGS_32BIT ); + else + return STATUS_UNSUCCESSFUL; + } + else + { + SERVER_START_REQ( get_selector_entry ) + { + req->handle = wine_server_obj_handle( handle ); + req->entry = info->Selector >> 3; + status = wine_server_call( req ); + if (!status) + { + if (reply->flags) + info->Entry = ldt_make_entry( (void *)reply->base, reply->limit, reply->flags ); + else + status = STATUS_UNSUCCESSFUL; + } + } + SERVER_END_REQ; + } + if (status == STATUS_SUCCESS && ret_len) + /* yes, that's a bit strange, but it's the way it is */ + *ret_len = sizeof(info->Entry); + + return status; +} + + +/****************************************************************************** + * NtSetLdtEntries (NTDLL.@) + * ZwSetLdtEntries (NTDLL.@) + */ +NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) +{ + sigset_t sigset; + + if (sel1 >> 16 || sel2 >> 16) return STATUS_INVALID_LDT_DESCRIPTOR; + if (sel1 && (sel1 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR; + if (sel2 && (sel2 >> 3) < first_ldt_entry) return STATUS_INVALID_LDT_DESCRIPTOR; + + server_enter_uninterrupted_section( &ldt_section, &sigset ); + if (sel1) ldt_set_entry( sel1, entry1 ); + if (sel2) ldt_set_entry( sel2, entry2 ); + server_leave_uninterrupted_section( &ldt_section, &sigset ); + return STATUS_SUCCESS; +} + + +/********************************************************************** + * signal_init_threading + */ +void signal_init_threading(void) +{ +#ifdef __linux__ + /* the preloader may have allocated it already */ + gdt_fs_sel = get_fs(); + if (!gdt_fs_sel || !is_gdt_sel( gdt_fs_sel )) + { + struct modify_ldt_s ldt_info = { -1 }; + + ldt_info.seg_32bit = 1; + ldt_info.usable = 1; + if (set_thread_area( &ldt_info ) >= 0) gdt_fs_sel = (ldt_info.entry_number << 3) | 3; + else gdt_fs_sel = 0; + } +#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) + gdt_fs_sel = GSEL( GUFS_SEL, SEL_UPL ); +#endif +} + + +/********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB *teb ) +{ + struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; + + if (!gdt_fs_sel) + { + static int first_thread = 1; + sigset_t sigset; + int idx; + LDT_ENTRY entry = ldt_make_entry( teb, teb_size - 1, LDT_FLAGS_DATA | LDT_FLAGS_32BIT ); + + if (first_thread) /* no locking for first thread */ + { + /* leave some space if libc is using the LDT for %gs */ + if (!is_gdt_sel( get_gs() )) first_ldt_entry = 512; + idx = first_ldt_entry; + ldt_set_entry( (idx << 3) | 7, entry ); + first_thread = 0; + } + else + { + server_enter_uninterrupted_section( &ldt_section, &sigset ); + for (idx = first_ldt_entry; idx < LDT_SIZE; idx++) + { + if (__wine_ldt_copy.flags[idx]) continue; + ldt_set_entry( (idx << 3) | 7, entry ); + break; + } + server_leave_uninterrupted_section( &ldt_section, &sigset ); + if (idx == LDT_SIZE) return STATUS_TOO_MANY_THREADS; + } + thread_data->fs = (idx << 3) | 7; + } + else thread_data->fs = gdt_fs_sel; + + return STATUS_SUCCESS; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; + sigset_t sigset; + + if (gdt_fs_sel) return; + + server_enter_uninterrupted_section( &ldt_section, &sigset ); + __wine_ldt_copy.flags[thread_data->fs >> 3] = 0; + server_leave_uninterrupted_section( &ldt_section, &sigset ); +} + + +/********************************************************************** + * signal_init_thread + */ +void signal_init_thread( TEB *teb ) +{ + const WORD fpu_cw = 0x27f; + struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; + 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" ); + + ldt_set_fs( thread_data->fs, teb ); + thread_data->gs = get_gs(); + +#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, + "movl 8(%esp),%ecx\n\t" + /* fetch exit frame */ + "movl %fs:0x1f4,%edx\n\t" /* x86_thread_data()->exit_frame */ + "testl %edx,%edx\n\t" + "jnz 1f\n\t" + "jmp *%ecx\n\t" + /* switch to exit frame stack */ + "1:\tmovl 4(%esp),%eax\n\t" + "movl $0,%fs:0x1f4\n\t" + "movl %edx,%ebp\n\t" + __ASM_CFI(".cfi_def_cfa %ebp,4\n\t") + __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") + __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t") + __ASM_CFI(".cfi_rel_offset %esi,-8\n\t") + __ASM_CFI(".cfi_rel_offset %edi,-12\n\t") + "leal -20(%ebp),%esp\n\t" + "pushl %eax\n\t" + "call *%ecx" ) + +/********************************************************************** + * NtCurrentTeb (NTDLL.@) + */ +__ASM_STDCALL_FUNC( NtCurrentTeb, 0, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" ) + +#endif /* __i386__ */ diff --git a/dlls/ntdll/unix/signal_powerpc.c b/dlls/ntdll/unix/signal_powerpc.c new file mode 100644 index 00000000000..246db2dcbd4 --- /dev/null +++ b/dlls/ntdll/unix/signal_powerpc.c @@ -0,0 +1,140 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYSCALL_H +# include +#else +# ifdef HAVE_SYS_SYSCALL_H +# include +# endif +#endif +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifdef HAVE_SYS_UCONTEXT_H +# include +#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__ */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c new file mode 100644 index 00000000000..cc3dcd6db3c --- /dev/null +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -0,0 +1,278 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_MACHINE_SYSARCH_H +# include +#endif +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYSCALL_H +# include +#else +# ifdef HAVE_SYS_SYSCALL_H +# include +# endif +#endif +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifdef HAVE_SYS_UCONTEXT_H +# include +#endif +#ifdef HAVE_LIBUNWIND +# define UNW_LOCAL_ONLY +# include +#endif +#ifdef __APPLE__ +# include +#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 +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__ */ diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c new file mode 100644 index 00000000000..0ff64198b24 --- /dev/null +++ b/dlls/ntdll/unix/thread.c @@ -0,0 +1,150 @@ +/* + * 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 +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#ifdef HAVE_SYS_TIMES_H +#include +#endif +#ifdef HAVE_SYS_SYSCALL_H +#include +#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 ); +} diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 30b130aa373..8ea316c10b9 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -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 */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 8fa43a40e6e..f3cc2fbc4e3 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -26,6 +26,7 @@ #include "wine/port.h" #include +#include #include #ifdef HAVE_SYS_MMAN_H # include @@ -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) ); } diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 4af2dbe31fa..9b61ff6d4f3 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -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 ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index abad3b8a7d1..73f95b91553 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -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;