diff options
author | davidxu <davidxu@FreeBSD.org> | 2010-09-15 02:56:32 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2010-09-15 02:56:32 +0000 |
commit | b00fcaa22c4d87d8f0c95731f5e8325abfbc2075 (patch) | |
tree | fedf4c03bd378db206ea154a805f96e271f05b28 /lib/libthr/thread | |
parent | 6be463abbb69aa61ab186c9cba314068612328ba (diff) | |
download | FreeBSD-src-b00fcaa22c4d87d8f0c95731f5e8325abfbc2075.zip FreeBSD-src-b00fcaa22c4d87d8f0c95731f5e8325abfbc2075.tar.gz |
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.
Diffstat (limited to 'lib/libthr/thread')
-rw-r--r-- | lib/libthr/thread/thr_clean.c | 8 | ||||
-rw-r--r-- | lib/libthr/thread/thr_create.c | 5 | ||||
-rw-r--r-- | lib/libthr/thread/thr_exit.c | 151 | ||||
-rw-r--r-- | lib/libthr/thread/thr_init.c | 4 | ||||
-rw-r--r-- | lib/libthr/thread/thr_private.h | 9 |
5 files changed, 176 insertions, 1 deletions
diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c index 9cef930..b37a1b5 100644 --- a/lib/libthr/thread/thr_clean.c +++ b/lib/libthr/thread/thr_clean.c @@ -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) (void *), void *arg) 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 } diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c index d4f5a11..f0af20b 100644 --- a/lib/libthr/thread/thr_create.c +++ b/lib/libthr/thread/thr_create.c @@ -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)); diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c index 9e2e0cb..2ff3953 100644 --- a/lib/libthr/thread/thr_exit.c +++ b/lib/libthr/thread/thr_exit.c @@ -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_t *mask) /* 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: */ diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index c20f3c8..56541a8 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -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() */ } diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index fd5a2af..c18eb3d 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -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: |