Author: davidxu
Date: Wed Sep 15 02:56:32 2010
New Revision: 212630
URL: http://svn.freebsd.org/changeset/base/212630

Log:
  add code to support stack unwinding when thread exits. note that only
  defer-mode cancellation works, asynchrnous mode does not work because
  it lacks of libuwind's support. stack unwinding is not enabled unless
  LIBTHR_UNWIND_STACK is defined in Makefile.

Modified:
  head/lib/libthr/Makefile
  head/lib/libthr/thread/thr_clean.c
  head/lib/libthr/thread/thr_create.c
  head/lib/libthr/thread/thr_exit.c
  head/lib/libthr/thread/thr_init.c
  head/lib/libthr/thread/thr_private.h

Modified: head/lib/libthr/Makefile
==============================================================================
--- head/lib/libthr/Makefile    Wed Sep 15 01:21:30 2010        (r212629)
+++ head/lib/libthr/Makefile    Wed Sep 15 02:56:32 2010        (r212630)
@@ -25,6 +25,14 @@ CFLAGS+=-I${.CURDIR}/../../libexec/rtld-
 CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf/${MACHINE_CPUARCH}
 CFLAGS+=-I${.CURDIR}/../libthread_db
 CFLAGS+=-Winline
+
+LIBTHR_UNWIND_STACK=yes
+
+.ifdef LIBTHR_UNWIND_STACK
+CFLAGS+=-I${.CURDIR}/../../contrib/gcc -fexceptions 
+CFLAGS+=-D_PTHREAD_FORCED_UNWIND
+.endif
+
 LDFLAGS+=-Wl,-znodelete
 
 VERSION_DEF=${.CURDIR}/../libc/Versions.def

