Alexandre Julliard : ntdll: Use a more drastic (and simpler) method for unwinding the stack on thread exit.
Alexandre Julliard
julliard at winehq.org
Sat Aug 29 11:35:47 CDT 2009
Module: wine
Branch: master
Commit: 690cf4a6c8cde2d693f4c47be46ac7b8e6091945
URL: http://source.winehq.org/git/wine.git/?a=commit;h=690cf4a6c8cde2d693f4c47be46ac7b8e6091945
Author: Alexandre Julliard <julliard at winehq.org>
Date: Sat Aug 29 12:08:11 2009 +0200
ntdll: Use a more drastic (and simpler) method for unwinding the stack on thread exit.
---
dlls/ntdll/ntdll_misc.h | 4 ++
dlls/ntdll/signal_x86_64.c | 119 ++++++++++----------------------------------
2 files changed, 31 insertions(+), 92 deletions(-)
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index faafd20..179aa20 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -201,7 +201,11 @@ struct ntdll_thread_data
int reply_fd; /* 1e4/314 fd for receiving server replies */
int wait_fd[2]; /* 1e8/318 fd for sleeping server requests */
BOOL wow64_redir; /* 1f0/320 Wow64 filesystem redirection flag */
+#ifdef __i386__
void *vm86_ptr; /* 1f4/328 data for vm86 mode */
+#else
+ void *exit_frame; /* 1f4/328 exit frame pointer */
+#endif
pthread_t pthread_id; /* 1f8/330 pthread thread id */
};
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 50ecbe8..b5ff237 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2880,101 +2880,45 @@ void WINAPI __regs_RtlRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
DEFINE_REGS_ENTRYPOINT( RtlRaiseException, 1 )
-struct topmost_frame
-{
- EXCEPTION_REGISTRATION_RECORD frame;
- sigjmp_buf jmp;
- int exit_code;
-};
-
-static void DECLSPEC_NORETURN topmost_exit_unwind_target(void)
-{
- struct topmost_frame *topmost_frame = (struct topmost_frame *)__wine_get_frame();
- __wine_pop_frame( &topmost_frame->frame );
- siglongjmp( topmost_frame->jmp, 1 );
-}
-
-static void DECLSPEC_NORETURN topmost_abort_unwind_target(void)
-{
- struct topmost_frame *topmost_frame = (struct topmost_frame *)__wine_get_frame();
- __wine_pop_frame( &topmost_frame->frame );
- siglongjmp( topmost_frame->jmp, 2 );
-}
-
-static DWORD topmost_handler( EXCEPTION_RECORD *record,
- EXCEPTION_REGISTRATION_RECORD *frame,
- CONTEXT *context,
- EXCEPTION_REGISTRATION_RECORD **pdispatcher )
+/***********************************************************************
+ * call_thread_func
+ */
+void call_thread_func( LPTHREAD_START_ROUTINE entry, void *arg, void *frame )
{
- struct topmost_frame *topmost_frame = (struct topmost_frame *)frame;
- EXCEPTION_POINTERS ptrs;
-
- if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
- return ExceptionContinueSearch;
-
- ptrs.ExceptionRecord = record;
- ptrs.ContextRecord = context;
- switch (unhandled_exception_filter( &ptrs ))
+ ntdll_get_thread_data()->exit_frame = frame;
+ __TRY
{
- case EXCEPTION_CONTINUE_SEARCH:
- return ExceptionContinueSearch;
- case EXCEPTION_CONTINUE_EXECUTION:
- return ExceptionContinueExecution;
- case EXCEPTION_EXECUTE_HANDLER:
- break;
+ RtlExitUserThread( entry( arg ));
}
- /* send the exit code to the server */
- /* we can't simply call NtTerminateThread since it's a WINAPI function */
- /* and libgcc unwinding doesn't handle those correctly */
- SERVER_START_REQ( terminate_thread )
+ __EXCEPT(unhandled_exception_filter)
{
- req->handle = wine_server_obj_handle( GetCurrentThread() );
- req->exit_code = record->ExceptionCode;
- wine_server_call( req );
+ NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
}
- SERVER_END_REQ;
- topmost_frame->exit_code = record->ExceptionCode;
- for (;;) RtlUnwind( frame, topmost_abort_unwind_target, record, 0 );
+ __ENDTRY
+ abort(); /* should not be reached */
}
-/***********************************************************************
- * call_thread_entry_point
- */
-void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
-{
- struct topmost_frame frame;
+extern void DECLSPEC_NORETURN call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg );
+__ASM_GLOBAL_FUNC( call_thread_entry_point,
+ "subq $8,%rsp\n\t"
+ ".cfi_adjust_cfa_offset 8\n\t"
+ "movq %rsp,%rdx\n\t"
+ "call " __ASM_NAME("call_thread_func") );
- frame.frame.Handler = topmost_handler;
- switch (sigsetjmp( frame.jmp, 0 ))
- {
- case 0:
- __wine_push_frame( &frame.frame );
- frame.exit_code = entry( arg );
- __wine_pop_frame( &frame.frame );
- /* fall through */
- case 1:
- exit_thread( frame.exit_code );
- default:
- terminate_thread( frame.exit_code );
- }
-}
+extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), void *frame );
+__ASM_GLOBAL_FUNC( call_thread_exit_func,
+ "subq $8,%rsp\n\t"
+ ".cfi_adjust_cfa_offset 8\n\t"
+ "movq %rdx,%rsp\n\t"
+ "call *%rsi" );
/***********************************************************************
* RtlExitUserThread (NTDLL.@)
*/
void WINAPI RtlExitUserThread( ULONG status )
{
- EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
-
- /* hack: find the top TEB frame and use it as unwind target */
- if (teb_frame != (EXCEPTION_REGISTRATION_RECORD *)~0UL)
- {
- while (teb_frame->Prev != (EXCEPTION_REGISTRATION_RECORD *)~0UL) teb_frame = teb_frame->Prev;
- TRACE( "unwinding to frame %p for thread exit\n", teb_frame );
- ((struct topmost_frame *)teb_frame)->exit_code = status;
- RtlUnwind( teb_frame, topmost_exit_unwind_target, NULL, 0 );
- }
- exit_thread( status );
+ if (!ntdll_get_thread_data()->exit_frame) exit_thread( status );
+ call_thread_exit_func( status, exit_thread, ntdll_get_thread_data()->exit_frame );
}
/***********************************************************************
@@ -2982,17 +2926,8 @@ void WINAPI RtlExitUserThread( ULONG status )
*/
void abort_thread( int status )
{
- EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
-
- /* hack: find the top TEB frame and use it as unwind target */
- if (teb_frame != (EXCEPTION_REGISTRATION_RECORD *)~0UL)
- {
- while (teb_frame->Prev != (EXCEPTION_REGISTRATION_RECORD *)~0UL) teb_frame = teb_frame->Prev;
- TRACE( "unwinding to frame %p for thread exit\n", teb_frame );
- ((struct topmost_frame *)teb_frame)->exit_code = status;
- RtlUnwind( teb_frame, topmost_abort_unwind_target, NULL, 0 );
- }
- terminate_thread( status );
+ if (!ntdll_get_thread_data()->exit_frame) terminate_thread( status );
+ call_thread_exit_func( status, terminate_thread, ntdll_get_thread_data()->exit_frame );
}
/**********************************************************************
More information about the wine-cvs
mailing list