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 );