Modified: head/lib/libthr/thread/thr_clean.c
==============================================================================
--- head/lib/libthr/thread/thr_clean.c  Wed Sep 15 01:21:30 2010        
(r212629)
+++ head/lib/libthr/thread/thr_clean.c  Wed Sep 15 02:56:32 2010        
(r212630)
@@ -78,6 +78,9 @@ __pthread_cleanup_pop_imp(int execute)
 void
 _pthread_cleanup_push(void (*routine) (void *), void *arg)
 {
+#ifdef _PTHREAD_FORCED_UNWIND
+       PANIC("_pthread_cleanup_push is not supported while stack unwinding is 
enabled.");
+#else
        struct pthread  *curthread = _get_curthread();
        struct pthread_cleanup *newbuf;
 
@@ -89,10 +92,15 @@ _pthread_cleanup_push(void (*routine) (v
                newbuf->prev = curthread->cleanup;
                curthread->cleanup = newbuf;
        }
+#endif
 }
 
 void
 _pthread_cleanup_pop(int execute)
 {
+#ifdef _PTHREAD_FORCED_UNWIND
+       PANIC("_pthread_cleanup_pop is not supported while stack unwinding is 
enabled.");
+#else
        __pthread_cleanup_pop_imp(execute);
+#endif
 }

Modified: head/lib/libthr/thread/thr_create.c
==============================================================================
--- head/lib/libthr/thread/thr_create.c Wed Sep 15 01:21:30 2010        
(r212629)
+++ head/lib/libthr/thread/thr_create.c Wed Sep 15 02:56:32 2010        
(r212630)
@@ -264,6 +264,11 @@ thread_start(struct pthread *curthread)
                __sys_sigprocmask(SIG_SETMASK, &set, NULL);
        }
 
+#ifdef _PTHREAD_FORCED_UNWIND
+       curthread->unwind_stackend = (char *)curthread->attr.stackaddr_attr +
+               curthread->attr.stacksize_attr;
+#endif
+
        /* Run the current thread's start routine with argument: */
        _pthread_exit(curthread->start_routine(curthread->arg));
 

Modified: head/lib/libthr/thread/thr_exit.c
==============================================================================
--- head/lib/libthr/thread/thr_exit.c   Wed Sep 15 01:21:30 2010        
(r212629)
+++ head/lib/libthr/thread/thr_exit.c   Wed Sep 15 02:56:32 2010        
(r212630)
@@ -31,6 +31,9 @@
 
 #include "namespace.h"
 #include <errno.h>
+#ifdef _PTHREAD_FORCED_UNWIND
+#include <dlfcn.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <pthread.h>
@@ -43,8 +46,125 @@
 
 void   _pthread_exit(void *status);
 
+static void    exit_thread(void) __dead2;
+
 __weak_reference(_pthread_exit, pthread_exit);
 
+#ifdef _PTHREAD_FORCED_UNWIND
+
+static void thread_unwind(void) __dead2;
+#ifdef PIC
+static void thread_uw_init(void);
+static _Unwind_Reason_Code thread_unwind_stop(int version,
+       _Unwind_Action actions,
+       _Unwind_Exception_Class exc_class,
+       struct _Unwind_Exception *exc_obj,
+       struct _Unwind_Context *context, void *stop_parameter);
+/* unwind library pointers */
+static _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *,
+       _Unwind_Stop_Fn, void *);
+static void (*uwl_resume)(struct _Unwind_Exception *exc);
+static _Unwind_Word (*uwl_getcfa)(struct _Unwind_Context *);
+
+static void
+thread_uw_init(void)
+{
+       static int inited = 0;
+       void *handle;
+
+       if (inited)
+               return;
+       inited = 1;
+       handle = RTLD_DEFAULT;
+       if ((uwl_forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) == NULL||
+           (uwl_resume = dlsym(handle, "_Unwind_Resume")) == NULL ||
+           (uwl_getcfa = dlsym(handle, "_Unwind_GetCFA")) == NULL) {
+               uwl_forcedunwind = NULL;
+               return;
+       }
+}
+
+void
+_Unwind_Resume(struct _Unwind_Exception *ex)
+{
+       (*uwl_resume)(ex);
+}
+ 
+_Unwind_Reason_Code
+_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func,
+       void *stop_arg)
+{
+       return (*uwl_forcedunwind)(ex, stop_func, stop_arg);
+}
+
+_Unwind_Word
+_Unwind_GetCFA(struct _Unwind_Context *context)
+{
+       return (*uwl_getcfa)(context);
+}
+#else
+#pragma weak _Unwind_GetCFA
+#pragma weak _Unwind_ForcedUnwind
+#pragma weak _Unwind_Resume
+#endif /* PIC */
+
+static void
+thread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e)
+{
+       /*
+        * Specification said that _Unwind_Resume should not be used here,
+        * instead, user should rethrow the exception. For C++ user, they
+        * should put "throw" sentence in catch(...) block.
+        */
+       PANIC("exception should be rethrown");
+}
+
+static _Unwind_Reason_Code
+thread_unwind_stop(int version, _Unwind_Action actions,
+       _Unwind_Exception_Class exc_class,
+       struct _Unwind_Exception *exc_obj,
+       struct _Unwind_Context *context, void *stop_parameter)
+{
+       struct pthread *curthread = _get_curthread();
+       struct pthread_cleanup *cur;
+       uintptr_t cfa;
+       int done = 0;
+
+       /* XXX assume stack grows down to lower address */
+
+       cfa = _Unwind_GetCFA(context);
+       if (actions & _UA_END_OF_STACK) {
+               done = 1;
+       } else if (cfa >= (uintptr_t)curthread->unwind_stackend) {
+               done = 1;
+       }
+
+       while ((cur = curthread->cleanup) != NULL &&
+              (done ||
+               ((uintptr_t)cur < (uintptr_t)curthread->unwind_stackend &&
+                (uintptr_t)cur >= cfa))) {
+                       __pthread_cleanup_pop_imp(1);
+       }
+
+       if (done)
+               exit_thread(); /* Never return! */
+
+       return (_URC_NO_REASON);
+}
+
+static void
+thread_unwind(void)
+{
+       struct pthread  *curthread = _get_curthread();
+
+       curthread->ex.exception_class = 0;
+       curthread->ex.exception_cleanup = thread_unwind_cleanup;
+       _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL);
+       PANIC("_Unwind_ForcedUnwind returned");
+}
+
+#endif
+
 void
 _thread_exit(const char *fname, int lineno, const char *msg)
 {
@@ -95,10 +215,39 @@ _pthread_exit_mask(void *status, sigset_
        
        /* Save the return value: */
        curthread->ret = status;
+#ifdef _PTHREAD_FORCED_UNWIND
+#ifdef PIC
+       thread_uw_init();
+       if (uwl_forcedunwind != NULL) {
+               thread_unwind();
+       }
+#else
+       if (_Unwind_ForcedUnwind != NULL) {
+               thread_unwind();
+       }
+#endif /* PIC */
+
+       else {
+               while (curthread->cleanup != NULL) {
+                       __pthread_cleanup_pop_imp(1);
+               }
+               exit_thread();
+       }
+
+#else
        while (curthread->cleanup != NULL) {
-               _pthread_cleanup_pop(1);
+               __pthread_cleanup_pop_imp(1);
        }
 
+       exit_thread();
+#endif /* _PTHREAD_FORCED_UNWIND */
+}
+
+static void
+exit_thread(void)
+{
+       struct pthread *curthread = _get_curthread();
+
        /* Check if there is thread specific data: */
        if (curthread->specific != NULL) {
                /* Run the thread-specific data destructors: */

Modified: head/lib/libthr/thread/thr_init.c
==============================================================================
--- head/lib/libthr/thread/thr_init.c   Wed Sep 15 01:21:30 2010        
(r212629)
+++ head/lib/libthr/thread/thr_init.c   Wed Sep 15 02:56:32 2010        
(r212630)
@@ -413,6 +413,10 @@ init_main_thread(struct pthread *thread)
                 &sched_param);
        thread->attr.prio = sched_param.sched_priority;
 
+#ifdef _PTHREAD_FORCED_UNWIND
+       thread->unwind_stackend = _usrstack;
+#endif
+
        /* Others cleared to zero by thr_alloc() */
 }
 

Modified: head/lib/libthr/thread/thr_private.h
==============================================================================
--- head/lib/libthr/thread/thr_private.h        Wed Sep 15 01:21:30 2010        
(r212629)
+++ head/lib/libthr/thread/thr_private.h        Wed Sep 15 02:56:32 2010        
(r212630)
@@ -70,6 +70,10 @@
 #include "thr_umtx.h"
 #include "thread_db.h"
 
+#ifdef _PTHREAD_FORCED_UNWIND
+#include <unwind-generic.h>
+#endif
+
 typedef TAILQ_HEAD(pthreadlist, pthread) pthreadlist;
 typedef TAILQ_HEAD(atfork_head, pthread_atfork) atfork_head;
 TAILQ_HEAD(mutex_queue, pthread_mutex);
@@ -446,6 +450,11 @@ struct pthread {
        /* Cleanup handlers Link List */
        struct pthread_cleanup  *cleanup;
 
+#ifdef _PTHREAD_FORCED_UNWIND
+       struct _Unwind_Exception        ex;
+       void                    *unwind_stackend;
+#endif
+
        /*
         * Magic value to help recognize a valid thread structure
         * from an invalid one:
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to