thr_exit.c revision 212837
1177391Sobrien/* 2107484Speter * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 381404Speter * All rights reserved. 4175261Sobrien * 5177391Sobrien * Redistribution and use in source and binary forms, with or without 681404Speter * modification, are permitted provided that the following conditions 781404Speter * are met: 881404Speter * 1. Redistributions of source code must retain the above copyright 981404Speter * notice, this list of conditions and the following disclaimer. 1081404Speter * 2. Redistributions in binary form must reproduce the above copyright 1181404Speter * notice, this list of conditions and the following disclaimer in the 1281404Speter * documentation and/or other materials provided with the distribution. 1381404Speter * 3. Neither the name of the author nor the names of any co-contributors 1481404Speter * may be used to endorse or promote products derived from this software 1581404Speter * without specific prior written permission. 1681404Speter * 1717721Speter * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 1817721Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19175261Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20175261Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21175261Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22175261Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23175261Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2417721Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2517721Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2617721Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2717721Speter * SUCH DAMAGE. 2817721Speter * 2917721Speter * $FreeBSD: head/lib/libthr/thread/thr_exit.c 212837 2010-09-19 05:19:47Z davidxu $ 3017721Speter */ 3117721Speter 3217721Speter#include "namespace.h" 3317721Speter#include <errno.h> 3481404Speter#ifdef _PTHREAD_FORCED_UNWIND 35175261Sobrien#include <dlfcn.h> 3681404Speter#endif 3781404Speter#include <stdio.h> 3881404Speter#include <stdlib.h> 3981404Speter#include <pthread.h> 40107484Speter#include <sys/types.h> 41107484Speter#include <sys/signalvar.h> 42107484Speter#include "un-namespace.h" 43107484Speter 4481404Speter#include "libc_private.h" 45128266Speter#include "thr_private.h" 4681404Speter 4781404Spetervoid _pthread_exit(void *status); 4881404Speter 4981404Speterstatic void exit_thread(void) __dead2; 5081404Speter 5181404Speter__weak_reference(_pthread_exit, pthread_exit); 52175261Sobrien 53175261Sobrien#ifdef _PTHREAD_FORCED_UNWIND 54175261Sobrien 55175261Sobrienstatic void thread_unwind(void) __dead2; 56175261Sobrien#ifdef PIC 57175261Sobrienstatic void thread_uw_init(void); 58175261Sobrienstatic _Unwind_Reason_Code thread_unwind_stop(int version, 59175261Sobrien _Unwind_Action actions, 60175261Sobrien _Unwind_Exception_Class exc_class, 61175261Sobrien struct _Unwind_Exception *exc_obj, 62175261Sobrien struct _Unwind_Context *context, void *stop_parameter); 63175261Sobrien/* unwind library pointers */ 64175261Sobrienstatic _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *, 65175261Sobrien _Unwind_Stop_Fn, void *); 66175261Sobrienstatic void (*uwl_resume)(struct _Unwind_Exception *exc); 67175261Sobrienstatic _Unwind_Word (*uwl_getcfa)(struct _Unwind_Context *); 68175261Sobrien 69175261Sobrienstatic void 70175261Sobrienthread_uw_init(void) 71175261Sobrien{ 72175261Sobrien static int inited = 0; 73175261Sobrien Dl_info dlinfo; 74175261Sobrien void *handle; 75175261Sobrien void *forcedunwind, *resume, *getcfa; 76175261Sobrien 77175261Sobrien if (inited) 78175261Sobrien return; 79175261Sobrien handle = RTLD_DEFAULT; 80175261Sobrien if ((forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) != NULL) { 81175261Sobrien if (dladdr(forcedunwind, &dlinfo)) { 82128266Speter if ((handle = dlopen(dlinfo.dli_fname, RTLD_LAZY)) != NULL) { 8381404Speter forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind"); 84128266Speter resume = dlsym(handle, "_Unwind_Resume"); 85128266Speter getcfa = dlsym(handle, "_Unwind_GetCFA"); 86128266Speter if (forcedunwind != NULL && resume != NULL && 8781404Speter getcfa != NULL) { 8881404Speter uwl_forcedunwind = forcedunwind; 89128266Speter uwl_resume = resume; 90128266Speter uwl_getcfa = getcfa; 91128266Speter } else { 92128266Speter dlclose(handle); 9381404Speter } 94128266Speter } 95128266Speter } 9681404Speter } 97128266Speter inited = 1; 98128266Speter} 99128266Speter 100107484Spetervoid 101128266Speter_Unwind_Resume(struct _Unwind_Exception *ex) 102128266Speter{ 103177391Sobrien (*uwl_resume)(ex); 104177391Sobrien} 105128266Speter 106128266Speter_Unwind_Reason_Code 107128266Speter_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func, 10881404Speter void *stop_arg) 10981404Speter{ 110128266Speter return (*uwl_forcedunwind)(ex, stop_func, stop_arg); 111128266Speter} 112128266Speter 11381404Speter_Unwind_Word 114128266Speter_Unwind_GetCFA(struct _Unwind_Context *context) 115128266Speter{ 116128266Speter return (*uwl_getcfa)(context); 117177391Sobrien} 118128266Speter#else 119128266Speter#pragma weak _Unwind_GetCFA 12081404Speter#pragma weak _Unwind_ForcedUnwind 121128266Speter#pragma weak _Unwind_Resume 122128266Speter#endif /* PIC */ 123128266Speter 124128266Speterstatic void 125128266Speterthread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e) 126128266Speter{ 12781404Speter /* 12881404Speter * Specification said that _Unwind_Resume should not be used here, 12981404Speter * instead, user should rethrow the exception. For C++ user, they 13081404Speter * should put "throw" sentence in catch(...) block. 13181404Speter */ 132128266Speter PANIC("exception should be rethrown"); 133128266Speter} 134128266Speter 135107484Speterstatic _Unwind_Reason_Code 13681404Speterthread_unwind_stop(int version, _Unwind_Action actions, 13781404Speter _Unwind_Exception_Class exc_class, 13881404Speter struct _Unwind_Exception *exc_obj, 139177391Sobrien struct _Unwind_Context *context, void *stop_parameter) 140177391Sobrien{ 141177391Sobrien struct pthread *curthread = _get_curthread(); 142177391Sobrien struct pthread_cleanup *cur; 143177391Sobrien uintptr_t cfa; 144128266Speter int done = 0; 145128266Speter 146102840Speter /* XXX assume stack grows down to lower address */ 147128266Speter 148102840Speter cfa = _Unwind_GetCFA(context); 149175261Sobrien if (actions & _UA_END_OF_STACK) { 150175261Sobrien done = 1; 151128266Speter } else if (cfa >= (uintptr_t)curthread->unwind_stackend) { 152128266Speter done = 1; 153177391Sobrien } 154128266Speter 155177391Sobrien while ((cur = curthread->cleanup) != NULL && 156177391Sobrien (done || 157177391Sobrien ((uintptr_t)cur < (uintptr_t)curthread->unwind_stackend && 158128266Speter (uintptr_t)cur >= cfa))) { 159128266Speter __pthread_cleanup_pop_imp(1); 160177391Sobrien } 161128266Speter 16281404Speter if (done) 163128266Speter exit_thread(); /* Never return! */ 16481404Speter 165128266Speter return (_URC_NO_REASON); 166128266Speter} 167177391Sobrien 168128266Speterstatic void 169128266Speterthread_unwind(void) 170175261Sobrien{ 171128266Speter struct pthread *curthread = _get_curthread(); 172177391Sobrien 173128266Speter curthread->ex.exception_class = 0; 174128266Speter curthread->ex.exception_cleanup = thread_unwind_cleanup; 175177391Sobrien _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL); 176128266Speter PANIC("_Unwind_ForcedUnwind returned"); 177128266Speter} 178177391Sobrien 179128266Speter#endif 180128266Speter 181177391Sobrienvoid 182177391Sobrien_thread_exit(const char *fname, int lineno, const char *msg) 183175261Sobrien{ 184177391Sobrien 18581404Speter /* Write an error message to the standard error file descriptor: */ 18681404Speter _thread_printf(2, 187107484Speter "Fatal error '%s' at line %d in file %s (errno = %d)\n", 18881404Speter msg, lineno, fname, errno); 18981404Speter 19081404Speter abort(); 19181404Speter} 19281404Speter 19381404Spetervoid 19481404Speter_pthread_exit(void *status) 19581404Speter{ 19681404Speter _pthread_exit_mask(status, NULL); 19781404Speter} 198102840Speter 19981404Spetervoid 20081404Speter_pthread_exit_mask(void *status, sigset_t *mask) 20181404Speter{ 20281404Speter struct pthread *curthread = _get_curthread(); 20317721Speter 20481404Speter /* Check if this thread is already in the process of exiting: */ 20581404Speter if (curthread->cancelling) { 20681404Speter char msg[128]; 20717721Speter snprintf(msg, sizeof(msg), "Thread %p has called " 20881404Speter "pthread_exit() from a destructor. POSIX 1003.1 " 20981404Speter "1996 s16.2.5.2 does not allow this!", curthread); 21017721Speter PANIC(msg); 21181404Speter } 21281404Speter 21381404Speter /* Flag this thread as exiting. */ 21481404Speter curthread->cancelling = 1; 21581404Speter curthread->cancel_enable = 0; 21681404Speter curthread->cancel_async = 0; 21781404Speter curthread->cancel_point = 0; 21881404Speter if (mask != NULL) 21981404Speter __sys_sigprocmask(SIG_SETMASK, mask, NULL); 22081404Speter if (curthread->unblock_sigcancel) { 221175261Sobrien sigset_t set; 22281404Speter 22381404Speter curthread->unblock_sigcancel = 0; 22481404Speter SIGEMPTYSET(set); 22581404Speter SIGADDSET(set, SIGCANCEL); 22681404Speter __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); 22781404Speter } 22881404Speter 22981404Speter /* Save the return value: */ 23081404Speter curthread->ret = status; 23181404Speter#ifdef _PTHREAD_FORCED_UNWIND 23281404Speter#ifdef PIC 23381404Speter thread_uw_init(); 23481404Speter if (uwl_forcedunwind != NULL) { 23581404Speter thread_unwind(); 236175261Sobrien } 237175261Sobrien#else 238175261Sobrien if (_Unwind_ForcedUnwind != NULL) { 239175261Sobrien thread_unwind(); 240175261Sobrien } 241175261Sobrien#endif /* PIC */ 242175261Sobrien 243175261Sobrien else { 244175261Sobrien while (curthread->cleanup != NULL) { 245175261Sobrien __pthread_cleanup_pop_imp(1); 24681404Speter } 24781404Speter exit_thread(); 248175261Sobrien } 249175261Sobrien 250175261Sobrien#else 251175261Sobrien while (curthread->cleanup != NULL) { 252175261Sobrien __pthread_cleanup_pop_imp(1); 253175261Sobrien } 254175261Sobrien 255175261Sobrien exit_thread(); 256175261Sobrien#endif /* _PTHREAD_FORCED_UNWIND */ 257175261Sobrien} 258175261Sobrien 259175261Sobrienstatic void 260175261Sobrienexit_thread(void) 261175261Sobrien{ 262175261Sobrien struct pthread *curthread = _get_curthread(); 263175261Sobrien 264175261Sobrien /* Check if there is thread specific data: */ 265175261Sobrien if (curthread->specific != NULL) { 266107484Speter /* Run the thread-specific data destructors: */ 267175261Sobrien _thread_cleanupspecific(); 268107484Speter } 269175261Sobrien 270107484Speter if (!_thr_isthreaded()) 271175261Sobrien exit(0); 272107484Speter 273175261Sobrien if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { 274107484Speter exit(0); 275175261Sobrien /* Never reach! */ 276107484Speter } 277175261Sobrien 278107484Speter /* Tell malloc that the thread is exiting. */ 279175261Sobrien _malloc_thread_cleanup(); 280107484Speter 281175261Sobrien THR_LOCK(curthread); 282107484Speter curthread->state = PS_DEAD; 283175261Sobrien if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 284128266Speter curthread->cycle++; 285175261Sobrien _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 286107484Speter } 287175261Sobrien /* 288107484Speter * Thread was created with initial refcount 1, we drop the 28981404Speter * reference count to allow it to be garbage collected. 29081404Speter */ 291177391Sobrien curthread->refcount--; 29281404Speter _thr_try_gc(curthread, curthread); /* thread lock released */ 293107484Speter 294107484Speter if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 295107484Speter _thr_report_death(curthread); 296175261Sobrien 297175261Sobrien#if defined(_PTHREADS_INVARIANTS) 29881404Speter if (THR_IN_CRITICAL(curthread)) 29917721Speter PANIC("thread exits with resources held!"); 30081404Speter#endif 30181404Speter /* 30281404Speter * Kernel will do wakeup at the address, so joiner thread 30381404Speter * will be resumed if it is sleeping at the address. 304107484Speter */ 305175261Sobrien thr_exit(&curthread->tid); 306175261Sobrien PANIC("thr_exit() returned"); 30717721Speter /* Never reach! */ 30881404Speter} 30981404Speter