Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Sep 2010 02:56:33 +0000 (UTC)
From:      David Xu <davidxu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r212630 - in head/lib/libthr: . thread
Message-ID:  <201009150256.o8F2uXwX004579@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009150256.o8F2uXwX004579>