From fb9cead92b199ec16809383c8946b8a4bc75d10c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 14 Sep 2005 10:36:58 +0000 Subject: [PATCH] Support arbitrary sizes for the thread signal stack, and set the default size from the MINSIGSTKSZ constant. --- dlls/ntdll/ntdll_misc.h | 8 +------ dlls/ntdll/signal_i386.c | 33 ++++++++++++++++++++++---- dlls/ntdll/signal_powerpc.c | 14 +++++++++++ dlls/ntdll/signal_sparc.c | 17 +++++++++++++- dlls/ntdll/thread.c | 8 ++++--- dlls/ntdll/virtual.c | 47 ++++++++++++++++++++++++------------- 6 files changed, 96 insertions(+), 31 deletions(-) diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 0cca428aaa..e1534e6879 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 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl /* 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 6eb2429f6e..07f89ad6c0 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -443,6 +443,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); 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 @@ static inline TEB *get_current_teb(void) { unsigned long esp; __asm__("movl %%esp,%0" : "=g" (esp) ); - return (TEB *)((esp & ~4095) - 4096); + return (TEB *)(esp & ~signal_stack_mask); } @@ -753,7 +756,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun /* 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 @@ static HANDLER_DEF(usr1_handler) } +/********************************************************************** + * 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 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() ) 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 @@ BOOL SIGNAL_Init(void) #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 1e71edbce4..3c976f56b2 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 #include #include #include @@ -584,6 +585,19 @@ static HANDLER_DEF(usr1_handler) } +/********************************************************************** + * 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 8880abbee8..85786b3ee5 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 #include #include #ifdef HAVE_UNISTD_H @@ -386,7 +388,20 @@ static HANDLER_DEF(usr1_handler) /* 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 e245609bf5..a504e098b7 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -55,6 +55,7 @@ static WCHAR current_dir[MAX_NT_PATH_LENGTH]; 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 @@ static inline void free_teb( TEB *teb ) 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 @@ void thread_init(void) 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 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR * 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 9c4d12823e..41cbc13f30 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -548,6 +548,26 @@ static BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */ } +/*********************************************************************** + * 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 * @@ -608,18 +628,7 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, 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 @@ static inline void virtual_init(void) /*********************************************************************** * 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 );