Added support for cleaning up the TEB from inside the exiting thread.

diff --git a/scheduler/sysdeps.c b/scheduler/sysdeps.c
index 69da094..c02fb6a 100644
--- a/scheduler/sysdeps.c
+++ b/scheduler/sysdeps.c
@@ -21,9 +21,13 @@
 #ifdef HAVE_UCONTEXT_H
 # include <ucontext.h>
 #endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
 #include "thread.h"
 #include "wine/server.h"
 #include "winbase.h"
+#include "wine/winbase16.h"
 #include "wine/exception.h"
 #include "debugtools.h"
 
@@ -42,6 +46,21 @@
 # endif  /* CLONE_VM */
 #endif  /* linux || HAVE_CLONE */
 
+extern void SELECTOR_FreeFs(void);
+
+struct thread_cleanup_info
+{
+    void *stack_base;
+    int   stack_size;
+    int   status;
+};
+
+/* temporary stacks used on thread exit */
+#define TEMP_STACK_SIZE 1024
+#define NB_TEMP_STACKS  8
+static char temp_stacks[NB_TEMP_STACKS][TEMP_STACK_SIZE];
+static LONG next_temp_stack;  /* next temp stack to use */
+
 /***********************************************************************
  *           SYSDEPS_SetCurThread
  *
@@ -58,6 +77,58 @@
 #endif
 }
 
+
+/***********************************************************************
+ *           call_on_thread_stack
+ *
+ * Call a function once we switched to the thread stack.
+ */
+static void call_on_thread_stack( void *func )
+{
+    __TRY
+    {
+        void (*funcptr)(void) = func;
+        funcptr();
+    }
+    __EXCEPT(UnhandledExceptionFilter)
+    {
+        TerminateThread( GetCurrentThread(), GetExceptionCode() );
+    }
+    __ENDTRY
+    SYSDEPS_ExitThread(0);  /* should never get here */
+}
+
+
+/***********************************************************************
+ *           get_temp_stack
+ *
+ * Get a temporary stack address to run the thread exit code on.
+ */
+inline static char *get_temp_stack(void)
+{
+    unsigned int next = InterlockedExchangeAdd( &next_temp_stack, 1 );
+    return temp_stacks[next % NB_TEMP_STACKS];
+}
+
+
+/***********************************************************************
+ *           cleanup_thread
+ *
+ * Cleanup the remains of a thread. Runs on a temporary stack.
+ */
+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 );
+    SELECTOR_FreeFs();
+#ifdef HAVE__LWP_CREATE
+    _lwp_exit();
+#endif
+    _exit( info.status );
+}
+
+
 /***********************************************************************
  *           SYSDEPS_StartThread
  *
@@ -138,6 +209,36 @@
 }
 
 
+/***********************************************************************
+ *           SYSDEPS_CallOnStack
+ */
+void SYSDEPS_CallOnStack( void (*func)(LPVOID), LPVOID arg ) WINE_NORETURN;
+#ifdef __i386__
+__ASM_GLOBAL_FUNC( SYSDEPS_CallOnStack,
+                   "movl 4(%esp),%ecx\n\t"  /* func */
+                   "movl 8(%esp),%edx\n\t"  /* arg */
+                   ".byte 0x64\n\tmovl 0x04,%esp\n\t"  /* teb->stack_top */
+                   "pushl %edx\n\t"
+                   "xorl %ebp,%ebp\n\t"
+                   "call *%ecx\n\t"
+                   "int $3" /* we never return here */ );
+#else
+void SYSDEPS_CallOnStack( void (*func)(LPVOID), LPVOID arg )
+{
+    func( arg );
+    while(1); /* avoid warning */
+}
+#endif
+
+
+/***********************************************************************
+ *           SYSDEPS_SwitchToThreadStack
+ */
+void SYSDEPS_SwitchToThreadStack( void (*func)(void) )
+{
+    SYSDEPS_CallOnStack( call_on_thread_stack, func );
+}
+
 
 /***********************************************************************
  *           SYSDEPS_ExitThread
@@ -146,97 +247,49 @@
  */
 void SYSDEPS_ExitThread( int status )
 {
-    int fd = NtCurrentTeb()->request_fd;
-    NtCurrentTeb()->request_fd = -1;
-    close( fd );
+    TEB *teb = NtCurrentTeb();
+    struct thread_cleanup_info info;
+    MEMORY_BASIC_INFORMATION meminfo;
+
+    FreeSelector16( teb->stack_sel );
+    VirtualQuery( teb->stack_top, &meminfo, sizeof(meminfo) );
+    info.stack_base = meminfo.AllocationBase;
+    info.stack_size = meminfo.RegionSize + ((char *)teb->stack_top - (char *)meminfo.AllocationBase);
+    info.status     = status;
+
+    SIGNAL_Reset();
+
+    VirtualFree( teb->stack_base, 0, MEM_RELEASE | MEM_SYSTEM );
+    close( teb->wait_fd[0] );
+    close( teb->wait_fd[1] );
+    close( teb->reply_fd );
+    close( teb->request_fd );
+    teb->stack_low = get_temp_stack();
+    teb->stack_top = teb->stack_low + TEMP_STACK_SIZE;
+    SYSDEPS_CallOnStack( cleanup_thread, &info );
+}
+
+
+/***********************************************************************
+ *           SYSDEPS_AbortThread
+ *
+ * Same as SYSDEPS_ExitThread, but must not do anything that requires a server call.
+ */
+void SYSDEPS_AbortThread( int status )
+{
+    SIGNAL_Reset();
+    close( NtCurrentTeb()->wait_fd[0] );
+    close( NtCurrentTeb()->wait_fd[1] );
+    close( NtCurrentTeb()->reply_fd );
+    close( NtCurrentTeb()->request_fd );
 #ifdef HAVE__LWP_CREATE
     _lwp_exit();
 #endif
-    _exit( status );
-    /*
-     * It is of course impossible to come here,
-     * but it eliminates a compiler warning.
-     */
-    exit( status );
+    for (;;)  /* avoid warning */
+        _exit( status );
 }
 
 
-/***********************************************************************
- *           SYSDEPS_CallOnStack
- */
-int SYSDEPS_DoCallOnStack( int (*func)(LPVOID), LPVOID arg )
-{
-    int retv = 0;
-
-    __TRY
-    {
-        retv = func( arg );
-    }
-    __EXCEPT(UnhandledExceptionFilter)
-    {
-        TerminateThread( GetCurrentThread(), GetExceptionCode() );
-        return 0;
-    }
-    __ENDTRY
-
-    return retv;
-}
-
-#ifdef __i386__
-int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
-                         int (*func)(LPVOID), LPVOID arg );
-__ASM_GLOBAL_FUNC( SYSDEPS_CallOnStack,
-                   "pushl %ebp\n\t"
-                   "movl %esp, %ebp\n\t"
-                   ".byte 0x64; pushl 0x04\n\t"
-                   ".byte 0x64; pushl 0x08\n\t"
-                   "movl 8(%ebp), %esp\n\t"
-                   "movl 12(%ebp), %eax\n\t"
-                   ".byte 0x64; movl %esp, 0x04\n\t"
-                   ".byte 0x64; movl %eax, 0x08\n\t"
-                   "pushl 20(%ebp)\n\t"
-                   "pushl 16(%ebp)\n\t"
-                   "call " __ASM_NAME("SYSDEPS_DoCallOnStack") "\n\t"
-                   "leal -8(%ebp), %esp\n\t"
-                   ".byte 0x64; popl 0x08\n\t"
-                   ".byte 0x64; popl 0x04\n\t"
-                   "popl %ebp\n\t"
-                   "ret" );
-#else
-int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
-                         int (*func)(LPVOID), LPVOID arg )
-{
-    return SYSDEPS_DoCallOnStack( func, arg );
-}
-#endif
-
-/***********************************************************************
- *           SYSDEPS_SwitchToThreadStack
- */
-void SYSDEPS_SwitchToThreadStack( void (*func)(void) )
-{
-    DWORD page_size = getpagesize();
-    void *cur_stack = (void *)(((ULONG_PTR)&func + (page_size-1)) & ~(page_size-1));
-
-    TEB *teb = NtCurrentTeb();
-    LPVOID stackTop = teb->stack_top;
-    LPVOID stackLow = teb->stack_low;
-
-    struct rlimit rl;
-
-    if ( getrlimit(RLIMIT_STACK, &rl) < 0 ) 
-    {
-        WARN("Can't get rlimit\n");
-        rl.rlim_cur = 8*1024*1024;
-    }
-
-    teb->stack_top = cur_stack;
-    teb->stack_low = (char *)cur_stack - rl.rlim_cur;
-
-    SYSDEPS_CallOnStack( stackTop, stackLow, 
-                         (int (*)(void *))func, NULL );
-}
-
 /**********************************************************************
  *           NtCurrentTeb   (NTDLL.@)
  *