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.
This commit is contained in:
David Xu 2010-09-15 02:56:32 +00:00
parent 707ee8154d
commit 3832fd24f1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=212630
6 changed files with 185 additions and 2 deletions

View File

@ -25,6 +25,14 @@ CFLAGS+=-I${.CURDIR}/../../libexec/rtld-elf
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

View File

@ -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
}

View File

@ -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));

View File

@ -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,9 +215,38 @@ _pthread_exit_mask(void *status, sigset_t *mask)
/* Save the return value: */
curthread->ret = status;
while (curthread->cleanup != NULL) {
_pthread_cleanup_pop(1);
#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_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) {

View File

@ -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() */
}

View File

@ -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: