1112918Sjeff/* 2112918Sjeff * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3112918Sjeff * All rights reserved. 4112918Sjeff * 5112918Sjeff * Redistribution and use in source and binary forms, with or without 6112918Sjeff * modification, are permitted provided that the following conditions 7112918Sjeff * are met: 8112918Sjeff * 1. Redistributions of source code must retain the above copyright 9112918Sjeff * notice, this list of conditions and the following disclaimer. 10112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11112918Sjeff * notice, this list of conditions and the following disclaimer in the 12112918Sjeff * documentation and/or other materials provided with the distribution. 13165967Simp * 3. Neither the name of the author nor the names of any co-contributors 14112918Sjeff * may be used to endorse or promote products derived from this software 15112918Sjeff * without specific prior written permission. 16112918Sjeff * 17112918Sjeff * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18112918Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19112918Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20112918Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21112918Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22112918Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23112918Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24112918Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25112918Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26112918Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27112918Sjeff * SUCH DAMAGE. 28112918Sjeff * 29112918Sjeff * $FreeBSD$ 30112918Sjeff */ 31144518Sdavidxu 32177605Sru#include "namespace.h" 33112918Sjeff#include <errno.h> 34212630Sdavidxu#ifdef _PTHREAD_FORCED_UNWIND 35212630Sdavidxu#include <dlfcn.h> 36212630Sdavidxu#endif 37112918Sjeff#include <stdio.h> 38112918Sjeff#include <stdlib.h> 39112918Sjeff#include <pthread.h> 40212076Sdavidxu#include <sys/types.h> 41212076Sdavidxu#include <sys/signalvar.h> 42177605Sru#include "un-namespace.h" 43144518Sdavidxu 44182225Sjasone#include "libc_private.h" 45112918Sjeff#include "thr_private.h" 46112918Sjeff 47144518Sdavidxuvoid _pthread_exit(void *status); 48144518Sdavidxu 49212630Sdavidxustatic void exit_thread(void) __dead2; 50212630Sdavidxu 51112918Sjeff__weak_reference(_pthread_exit, pthread_exit); 52112918Sjeff 53212630Sdavidxu#ifdef _PTHREAD_FORCED_UNWIND 54213159Sdavidxustatic int message_printed; 55212630Sdavidxu 56212630Sdavidxustatic void thread_unwind(void) __dead2; 57212630Sdavidxu#ifdef PIC 58212630Sdavidxustatic void thread_uw_init(void); 59212630Sdavidxustatic _Unwind_Reason_Code thread_unwind_stop(int version, 60212630Sdavidxu _Unwind_Action actions, 61213297Sdavidxu int64_t exc_class, 62212630Sdavidxu struct _Unwind_Exception *exc_obj, 63212630Sdavidxu struct _Unwind_Context *context, void *stop_parameter); 64212630Sdavidxu/* unwind library pointers */ 65212630Sdavidxustatic _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *, 66212630Sdavidxu _Unwind_Stop_Fn, void *); 67213297Sdavidxustatic unsigned long (*uwl_getcfa)(struct _Unwind_Context *); 68212630Sdavidxu 69212630Sdavidxustatic void 70212630Sdavidxuthread_uw_init(void) 71212630Sdavidxu{ 72212630Sdavidxu static int inited = 0; 73212837Sdavidxu Dl_info dlinfo; 74212630Sdavidxu void *handle; 75212838Sdavidxu void *forcedunwind, *getcfa; 76212630Sdavidxu 77212630Sdavidxu if (inited) 78212837Sdavidxu return; 79212630Sdavidxu handle = RTLD_DEFAULT; 80212837Sdavidxu if ((forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) != NULL) { 81212837Sdavidxu if (dladdr(forcedunwind, &dlinfo)) { 82212838Sdavidxu /* 83212838Sdavidxu * Make sure the address is always valid by holding the library, 84212838Sdavidxu * also assume functions are in same library. 85212838Sdavidxu */ 86212837Sdavidxu if ((handle = dlopen(dlinfo.dli_fname, RTLD_LAZY)) != NULL) { 87212837Sdavidxu forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind"); 88212837Sdavidxu getcfa = dlsym(handle, "_Unwind_GetCFA"); 89212838Sdavidxu if (forcedunwind != NULL && getcfa != NULL) { 90212837Sdavidxu uwl_getcfa = getcfa; 91212838Sdavidxu atomic_store_rel_ptr((volatile void *)&uwl_forcedunwind, 92212838Sdavidxu (uintptr_t)forcedunwind); 93212837Sdavidxu } else { 94212837Sdavidxu dlclose(handle); 95212837Sdavidxu } 96212837Sdavidxu } 97212837Sdavidxu } 98212630Sdavidxu } 99212837Sdavidxu inited = 1; 100212630Sdavidxu} 101212630Sdavidxu 102212630Sdavidxu_Unwind_Reason_Code 103212630Sdavidxu_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func, 104212630Sdavidxu void *stop_arg) 105212630Sdavidxu{ 106212630Sdavidxu return (*uwl_forcedunwind)(ex, stop_func, stop_arg); 107212630Sdavidxu} 108212630Sdavidxu 109213297Sdavidxuunsigned long 110212630Sdavidxu_Unwind_GetCFA(struct _Unwind_Context *context) 111212630Sdavidxu{ 112212630Sdavidxu return (*uwl_getcfa)(context); 113212630Sdavidxu} 114212630Sdavidxu#else 115212630Sdavidxu#pragma weak _Unwind_GetCFA 116212630Sdavidxu#pragma weak _Unwind_ForcedUnwind 117212630Sdavidxu#endif /* PIC */ 118212630Sdavidxu 119212630Sdavidxustatic void 120212630Sdavidxuthread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e) 121212630Sdavidxu{ 122212630Sdavidxu /* 123212630Sdavidxu * Specification said that _Unwind_Resume should not be used here, 124212630Sdavidxu * instead, user should rethrow the exception. For C++ user, they 125212630Sdavidxu * should put "throw" sentence in catch(...) block. 126212630Sdavidxu */ 127212630Sdavidxu PANIC("exception should be rethrown"); 128212630Sdavidxu} 129212630Sdavidxu 130212630Sdavidxustatic _Unwind_Reason_Code 131212630Sdavidxuthread_unwind_stop(int version, _Unwind_Action actions, 132213297Sdavidxu int64_t exc_class, 133212630Sdavidxu struct _Unwind_Exception *exc_obj, 134212630Sdavidxu struct _Unwind_Context *context, void *stop_parameter) 135212630Sdavidxu{ 136212630Sdavidxu struct pthread *curthread = _get_curthread(); 137212630Sdavidxu struct pthread_cleanup *cur; 138212630Sdavidxu uintptr_t cfa; 139212630Sdavidxu int done = 0; 140212630Sdavidxu 141212630Sdavidxu /* XXX assume stack grows down to lower address */ 142212630Sdavidxu 143212630Sdavidxu cfa = _Unwind_GetCFA(context); 144213154Sdavidxu if (actions & _UA_END_OF_STACK || 145213154Sdavidxu cfa >= (uintptr_t)curthread->unwind_stackend) { 146212630Sdavidxu done = 1; 147212630Sdavidxu } 148212630Sdavidxu 149212630Sdavidxu while ((cur = curthread->cleanup) != NULL && 150213154Sdavidxu (done || (uintptr_t)cur <= cfa)) { 151213154Sdavidxu __pthread_cleanup_pop_imp(1); 152212630Sdavidxu } 153212630Sdavidxu 154304527Skib if (done) { 155304527Skib /* Tell libc that it should call non-trivial TLS dtors. */ 156304527Skib __cxa_thread_call_dtors(); 157304527Skib 158212630Sdavidxu exit_thread(); /* Never return! */ 159304527Skib } 160212630Sdavidxu 161212630Sdavidxu return (_URC_NO_REASON); 162212630Sdavidxu} 163212630Sdavidxu 164212630Sdavidxustatic void 165212630Sdavidxuthread_unwind(void) 166212630Sdavidxu{ 167212630Sdavidxu struct pthread *curthread = _get_curthread(); 168212630Sdavidxu 169212630Sdavidxu curthread->ex.exception_class = 0; 170212630Sdavidxu curthread->ex.exception_cleanup = thread_unwind_cleanup; 171212630Sdavidxu _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL); 172212630Sdavidxu PANIC("_Unwind_ForcedUnwind returned"); 173212630Sdavidxu} 174212630Sdavidxu 175212630Sdavidxu#endif 176212630Sdavidxu 177212630Sdavidxuvoid 178157457Sdavidxu_thread_exit(const char *fname, int lineno, const char *msg) 179112918Sjeff{ 180112918Sjeff 181144518Sdavidxu /* Write an error message to the standard error file descriptor: */ 182144518Sdavidxu _thread_printf(2, 183112918Sjeff "Fatal error '%s' at line %d in file %s (errno = %d)\n", 184144518Sdavidxu msg, lineno, fname, errno); 185112918Sjeff 186112918Sjeff abort(); 187112918Sjeff} 188112918Sjeff 189112918Sjeffvoid 190112918Sjeff_pthread_exit(void *status) 191112918Sjeff{ 192212076Sdavidxu _pthread_exit_mask(status, NULL); 193212076Sdavidxu} 194212076Sdavidxu 195212076Sdavidxuvoid 196212076Sdavidxu_pthread_exit_mask(void *status, sigset_t *mask) 197212076Sdavidxu{ 198144518Sdavidxu struct pthread *curthread = _get_curthread(); 199112918Sjeff 200112918Sjeff /* Check if this thread is already in the process of exiting: */ 201164583Sdavidxu if (curthread->cancelling) { 202112918Sjeff char msg[128]; 203144518Sdavidxu snprintf(msg, sizeof(msg), "Thread %p has called " 204144518Sdavidxu "pthread_exit() from a destructor. POSIX 1003.1 " 205144518Sdavidxu "1996 s16.2.5.2 does not allow this!", curthread); 206112918Sjeff PANIC(msg); 207112918Sjeff } 208112918Sjeff 209144518Sdavidxu /* Flag this thread as exiting. */ 210164583Sdavidxu curthread->cancelling = 1; 211212841Sdavidxu curthread->no_cancel = 1; 212211409Sdavidxu curthread->cancel_async = 0; 213212076Sdavidxu curthread->cancel_point = 0; 214212076Sdavidxu if (mask != NULL) 215212076Sdavidxu __sys_sigprocmask(SIG_SETMASK, mask, NULL); 216212076Sdavidxu if (curthread->unblock_sigcancel) { 217212076Sdavidxu sigset_t set; 218212076Sdavidxu 219212076Sdavidxu curthread->unblock_sigcancel = 0; 220212076Sdavidxu SIGEMPTYSET(set); 221212076Sdavidxu SIGADDSET(set, SIGCANCEL); 222212076Sdavidxu __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); 223212076Sdavidxu } 224144518Sdavidxu 225112918Sjeff /* Save the return value: */ 226112918Sjeff curthread->ret = status; 227212630Sdavidxu#ifdef _PTHREAD_FORCED_UNWIND 228213159Sdavidxu 229212630Sdavidxu#ifdef PIC 230212630Sdavidxu thread_uw_init(); 231213159Sdavidxu#endif /* PIC */ 232213159Sdavidxu 233213159Sdavidxu#ifdef PIC 234212630Sdavidxu if (uwl_forcedunwind != NULL) { 235212630Sdavidxu#else 236212630Sdavidxu if (_Unwind_ForcedUnwind != NULL) { 237213159Sdavidxu#endif 238213159Sdavidxu if (curthread->unwind_disabled) { 239213159Sdavidxu if (message_printed == 0) { 240213159Sdavidxu message_printed = 1; 241213159Sdavidxu _thread_printf(2, "Warning: old _pthread_cleanup_push was called, " 242213159Sdavidxu "stack unwinding is disabled.\n"); 243213159Sdavidxu } 244213159Sdavidxu goto cleanup; 245213159Sdavidxu } 246212630Sdavidxu thread_unwind(); 247212630Sdavidxu 248213159Sdavidxu } else { 249213159Sdavidxucleanup: 250212630Sdavidxu while (curthread->cleanup != NULL) { 251212630Sdavidxu __pthread_cleanup_pop_imp(1); 252212630Sdavidxu } 253304527Skib __cxa_thread_call_dtors(); 254304527Skib 255212630Sdavidxu exit_thread(); 256212630Sdavidxu } 257212630Sdavidxu 258212630Sdavidxu#else 259112918Sjeff while (curthread->cleanup != NULL) { 260212630Sdavidxu __pthread_cleanup_pop_imp(1); 261112918Sjeff } 262304527Skib __cxa_thread_call_dtors(); 263157457Sdavidxu 264212630Sdavidxu exit_thread(); 265212630Sdavidxu#endif /* _PTHREAD_FORCED_UNWIND */ 266212630Sdavidxu} 267212630Sdavidxu 268212630Sdavidxustatic void 269212630Sdavidxuexit_thread(void) 270212630Sdavidxu{ 271212630Sdavidxu struct pthread *curthread = _get_curthread(); 272212630Sdavidxu 273112918Sjeff /* Check if there is thread specific data: */ 274112918Sjeff if (curthread->specific != NULL) { 275112918Sjeff /* Run the thread-specific data destructors: */ 276112918Sjeff _thread_cleanupspecific(); 277112918Sjeff } 278112918Sjeff 279144518Sdavidxu if (!_thr_isthreaded()) 280144518Sdavidxu exit(0); 281115357Smtm 282212536Sdavidxu if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { 283115387Smtm exit(0); 284144518Sdavidxu /* Never reach! */ 285127523Smtm } 286182894Sjasone 287182894Sjasone /* Tell malloc that the thread is exiting. */ 288182894Sjasone _malloc_thread_cleanup(); 289182894Sjasone 290154055Sdavidxu THR_LOCK(curthread); 291154055Sdavidxu curthread->state = PS_DEAD; 292177337Sdavidxu if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 293177337Sdavidxu curthread->cycle++; 294178647Sdavidxu _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 295177337Sdavidxu } 296213182Sdavidxu if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 297213182Sdavidxu _thr_report_death(curthread); 298154055Sdavidxu /* 299154055Sdavidxu * Thread was created with initial refcount 1, we drop the 300154055Sdavidxu * reference count to allow it to be garbage collected. 301154055Sdavidxu */ 302154055Sdavidxu curthread->refcount--; 303212536Sdavidxu _thr_try_gc(curthread, curthread); /* thread lock released */ 304212536Sdavidxu 305212536Sdavidxu#if defined(_PTHREADS_INVARIANTS) 306212536Sdavidxu if (THR_IN_CRITICAL(curthread)) 307212536Sdavidxu PANIC("thread exits with resources held!"); 308212536Sdavidxu#endif 309151694Sdavidxu /* 310151694Sdavidxu * Kernel will do wakeup at the address, so joiner thread 311151694Sdavidxu * will be resumed if it is sleeping at the address. 312151694Sdavidxu */ 313144921Sdavidxu thr_exit(&curthread->tid); 314144518Sdavidxu PANIC("thr_exit() returned"); 315144518Sdavidxu /* Never reach! */ 316127523Smtm} 317