Support arbitrary sizes for the thread signal stack, and set the default size from the MINSIGSTKSZ constant.
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 0cca428..e1534e6 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h
@@ -28,13 +28,6 @@ #include "winioctl.h" #include "wine/server.h" -/* The per-thread signal stack size */ -#ifdef __i386__ -#define SIGNAL_STACK_SIZE 4096 -#else -#define SIGNAL_STACK_SIZE 0 /* we don't need a signal stack on non-i386 */ -#endif - #define MAX_NT_PATH_LENGTH 277 extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); @@ -50,6 +43,7 @@ /* init routines */ extern BOOL SIGNAL_Init(void); +extern size_t get_signal_stack_total_size(void); extern void version_init( const WCHAR *appname ); extern void debug_init(void); extern void thread_init(void);
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 6eb2429..07f89ad 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c
@@ -443,6 +443,9 @@ typedef int (*wine_signal_handler)(unsigned int sig); +static size_t signal_stack_mask; +static size_t signal_stack_size; + static wine_signal_handler handlers[256]; extern void DECLSPEC_NORETURN __wine_call_from_32_restore_regs( CONTEXT context ); @@ -506,7 +509,7 @@ { unsigned long esp; __asm__("movl %%esp,%0" : "=g" (esp) ); - return (TEB *)((esp & ~4095) - 4096); + return (TEB *)(esp & ~signal_stack_mask); } @@ -753,7 +756,7 @@ /* stack sanity checks */ if ((char *)stack >= (char *)get_signal_stack() && - (char *)stack < (char *)get_signal_stack() + SIGNAL_STACK_SIZE) + (char *)stack < (char *)get_signal_stack() + signal_stack_size) { ERR( "nested exception on signal stack in thread %04lx eip %08lx esp %08lx stack %p-%p\n", GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext), @@ -1156,6 +1159,28 @@ } +/********************************************************************** + * 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) +{ + static const size_t teb_size = 4096; /* we reserve one page for the TEB */ + + if (!signal_stack_size) + { + size_t size = 4096, min_size = teb_size + max( MINSIGSTKSZ, 4096 ); + /* 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; +} + + /*********************************************************************** * set_handler * @@ -1174,7 +1199,7 @@ sig_act.ksa_mask = (1 << (SIGINT-1)) | (1 << (SIGUSR2-1)); /* point to the top of the signal stack */ - sig_act.ksa_restorer = (char *)get_signal_stack() + SIGNAL_STACK_SIZE; + sig_act.ksa_restorer = (char *)get_signal_stack() + signal_stack_size; return wine_sigaction( sig, &sig_act, NULL ); } #endif /* linux */ @@ -1220,7 +1245,7 @@ #ifdef HAVE_SIGALTSTACK struct sigaltstack ss; ss.ss_sp = get_signal_stack(); - ss.ss_size = SIGNAL_STACK_SIZE; + ss.ss_size = signal_stack_size; ss.ss_flags = 0; if (!sigaltstack(&ss, NULL)) have_sigaltstack = 1; #ifdef linux
diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index 1e71edb..3c976f5 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c
@@ -23,6 +23,7 @@ #include "config.h" #include "wine/port.h" +#include <assert.h> #include <signal.h> #include <stdlib.h> #include <stdarg.h> @@ -584,6 +585,19 @@ } +/********************************************************************** + * 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 */ +} + + /*********************************************************************** * set_handler *
diff --git a/dlls/ntdll/signal_sparc.c b/dlls/ntdll/signal_sparc.c index 8880abb..85786b3 100644 --- a/dlls/ntdll/signal_sparc.c +++ b/dlls/ntdll/signal_sparc.c
@@ -21,7 +21,9 @@ #ifdef __sparc__ #include "config.h" +#include "wine/port.h" +#include <assert.h> #include <signal.h> #include <stdlib.h> #ifdef HAVE_UNISTD_H @@ -386,7 +388,20 @@ /* wait with 0 timeout, will only return once the thread is no longer suspended */ timeout.QuadPart = 0; - NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout ); + NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); +} + + +/********************************************************************** + * 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 */ }
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index e245609..a504e09 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c
@@ -55,6 +55,7 @@ static RTL_BITMAP tls_bitmap; static RTL_BITMAP tls_expansion_bitmap; static LIST_ENTRY tls_links; +static size_t sigstack_total_size; struct wine_pthread_functions pthread_functions = { NULL }; @@ -93,7 +94,7 @@ NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); wine_ldt_free_fs( thread_data->teb_sel ); - munmap( teb, SIGNAL_STACK_SIZE + sizeof(TEB) ); + munmap( teb, sigstack_total_size ); } @@ -128,7 +129,8 @@ InitializeListHead( &ldr.InInitializationOrderModuleList ); InitializeListHead( &tls_links ); - thread_info.teb_size = SIGNAL_STACK_SIZE + sizeof(TEB); + sigstack_total_size = get_signal_stack_total_size(); + thread_info.teb_size = sigstack_total_size; VIRTUAL_alloc_teb( &addr, thread_info.teb_size, TRUE ); teb = addr; init_teb( teb ); @@ -280,7 +282,7 @@ goto error; } - info->pthread_info.teb_size = SIGNAL_STACK_SIZE + sizeof(TEB); + info->pthread_info.teb_size = sigstack_total_size; if ((status = VIRTUAL_alloc_teb( &addr, info->pthread_info.teb_size, FALSE ))) goto error; teb = addr; if ((status = init_teb( teb ))) goto error;
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 9c4d128..41cbc13 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c
@@ -549,6 +549,26 @@ /*********************************************************************** + * unmap_extra_space + * + * Release the extra memory while keeping the range starting on the granularity boundary. + */ +static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t wanted_size, size_t mask ) +{ + if ((ULONG_PTR)ptr & mask) + { + size_t extra = mask + 1 - ((ULONG_PTR)ptr & mask); + munmap( ptr, extra ); + ptr = (char *)ptr + extra; + total_size -= extra; + } + if (total_size > wanted_size) + munmap( (char *)ptr + wanted_size, total_size - wanted_size ); + return ptr; +} + + +/*********************************************************************** * map_view * * Create a view and mmap the corresponding memory area. @@ -608,18 +628,7 @@ if (is_beyond_limit( ptr, view_size, user_space_limit )) add_reserved_area( ptr, view_size ); else break; } - - /* Release the extra memory while keeping the range - * starting on the granularity boundary. */ - if ((ULONG_PTR)ptr & granularity_mask) - { - size_t extra = granularity_mask + 1 - ((ULONG_PTR)ptr & granularity_mask); - munmap( ptr, extra ); - ptr = (char *)ptr + extra; - view_size -= extra; - } - if (view_size > size) - munmap( (char *)ptr + size, view_size - size ); + ptr = unmap_extra_space( ptr, view_size, size, granularity_mask ); } status = create_view( view_ret, ptr, size, vprot ); @@ -1109,30 +1118,36 @@ /*********************************************************************** * VIRTUAL_alloc_teb * - * Allocate a memory view for a new TEB. We don't care about granularity for TEBs. + * Allocate a memory view for a new TEB, properly aligned to a multiple of the size. */ NTSTATUS VIRTUAL_alloc_teb( void **ret, size_t size, BOOL first ) { void *ptr; NTSTATUS status; struct file_view *view; + size_t align_size = page_size; BYTE vprot = VPROT_READ | VPROT_WRITE | VPROT_COMMITTED; if (first) virtual_init(); *ret = NULL; size = ROUND_SIZE( 0, size ); + while (align_size < size) align_size *= 2; for (;;) { - if ((ptr = wine_anon_mmap( NULL, size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1) + if ((ptr = wine_anon_mmap( NULL, 2 * align_size, VIRTUAL_GetUnixProt(vprot), 0 )) == (void *)-1) { if (errno == ENOMEM) return STATUS_NO_MEMORY; return STATUS_INVALID_PARAMETER; } + if (!is_beyond_limit( ptr, 2 * align_size, user_space_limit )) + { + ptr = unmap_extra_space( ptr, 2 * align_size, align_size, align_size - 1 ); + break; + } /* if we got something beyond the user limit, unmap it and retry */ - if (is_beyond_limit( ptr, size, user_space_limit )) add_reserved_area( ptr, size ); - else break; + add_reserved_area( ptr, 2 * align_size ); } if (!first) RtlEnterCriticalSection( &csVirtual );