From owner-svn-src-all@FreeBSD.ORG Wed Sep 15 02:56:33 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 480BB1065670; Wed, 15 Sep 2010 02:56:33 +0000 (UTC) (envelope-from davidxu@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 366248FC12; Wed, 15 Sep 2010 02:56:33 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o8F2uXpV004586; Wed, 15 Sep 2010 02:56:33 GMT (envelope-from davidxu@svn.freebsd.org) Received: (from davidxu@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o8F2uXwX004579; Wed, 15 Sep 2010 02:56:33 GMT (envelope-from davidxu@svn.freebsd.org) Message-Id: <201009150256.o8F2uXwX004579@svn.freebsd.org> From: David Xu Date: Wed, 15 Sep 2010 02:56:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r212630 - in head/lib/libthr: . thread X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Sep 2010 02:56:33 -0000 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 +#ifdef _PTHREAD_FORCED_UNWIND +#include +#endif #include #include #include @@ -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 +#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: