diff --git a/dlls/kernel/thread.c b/dlls/kernel/thread.c
index c3f4f39559a..8fb3ed8b754 100644
--- a/dlls/kernel/thread.c
+++ b/dlls/kernel/thread.c
@@ -55,32 +55,22 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
  */
 TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
 {
-    DWORD old_prot, total_size;
+    DWORD old_prot;
     DWORD page_size = getpagesize();
     void *base;
 
-    /* Memory layout in allocated block:
-     *
-     *   size                 contents
-     * SIGNAL_STACK_SIZE   signal stack
-     * stack_size          normal stack (including a PAGE_GUARD page at the bottom)
-     * 1 page              TEB (except for initial thread)
-     */
-
     stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
-    total_size = stack_size + SIGNAL_STACK_SIZE;
 
-    if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
+    if (!(base = VirtualAlloc( NULL, stack_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
         return NULL;
 
     teb->DeallocationStack = base;
-    teb->Tib.StackBase     = (char *)base + SIGNAL_STACK_SIZE + stack_size;
+    teb->Tib.StackBase     = (char *)base + stack_size;
     teb->Tib.StackLimit    = base;  /* note: limit is lower than base since the stack grows down */
 
     /* Setup guard pages */
 
-    VirtualProtect( (char *)base + SIGNAL_STACK_SIZE, 1,
-                    PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
+    VirtualProtect( base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
     return teb;
 }
 
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index fba958cb1f6..59b475527a8 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1933,16 +1933,7 @@ void __wine_process_init( int argc, char *argv[] )
     ANSI_STRING func_name;
     void (* DECLSPEC_NORETURN init_func)();
 
-    /* setup the server connection */
-    wine_server_init_process();
-    wine_server_init_thread();
-
-    /* create the process heap */
-    if (!(NtCurrentTeb()->Peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
-    {
-        MESSAGE( "wine: failed to create the process heap\n" );
-        exit(1);
-    }
+    thread_init();
 
     /* setup the load callback and create ntdll modref */
     wine_dll_set_callback( load_builtin_callback );
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 3713208bfb2..73e830bdaba 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -31,6 +31,13 @@
 #include "thread.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
+
 /* debug helper */
 extern LPCSTR debugstr_us( const UNICODE_STRING *str );
 extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
@@ -38,7 +45,11 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
 extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout );
 extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
                                                  const LARGE_INTEGER *timeout );
+
+/* init routines */
 extern void wine_server_init_process(void);
+extern void wine_server_init_thread(void);
+extern void thread_init(void);
 
 /* module handling */
 extern BOOL MODULE_GetSystemDirectory( UNICODE_STRING *sysdir );
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 5ac36b59e25..18eb5c072cd 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -466,7 +466,7 @@ static inline int get_error_code( const SIGCONTEXT *sigcontext )
  */
 static inline void *get_signal_stack(void)
 {
-    return NtCurrentTeb()->DeallocationStack;
+    return (char *)NtCurrentTeb() + 4096;
 }
 
 
@@ -831,19 +831,20 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
         SYSDEPS_AbortThread(1);
     }
 
-    if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit + SIGNAL_STACK_SIZE + 4096 ||
+    if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit + 4096 ||
         (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
     {
-        UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit + SIGNAL_STACK_SIZE + 4096 - (char *)stack;
+        UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit + 4096 - (char *)stack;
         if (diff < 4096)
+        {
             ERR( "stack overflow %u bytes in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
                  diff, GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
                  NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
-        else
-            ERR( "exception outside of stack limits in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
-                 GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
-                 NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
-        SYSDEPS_AbortThread(1);
+            SYSDEPS_AbortThread(1);
+        }
+        else WARN( "exception outside of stack limits in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
+                   GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
+                   NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
     }
 
     stack--;  /* push the stack_layout structure */
diff --git a/dlls/ntdll/sysdeps.c b/dlls/ntdll/sysdeps.c
index 8632ee36b4c..4130dedadf8 100644
--- a/dlls/ntdll/sysdeps.c
+++ b/dlls/ntdll/sysdeps.c
@@ -58,7 +58,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread);
 struct thread_cleanup_info
 {
     void *stack_base;
-    int   stack_size;
+    ULONG stack_size;
+    void *teb_base;
+    ULONG teb_size;
     int   status;
 };
 
@@ -126,6 +128,7 @@ static void cleanup_thread( void *ptr )
     /* copy the info structure since it is on the stack we will free */
     struct thread_cleanup_info info = *(struct thread_cleanup_info *)ptr;
     munmap( info.stack_base, info.stack_size );
+    munmap( info.teb_base, info.teb_size );
     wine_ldt_free_fs( wine_get_fs() );
 #ifdef HAVE__LWP_CREATE
     _lwp_exit();
@@ -196,15 +199,13 @@ int SYSDEPS_SpawnThread( void (*func)(TEB *), TEB *teb )
  */
 void SYSDEPS_ExitThread( int status )
 {
-    TEB *teb = NtCurrentTeb();
-    DWORD size = 0;
-
 #ifdef HAVE_NPTL
     static TEB *teb_to_free;
     TEB *free_teb;
 
-    if ((free_teb = interlocked_xchg_ptr( (void **)&teb_to_free, teb )) != NULL)
+    if ((free_teb = interlocked_xchg_ptr( (void **)&teb_to_free, NtCurrentTeb() )) != NULL)
     {
+        DWORD size = 0;
         void *ptr;
 
         TRACE("freeing prev teb %p stack %p fs %04x\n",
@@ -214,26 +215,28 @@ void SYSDEPS_ExitThread( int status )
         wine_ldt_free_fs( free_teb->teb_sel );
         ptr = free_teb->DeallocationStack;
         NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
+        ptr = free_teb;
+        NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE | MEM_SYSTEM );
+        munmap( ptr, size );
     }
     SYSDEPS_AbortThread( status );
 #else
     struct thread_cleanup_info info;
-    MEMORY_BASIC_INFORMATION meminfo;
-
-    NtQueryVirtualMemory( GetCurrentProcess(), teb->Tib.StackBase, MemoryBasicInformation,
-                          &meminfo, sizeof(meminfo), NULL );
-    info.stack_base = meminfo.AllocationBase;
-    info.stack_size = meminfo.RegionSize + ((char *)teb->Tib.StackBase - (char *)meminfo.AllocationBase);
-    info.status     = status;
 
     SIGNAL_Block();
-    size = 0;
-    NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE | MEM_SYSTEM );
-    close( teb->wait_fd[0] );
-    close( teb->wait_fd[1] );
-    close( teb->reply_fd );
-    close( teb->request_fd );
-    SIGNAL_Reset();
+    info.status     = status;
+    info.stack_base = NtCurrentTeb()->DeallocationStack;
+    info.stack_size = 0;
+    NtFreeVirtualMemory( GetCurrentProcess(), &info.stack_base,
+                         &info.stack_size, MEM_RELEASE | MEM_SYSTEM );
+    info.teb_base = NtCurrentTeb();
+    info.teb_size = 0;
+    NtFreeVirtualMemory( GetCurrentProcess(), &info.teb_base,
+                         &info.teb_size, MEM_RELEASE | MEM_SYSTEM );
+    close( NtCurrentTeb()->wait_fd[0] );
+    close( NtCurrentTeb()->wait_fd[1] );
+    close( NtCurrentTeb()->reply_fd );
+    close( NtCurrentTeb()->request_fd );
     wine_switch_to_stack( cleanup_thread, &info, get_temp_stack() );
 #endif
 }
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 0a1aba2b980..9a13a943d5c 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -21,15 +21,68 @@
 #include "config.h"
 #include "wine/port.h"
 
+#include <sys/types.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
 #include "ntstatus.h"
 #include "thread.h"
 #include "winternl.h"
 #include "wine/library.h"
 #include "wine/server.h"
 #include "wine/debug.h"
+#include "ntdll_misc.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(thread);
 
+static PEB peb;
+static PEB_LDR_DATA ldr;
+static RTL_USER_PROCESS_PARAMETERS params;  /* default parameters if no parent */
+static RTL_BITMAP tls_bitmap;
+static LIST_ENTRY tls_links;
+static struct debug_info info;  /* debug info for initial thread */
+
+
+/***********************************************************************
+ *           alloc_teb
+ */
+static TEB *alloc_teb( ULONG *size )
+{
+    TEB *teb;
+
+    *size = SIGNAL_STACK_SIZE + sizeof(TEB);
+    teb = wine_anon_mmap( NULL, *size, PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
+    if (teb == (TEB *)-1) return NULL;
+    if (!(teb->teb_sel = wine_ldt_alloc_fs()))
+    {
+        munmap( teb, *size );
+        return NULL;
+    }
+    teb->Tib.ExceptionList = (void *)~0UL;
+    teb->Tib.Self          = &teb->Tib;
+    teb->Peb               = &peb;
+    teb->StaticUnicodeString.Buffer        = teb->StaticUnicodeBuffer;
+    teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
+    return teb;
+}
+
+
+/***********************************************************************
+ *           free_teb
+ */
+static inline void free_teb( TEB *teb )
+{
+    ULONG size = 0;
+    void *addr = teb;
+
+    if (teb->DeallocationStack)
+        NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
+    NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
+    wine_ldt_free_fs( teb->teb_sel );
+    munmap( teb, SIGNAL_STACK_SIZE + sizeof(TEB) );
+}
+
 
 /***********************************************************************
  *           thread_init
@@ -38,35 +91,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread);
  *
  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
  */
-DECL_GLOBAL_CONSTRUCTOR(thread_init)
+void thread_init(void)
 {
-    static TEB teb;
-    static PEB peb;
-    static PEB_LDR_DATA ldr;
-    static RTL_USER_PROCESS_PARAMETERS params;  /* default parameters if no parent */
-    static RTL_BITMAP tls_bitmap;
-    static struct debug_info info;  /* debug info for initial thread */
-
-    if (teb.Tib.Self) return;  /* do it only once */
+    TEB *teb;
+    void *addr;
+    ULONG size;
 
     info.str_pos = info.strings;
     info.out_pos = info.output;
 
-    teb.Tib.ExceptionList = (void *)~0UL;
-    teb.Tib.StackBase     = (void *)~0UL;
-    teb.Tib.Self          = &teb.Tib;
-    teb.Peb               = &peb;
-    teb.tibflags          = TEBF_WIN32;
-    teb.request_fd        = -1;
-    teb.reply_fd          = -1;
-    teb.wait_fd[0]        = -1;
-    teb.wait_fd[1]        = -1;
-    teb.teb_sel           = wine_ldt_alloc_fs();
-    teb.debug_info        = &info;
-    teb.StaticUnicodeString.MaximumLength = sizeof(teb.StaticUnicodeBuffer);
-    teb.StaticUnicodeString.Buffer        = teb.StaticUnicodeBuffer;
-    InitializeListHead( &teb.TlsLinks );
-
     peb.ProcessParameters = &params;
     peb.TlsBitmap         = &tls_bitmap;
     peb.LdrData           = &ldr;
@@ -74,12 +107,42 @@ DECL_GLOBAL_CONSTRUCTOR(thread_init)
     InitializeListHead( &ldr.InLoadOrderModuleList );
     InitializeListHead( &ldr.InMemoryOrderModuleList );
     InitializeListHead( &ldr.InInitializationOrderModuleList );
+    InitializeListHead( &tls_links );
 
-    SYSDEPS_SetCurThread( &teb );
+    teb = alloc_teb( &size );
+    teb->Tib.StackBase = (void *)~0UL;
+    teb->tibflags      = TEBF_WIN32;
+    teb->request_fd    = -1;
+    teb->reply_fd      = -1;
+    teb->wait_fd[0]    = -1;
+    teb->wait_fd[1]    = -1;
+    teb->debug_info    = &info;
+    InsertHeadList( &tls_links, &teb->TlsLinks );
+
+    SYSDEPS_SetCurThread( teb );
+
+    /* setup the server connection */
+    wine_server_init_process();
+    wine_server_init_thread();
+
+    /* create a memory view for the TEB */
+    NtAllocateVirtualMemory( GetCurrentProcess(), &addr, teb, &size,
+                             MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
+
+    /* create the process heap */
+    if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
+    {
+        MESSAGE( "wine: failed to create the process heap\n" );
+        exit(1);
+    }
 }
 
 
-/* startup routine for a newly created thread */
+/***********************************************************************
+ *           start_thread
+ *
+ * Startup routine for a newly created thread.
+ */
 static void start_thread( TEB *teb )
 {
     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
@@ -93,6 +156,10 @@ static void start_thread( TEB *teb )
     SIGNAL_Init();
     wine_server_init_thread();
 
+    RtlAcquirePebLock();
+    InsertHeadList( &tls_links, &teb->TlsLinks );
+    RtlReleasePebLock();
+
     NtTerminateThread( GetCurrentThread(), func( NtCurrentTeb()->entry_arg ) );
 }
 
@@ -107,11 +174,10 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
                                      HANDLE *handle_ptr, CLIENT_ID *id )
 {
     HANDLE handle = 0;
-    TEB *teb;
+    TEB *teb = NULL;
     DWORD tid = 0;
-    SIZE_T total_size;
-    SIZE_T page_size = getpagesize();
-    void *ptr, *base = NULL;
+    ULONG size;
+    void *base;
     int request_pipe[2];
     NTSTATUS status;
 
@@ -135,49 +201,13 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
 
     if (status) goto error;
 
-    if (!stack_reserve || !stack_commit)
+    if (!(teb = alloc_teb( &size )))
     {
-        IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
-        if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
-        if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
-    }
-    if (stack_reserve < stack_commit) stack_reserve = stack_commit;
-    stack_reserve = (stack_reserve + 0xffff) & ~0xffff;  /* round to 64K boundary */
-
-    /* Memory layout in allocated block:
-     *
-     *   size                 contents
-     * SIGNAL_STACK_SIZE   signal stack
-     * stack_size          normal stack (including a PAGE_GUARD page at the bottom)
-     * 1 page              TEB (except for initial thread)
-     */
-
-    total_size = stack_reserve + SIGNAL_STACK_SIZE + page_size;
-    if ((status = NtAllocateVirtualMemory( GetCurrentProcess(), &base, NULL, &total_size,
-                                           MEM_COMMIT, PAGE_EXECUTE_READWRITE )) != STATUS_SUCCESS)
-        goto error;
-
-    teb = (TEB *)((char *)base + total_size - page_size);
-
-    if (!(teb->teb_sel = wine_ldt_alloc_fs()))
-    {
-        status = STATUS_TOO_MANY_THREADS;
+        status = STATUS_NO_MEMORY;
         goto error;
     }
-
-    teb->Tib.ExceptionList          = (void *)~0UL;
-    teb->Tib.StackBase              = (char *)base + SIGNAL_STACK_SIZE + stack_reserve;
-    teb->Tib.StackLimit             = base;  /* limit is lower than base since the stack grows down */
-    teb->Tib.Self                   = &teb->Tib;
-    teb->ClientId.UniqueProcess     = (HANDLE)GetCurrentProcessId();
-    teb->ClientId.UniqueThread      = (HANDLE)tid;
-    teb->Peb                        = NtCurrentTeb()->Peb;
-    teb->DeallocationStack          = base;
-    teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
-    teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
-    RtlAcquirePebLock();
-    InsertHeadList( &NtCurrentTeb()->TlsLinks, &teb->TlsLinks );
-    RtlReleasePebLock();
+    teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
+    teb->ClientId.UniqueThread  = (HANDLE)tid;
 
     teb->tibflags    = TEBF_WIN32;
     teb->exit_code   = STILL_ACTIVE;
@@ -189,17 +219,33 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
     teb->entry_arg   = param;
     teb->htask16     = NtCurrentTeb()->htask16;
 
+    NtAllocateVirtualMemory( GetCurrentProcess(), &base, teb, &size,
+                             MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
+
+    if (!stack_reserve || !stack_commit)
+    {
+        IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
+        if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
+        if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
+    }
+    if (stack_reserve < stack_commit) stack_reserve = stack_commit;
+    stack_reserve = (stack_reserve + 0xffff) & ~0xffff;  /* round to 64K boundary */
+
+    status = NtAllocateVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, NULL,
+                                      &stack_reserve, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+    if (status != STATUS_SUCCESS) goto error;
+
+    /* limit is lower than base since the stack grows down */
+    teb->Tib.StackBase  = (char *)teb->DeallocationStack + stack_reserve;
+    teb->Tib.StackLimit = teb->DeallocationStack;
+
     /* setup the guard page */
-    ptr = (char *)base + SIGNAL_STACK_SIZE;
-    NtProtectVirtualMemory( GetCurrentProcess(), &ptr, &page_size,
+    size = 1;
+    NtProtectVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size,
                             PAGE_EXECUTE_READWRITE | PAGE_GUARD, NULL );
 
     if (SYSDEPS_SpawnThread( start_thread, teb ) == -1)
     {
-        RtlAcquirePebLock();
-        RemoveEntryList( &teb->TlsLinks );
-        RtlReleasePebLock();
-        wine_ldt_free_fs( teb->teb_sel );
         status = STATUS_TOO_MANY_THREADS;
         goto error;
     }
@@ -211,11 +257,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
     return STATUS_SUCCESS;
 
 error:
-    if (base)
-    {
-        total_size = 0;
-        NtFreeVirtualMemory( GetCurrentProcess(), &base, &total_size, MEM_RELEASE );
-    }
+    if (teb) free_teb( teb );
     if (handle) NtClose( handle );
     close( request_pipe[1] );
     return status;
@@ -444,19 +486,18 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
     case ThreadZeroTlsCell:
         if (handle == GetCurrentThread())
         {
-            LIST_ENTRY *entry = &NtCurrentTeb()->TlsLinks;
+            LIST_ENTRY *entry;
             DWORD index;
 
             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
             index = *(DWORD *)data;
             if (index >= 64) return STATUS_INVALID_PARAMETER;
             RtlAcquirePebLock();
-            do
+            for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
             {
                 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
                 teb->TlsSlots[index] = 0;
-                entry = entry->Flink;
-            } while (entry != &NtCurrentTeb()->TlsLinks);
+            }
             RtlReleasePebLock();
             return STATUS_SUCCESS;
         }
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 8a73307bf04..ebaca5e2dd5 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -834,7 +834,7 @@ DWORD VIRTUAL_HandleFault( LPCVOID addr )
         {
             BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift];
             void *page = (void *)((UINT_PTR)addr & ~page_mask);
-            char *stack = (char *)NtCurrentTeb()->DeallocationStack + SIGNAL_STACK_SIZE;
+            char *stack = NtCurrentTeb()->Tib.StackLimit;
             if (vprot & VPROT_GUARD)
             {
                 VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
@@ -1101,8 +1101,12 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *siz
 
     if (type & MEM_SYSTEM)
     {
+        /* return the values that the caller should use to unmap the area */
+        *addr_ptr = view->base;
+        *size_ptr = view->size;
         view->flags |= VFLAG_SYSTEM;
-        type &= ~MEM_SYSTEM;
+        VIRTUAL_DeleteView( view );
+        return STATUS_SUCCESS;
     }
 
     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
diff --git a/include/thread.h b/include/thread.h
index 4fbc00a52e9..2d07b254ade 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -140,14 +140,6 @@ typedef struct _TEB
 #define TEBF_WIN32  0x0001
 #define TEBF_TRAP   0x0002
 
-/* The per-thread signal stack size */
-#ifdef __i386__
-#define SIGNAL_STACK_SIZE  0x100000  /* 1Mb  FIXME: should be much smaller than that */
-#else
-#define SIGNAL_STACK_SIZE  0  /* we don't need a signal stack on non-i386 */
-#endif
-
-
 /* scheduler/thread.c */
 extern TEB *THREAD_InitStack( TEB *teb, DWORD stack_size );
 
diff --git a/include/wine/server.h b/include/wine/server.h
index 54e54596279..7da6faa1d1f 100644
--- a/include/wine/server.h
+++ b/include/wine/server.h
@@ -56,7 +56,6 @@ extern void wine_server_send_fd( int fd );
 extern int wine_server_fd_to_handle( int fd, unsigned int access, int inherit, obj_handle_t *handle );
 extern int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
                                      enum fd_type *type, int *flags );
-extern void wine_server_init_thread(void);
 
 /* do a server call and set the last error code */
 inline static unsigned int wine_server_call_err( void *req_ptr )