Skip to content
Snippets Groups Projects
Commit fb9cead9 authored by Alexandre Julliard's avatar Alexandre Julliard
Browse files

Support arbitrary sizes for the thread signal stack, and set the

default size from the MINSIGSTKSZ constant.
parent 305b221c
No related merge requests found
......@@ -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);
......
......@@ -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
......
......@@ -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 @@ 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
*
......
......@@ -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 @@ 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 */
}
......
......@@ -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;
......
......@@ -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 );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment