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

diff --git a/include/thread.h b/include/thread.h
index 5ecfc27..9e0b243 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -89,8 +89,7 @@
     DWORD        unknown6[5];    /* --n 1e8 Unknown */
 
     /* The following are Wine-specific fields (NT: GDI stuff) */
-    DWORD        cleanup;        /* --3 1fc Cleanup service handle */
-    DWORD        unused[3];      /* --3 200 Was server buffer */
+    DWORD        unused[4];      /* --3 1fc Was server buffer */
     int          request_fd;     /* --3 20c fd for sending server requests */
     int          reply_fd;       /* --3 210 fd for receiving server replies */
     int          wait_fd[2];     /* --3 214 fd for sleeping server requests */
@@ -132,5 +131,11 @@
 extern int SYSDEPS_SpawnThread( TEB *teb );
 extern void SYSDEPS_SetCurThread( TEB *teb );
 extern void SYSDEPS_ExitThread( int status ) WINE_NORETURN;
+extern void SYSDEPS_AbortThread( int status ) WINE_NORETURN;
+extern void SYSDEPS_SwitchToThreadStack( void (*func)(void) ) WINE_NORETURN;
+
+/* signal handling */
+extern BOOL SIGNAL_Init(void);
+extern void SIGNAL_Reset(void);
 
 #endif  /* __WINE_THREAD_H */
diff --git a/include/wine/exception.h b/include/wine/exception.h
index 41d0757..87ec2e3 100644
--- a/include/wine/exception.h
+++ b/include/wine/exception.h
@@ -179,7 +179,6 @@
 
 #ifdef __WINE__
 extern void WINAPI EXC_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
-extern BOOL SIGNAL_Init(void);
 #endif
 
 #endif  /* __WINE_WINE_EXCEPTION_H */
diff --git a/memory/selector.c b/memory/selector.c
index e68a92f..57af3ff 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -27,6 +27,8 @@
     return (wine_ldt_copy.limit[sel >> __AHSHIFT] >> 16) + 1;
 }
 
+static const LDT_ENTRY null_entry;  /* all-zeros, used to clear LDT entries */
+
 /***********************************************************************
  *           SELECTOR_AllocArray
  *
@@ -98,8 +100,6 @@
  */
 WORD WINAPI FreeSelector16( WORD sel )
 {
-    LDT_ENTRY entry;
-
     if (IS_SELECTOR_FREE(sel)) return sel;  /* error */
 
 #ifdef __i386__
@@ -112,14 +112,30 @@
     if (!((__get_gs() ^ sel) & ~7)) __set_gs( 0 );
 #endif  /* __i386__ */
 
-    memset( &entry, 0, sizeof(entry) );  /* clear the LDT entries */
-    wine_ldt_set_entry( sel, &entry );
+    wine_ldt_set_entry( sel, &null_entry );
     wine_ldt_copy.flags[sel >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
     return 0;
 }
 
 
 /***********************************************************************
+ *           SELECTOR_FreeFs
+ *
+ * Free the current %fs selector.
+ */
+void SELECTOR_FreeFs(void)
+{
+    WORD fs = __get_fs();
+    if (fs)
+    {
+        wine_ldt_copy.flags[fs >> __AHSHIFT] &= ~WINE_LDT_FLAGS_ALLOCATED;
+        __set_fs(0);
+        wine_ldt_set_entry( fs, &null_entry );
+    }
+}
+
+
+/***********************************************************************
  *           SELECTOR_SetEntries
  *
  * Set the LDT entries for an array of selectors.
diff --git a/memory/virtual.c b/memory/virtual.c
index 7dce79c..7c9eda7 100644
--- a/memory/virtual.c
+++ b/memory/virtual.c
@@ -958,7 +958,13 @@
         return FALSE;
     }
 
-    /* Compute the protection flags */
+    /* Check the type */
+
+    if (type & MEM_SYSTEM)
+    {
+        view->flags |= VFLAG_SYSTEM;
+        type &= ~MEM_SYSTEM;
+    }
 
     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
     {
diff --git a/scheduler/client.c b/scheduler/client.c
index 9fe5fd5..0aeb9f0 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -98,7 +98,7 @@
     fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid );
     vfprintf( stderr, err, args );
     va_end( args );
-    SYSDEPS_ExitThread(1);
+    SYSDEPS_AbortThread(1);
 }
 
 
@@ -109,7 +109,7 @@
 {
     fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid );
     perror( err );
-    SYSDEPS_ExitThread(1);
+    SYSDEPS_AbortThread(1);
 }
 
 
@@ -144,7 +144,7 @@
     }
 
     if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
-    if (errno == EPIPE) SYSDEPS_ExitThread(0);
+    if (errno == EPIPE) SYSDEPS_AbortThread(0);
     server_protocol_perror( "sendmsg" );
 }
 
@@ -172,7 +172,7 @@
         server_protocol_perror("read");
     }
     /* the server closed the connection; time to die... */
-    SYSDEPS_ExitThread(0);
+    SYSDEPS_AbortThread(0);
 }
 
 
@@ -252,7 +252,7 @@
         if ((ret = sendmsg( fd_socket, &msghdr, 0 )) == sizeof(data)) return;
         if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
         if (errno == EINTR) continue;
-        if (errno == EPIPE) SYSDEPS_ExitThread(0);
+        if (errno == EPIPE) SYSDEPS_AbortThread(0);
         server_protocol_perror( "sendmsg" );
     }
 }
@@ -311,7 +311,7 @@
         server_protocol_perror("recvmsg");
     }
     /* the server closed the connection; time to die... */
-    SYSDEPS_ExitThread(0);
+    SYSDEPS_AbortThread(0);
 }
 
 
diff --git a/scheduler/process.c b/scheduler/process.c
index ff11d1f..f0d352f 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -109,9 +109,6 @@
 /* scheduler/pthread.c */
 extern void PTHREAD_init_done(void);
 
-/* scheduler/sysdeps.c */
-extern void SYSDEPS_SwitchToThreadStack( void (*func)(void) ) WINE_NORETURN;
-
 extern BOOL MAIN_MainInit(void);
 
 typedef WORD WINAPI (*pUserSignalProc)( UINT, DWORD, DWORD, HMODULE16 );
diff --git a/scheduler/synchro.c b/scheduler/synchro.c
index d394899..e862737 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -140,7 +140,7 @@
         server_protocol_perror("wakeup read");
     }
     /* the server closed the connection; time to die... */
-    SYSDEPS_ExitThread(0);
+    SYSDEPS_AbortThread(0);
 }
 
 
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.@)
  *