summaryrefslogtreecommitdiffstats
path: root/lib/libthr/thread
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2010-09-15 02:56:32 +0000
committerdavidxu <davidxu@FreeBSD.org>2010-09-15 02:56:32 +0000
commitb00fcaa22c4d87d8f0c95731f5e8325abfbc2075 (patch)
treefedf4c03bd378db206ea154a805f96e271f05b28 /lib/libthr/thread
parent6be463abbb69aa61ab186c9cba314068612328ba (diff)
downloadFreeBSD-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.c8
-rw-r--r--lib/libthr/thread/thr_create.c5
-rw-r--r--lib/libthr/thread/thr_exit.c151
-rw-r--r--lib/libthr/thread/thr_init.c4
-rw-r--r--lib/libthr/thread/thr_private.h9
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:
OpenPOWER on IntegriCloud