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