diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index be6c770afe5..f74007b4db3 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -59,9 +59,10 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl const LARGE_INTEGER *timeout, HANDLE signal_object ); /* init routines */ +extern NTSTATUS signal_alloc_thread( TEB **teb ); +extern void signal_free_thread( TEB *teb ); extern void signal_init_thread( TEB *teb ); extern void signal_init_process(void); -extern size_t get_signal_stack_total_size(void); extern void version_init( const WCHAR *appname ); extern void debug_init(void); extern HANDLE thread_init(void); diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 79e38062955..9ec739c9163 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1995,26 +1995,6 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } -/********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. - */ -size_t get_signal_stack_total_size(void) -{ - if (!signal_stack_size) - { - size_t size = 8192, min_size = teb_size + max( MINSIGSTKSZ, 8192 ); - /* find the first power of two not smaller than min_size */ - while (size < min_size) size *= 2; - signal_stack_mask = size - 1; - signal_stack_size = size - teb_size; - } - return signal_stack_size + teb_size; -} - - /*********************************************************************** * __wine_set_signal_handler (NTDLL.@) */ @@ -2027,6 +2007,65 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) } +/********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB **teb ) +{ + static size_t sigstack_zero_bits; + struct ntdll_thread_data *thread_data; + SIZE_T size; + void *addr = NULL; + NTSTATUS status; + + if (!sigstack_zero_bits) + { + size_t min_size = teb_size + max( MINSIGSTKSZ, 8192 ); + /* find the first power of two not smaller than min_size */ + sigstack_zero_bits = 12; + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + signal_stack_mask = (1 << sigstack_zero_bits) - 1; + signal_stack_size = (1 << sigstack_zero_bits) - teb_size; + } + + size = signal_stack_mask + 1; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + *teb = addr; + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + thread_data = (struct ntdll_thread_data *)(*teb)->SystemReserved2; + if (!(thread_data->fs = wine_ldt_alloc_fs())) + { + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); + status = STATUS_TOO_MANY_THREADS; + } + } + return status; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + SIZE_T size; + struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + + if (thread_data) wine_ldt_free_fs( thread_data->fs ); + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); +} + + /********************************************************************** * signal_init_thread */ diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index a1a6ccc3f91..662d97ba91d 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -965,19 +965,6 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } -/********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. - */ -size_t get_signal_stack_total_size(void) -{ - assert( sizeof(TEB) <= getpagesize() ); - return getpagesize(); /* this is just for the TEB, we don't need a signal stack */ -} - - /*********************************************************************** * __wine_set_signal_handler (NTDLL.@) */ @@ -990,6 +977,52 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) } +/********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB **teb ) +{ + static size_t sigstack_zero_bits; + SIZE_T size; + NTSTATUS status; + + if (!sigstack_zero_bits) + { + size_t min_size = getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */ + /* find the first power of two not smaller than min_size */ + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + assert( sizeof(TEB) <= min_size ); + } + + size = 1 << sigstack_zero_bits; + *teb = NULL; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + } + return status; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + SIZE_T size; + + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); +} + + /********************************************************************** * signal_init_thread */ diff --git a/dlls/ntdll/signal_sparc.c b/dlls/ntdll/signal_sparc.c index 2952f8ed4a6..660bc9c89d1 100644 --- a/dlls/ntdll/signal_sparc.c +++ b/dlls/ntdll/signal_sparc.c @@ -700,19 +700,6 @@ static void usr1_handler( int signal, struct siginfo *info, void *ucontext ) } -/********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. - */ -size_t get_signal_stack_total_size(void) -{ - assert( sizeof(TEB) <= getpagesize() ); - return getpagesize(); /* this is just for the TEB, we don't need a signal stack */ -} - - /*********************************************************************** * __wine_set_signal_handler (NTDLL.@) */ @@ -725,6 +712,52 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) } +/********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB **teb ) +{ + static size_t sigstack_zero_bits; + SIZE_T size; + NTSTATUS status; + + if (!sigstack_zero_bits) + { + size_t min_size = getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */ + /* find the first power of two not smaller than min_size */ + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + assert( sizeof(TEB) <= min_size ); + } + + size = 1 << sigstack_zero_bits; + *teb = NULL; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + } + return status; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + SIZE_T size; + + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); +} + + /********************************************************************** * signal_init_thread */ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 7e6c6347858..94ec742f162 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -2191,26 +2191,6 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext ) } -/********************************************************************** - * get_signal_stack_total_size - * - * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. - * Must be a power of two. - */ -size_t get_signal_stack_total_size(void) -{ - assert( sizeof(TEB) <= teb_size ); - if (!signal_stack_size) - { - size_t size = 8192, min_size = teb_size + max( MINSIGSTKSZ, 8192 ); - /* find the first power of two not smaller than min_size */ - while (size < min_size) size *= 2; - signal_stack_size = size - teb_size; - } - return signal_stack_size + teb_size; -} - - /*********************************************************************** * __wine_set_signal_handler (NTDLL.@) */ @@ -2223,6 +2203,54 @@ int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) } +/********************************************************************** + * signal_alloc_thread + */ +NTSTATUS signal_alloc_thread( TEB **teb ) +{ + static size_t sigstack_zero_bits; + SIZE_T size; + NTSTATUS status; + + if (!sigstack_zero_bits) + { + size_t min_size = teb_size + max( MINSIGSTKSZ, 8192 ); + /* find the first power of two not smaller than min_size */ + sigstack_zero_bits = 12; + while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++; + signal_stack_size = (1 << sigstack_zero_bits) - teb_size; + assert( sizeof(TEB) <= teb_size ); + } + + size = 1 << sigstack_zero_bits; + *teb = NULL; + if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits, + &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) + { + (*teb)->Tib.Self = &(*teb)->Tib; + (*teb)->Tib.ExceptionList = (void *)~0UL; + } + return status; +} + + +/********************************************************************** + * signal_free_thread + */ +void signal_free_thread( TEB *teb ) +{ + SIZE_T size; + + if (teb->DeallocationStack) + { + size = 0; + NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); + } + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); +} + + /********************************************************************** * signal_init_thread */ diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 30a299db0e0..1c8a617a731 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -64,8 +64,6 @@ static RTL_BITMAP tls_bitmap; static RTL_BITMAP tls_expansion_bitmap; static RTL_BITMAP fls_bitmap; static LIST_ENTRY tls_links; -static size_t sigstack_total_size; -static ULONG sigstack_zero_bits; static int nb_threads = 1; static RTL_CRITICAL_SECTION ldt_section; @@ -102,29 +100,6 @@ static void ldt_unlock(void) } -/*********************************************************************** - * init_teb - */ -static inline NTSTATUS init_teb( TEB *teb ) -{ - struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - - teb->Tib.ExceptionList = (void *)~0UL; - teb->Tib.StackBase = (void *)~0UL; - teb->Tib.Self = &teb->Tib; - teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; - teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); - - if (!(thread_data->fs = wine_ldt_alloc_fs())) return STATUS_TOO_MANY_THREADS; - thread_data->request_fd = -1; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; - thread_data->wait_fd[1] = -1; - - return STATUS_SUCCESS; -} - - /*********************************************************************** * get_unicode_string * @@ -297,19 +272,17 @@ HANDLE thread_init(void) /* allocate and initialize the initial TEB */ - sigstack_total_size = get_signal_stack_total_size(); - while (1U << sigstack_zero_bits < sigstack_total_size) sigstack_zero_bits++; - assert( 1U << sigstack_zero_bits == sigstack_total_size ); /* must be a power of 2 */ - assert( sigstack_total_size >= sizeof(TEB) + sizeof(struct startup_info) ); - - addr = NULL; - size = sigstack_total_size; - NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits, - &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ); - teb = addr; + signal_alloc_thread( &teb ); teb->Peb = peb; - init_teb( teb ); + teb->Tib.StackBase = (void *)~0UL; + teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; thread_data->debug_info = &debug_info; InsertHeadList( &tls_links, &teb->TlsLinks ); @@ -417,14 +390,9 @@ void exit_thread( int status ) if ((teb = interlocked_xchg_ptr( &prev_teb, NtCurrentTeb() ))) { struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; - SIZE_T size; pthread_join( thread_data->pthread_id, NULL ); - wine_ldt_free_fs( thread_data->fs ); - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); - size = 0; - NtFreeVirtualMemory( GetCurrentProcess(), (void **)&teb, &size, MEM_RELEASE ); + signal_free_thread( teb ); } close( ntdll_get_thread_data()->wait_fd[0] ); @@ -482,16 +450,14 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * sigset_t sigset; pthread_t pthread_id; pthread_attr_t attr; - struct ntdll_thread_data *thread_data = NULL; + struct ntdll_thread_data *thread_data; struct ntdll_thread_regs *thread_regs; struct startup_info *info = NULL; - void *addr = NULL; HANDLE handle = 0; - TEB *teb; + TEB *teb = NULL; DWORD tid = 0; int request_pipe[2]; NTSTATUS status; - SIZE_T size; if (process != NtCurrentProcess()) { @@ -544,26 +510,25 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset ); - addr = NULL; - size = sigstack_total_size; - if ((status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits, - &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE ))) - goto error; - teb = addr; + if ((status = signal_alloc_thread( &teb ))) goto error; + teb->Peb = NtCurrentTeb()->Peb; + teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId()); + teb->ClientId.UniqueThread = ULongToHandle(tid); + teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + info = (struct startup_info *)(teb + 1); info->teb = teb; info->entry_point = start; info->entry_arg = param; - if ((status = init_teb( teb ))) goto error; - - teb->ClientId.UniqueProcess = ULongToHandle(GetCurrentProcessId()); - teb->ClientId.UniqueThread = ULongToHandle(tid); - thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1; thread_data->request_fd = request_pipe[1]; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; /* inherit debug registers from parent thread */ thread_regs->dr0 = ntdll_get_thread_regs()->dr0; @@ -584,8 +549,6 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * { interlocked_xchg_add( &nb_threads, -1 ); pthread_attr_destroy( &attr ); - size = 0; - NtFreeVirtualMemory( NtCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE ); status = STATUS_NO_MEMORY; goto error; } @@ -599,12 +562,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * return STATUS_SUCCESS; error: - if (thread_data) wine_ldt_free_fs( thread_data->fs ); - if (addr) - { - size = 0; - NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); - } + if (teb) signal_free_thread( teb ); if (handle) NtClose( handle ); pthread_sigmask( SIG_SETMASK, &sigset, NULL ); close( request_pipe[1] );