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.@)
*