thr_exit.c revision 304527
1226633Sdim/* 2193326Sed * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3193326Sed * All rights reserved. 4193326Sed * 5193326Sed * Redistribution and use in source and binary forms, with or without 6193326Sed * modification, are permitted provided that the following conditions 7193326Sed * are met: 8193326Sed * 1. Redistributions of source code must retain the above copyright 9193326Sed * notice, this list of conditions and the following disclaimer. 10193326Sed * 2. Redistributions in binary form must reproduce the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer in the 12193326Sed * documentation and/or other materials provided with the distribution. 13193326Sed * 3. Neither the name of the author nor the names of any co-contributors 14193326Sed * may be used to endorse or promote products derived from this software 15193326Sed * without specific prior written permission. 16193326Sed * 17249423Sdim * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18226633Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19226633Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20226633Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21193326Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24226633Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25226633Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26193326Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27193326Sed * SUCH DAMAGE. 28193326Sed * 29226633Sdim * $FreeBSD: stable/10/lib/libthr/thread/thr_exit.c 304527 2016-08-20 12:26:44Z kib $ 30226633Sdim */ 31226633Sdim 32226633Sdim#include "namespace.h" 33226633Sdim#include <errno.h> 34198092Srdivacky#ifdef _PTHREAD_FORCED_UNWIND 35226633Sdim#include <dlfcn.h> 36226633Sdim#endif 37226633Sdim#include <stdio.h> 38226633Sdim#include <stdlib.h> 39193326Sed#include <pthread.h> 40226633Sdim#include <sys/types.h> 41226633Sdim#include <sys/signalvar.h> 42193326Sed#include "un-namespace.h" 43226633Sdim 44226633Sdim#include "libc_private.h" 45226633Sdim#include "thr_private.h" 46193326Sed 47226633Sdimvoid _pthread_exit(void *status); 48226633Sdim 49226633Sdimstatic void exit_thread(void) __dead2; 50226633Sdim 51226633Sdim__weak_reference(_pthread_exit, pthread_exit); 52226633Sdim 53193326Sed#ifdef _PTHREAD_FORCED_UNWIND 54226633Sdimstatic int message_printed; 55234353Sdim 56234353Sdimstatic void thread_unwind(void) __dead2; 57234353Sdim#ifdef PIC 58226633Sdimstatic void thread_uw_init(void); 59226633Sdimstatic _Unwind_Reason_Code thread_unwind_stop(int version, 60226633Sdim _Unwind_Action actions, 61193326Sed int64_t exc_class, 62226633Sdim struct _Unwind_Exception *exc_obj, 63226633Sdim struct _Unwind_Context *context, void *stop_parameter); 64226633Sdim/* unwind library pointers */ 65226633Sdimstatic _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *, 66226633Sdim _Unwind_Stop_Fn, void *); 67226633Sdimstatic unsigned long (*uwl_getcfa)(struct _Unwind_Context *); 68226633Sdim 69226633Sdimstatic void 70198092Srdivackythread_uw_init(void) 71193326Sed{ 72226633Sdim static int inited = 0; 73226633Sdim Dl_info dlinfo; 74226633Sdim void *handle; 75234353Sdim void *forcedunwind, *getcfa; 76226633Sdim 77226633Sdim if (inited) 78226633Sdim return; 79193326Sed handle = RTLD_DEFAULT; 80226633Sdim if ((forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) != NULL) { 81226633Sdim if (dladdr(forcedunwind, &dlinfo)) { 82226633Sdim /* 83193326Sed * Make sure the address is always valid by holding the library, 84193326Sed * also assume functions are in same library. 85193326Sed */ 86226633Sdim if ((handle = dlopen(dlinfo.dli_fname, RTLD_LAZY)) != NULL) { 87226633Sdim forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind"); 88226633Sdim getcfa = dlsym(handle, "_Unwind_GetCFA"); 89193326Sed if (forcedunwind != NULL && getcfa != NULL) { 90226633Sdim uwl_getcfa = getcfa; 91226633Sdim atomic_store_rel_ptr((volatile void *)&uwl_forcedunwind, 92226633Sdim (uintptr_t)forcedunwind); 93226633Sdim } else { 94226633Sdim dlclose(handle); 95198092Srdivacky } 96226633Sdim } 97226633Sdim } 98234353Sdim } 99226633Sdim inited = 1; 100226633Sdim} 101226633Sdim 102226633Sdim_Unwind_Reason_Code 103226633Sdim_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func, 104226633Sdim void *stop_arg) 105226633Sdim{ 106226633Sdim return (*uwl_forcedunwind)(ex, stop_func, stop_arg); 107193326Sed} 108226633Sdim 109226633Sdimunsigned long 110226633Sdim_Unwind_GetCFA(struct _Unwind_Context *context) 111234353Sdim{ 112226633Sdim return (*uwl_getcfa)(context); 113226633Sdim} 114226633Sdim#else 115226633Sdim#pragma weak _Unwind_GetCFA 116226633Sdim#pragma weak _Unwind_ForcedUnwind 117226633Sdim#endif /* PIC */ 118193326Sed 119193326Sedstatic void 120193326Sedthread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e) 121{ 122 /* 123 * Specification said that _Unwind_Resume should not be used here, 124 * instead, user should rethrow the exception. For C++ user, they 125 * should put "throw" sentence in catch(...) block. 126 */ 127 PANIC("exception should be rethrown"); 128} 129 130static _Unwind_Reason_Code 131thread_unwind_stop(int version, _Unwind_Action actions, 132 int64_t exc_class, 133 struct _Unwind_Exception *exc_obj, 134 struct _Unwind_Context *context, void *stop_parameter) 135{ 136 struct pthread *curthread = _get_curthread(); 137 struct pthread_cleanup *cur; 138 uintptr_t cfa; 139 int done = 0; 140 141 /* XXX assume stack grows down to lower address */ 142 143 cfa = _Unwind_GetCFA(context); 144 if (actions & _UA_END_OF_STACK || 145 cfa >= (uintptr_t)curthread->unwind_stackend) { 146 done = 1; 147 } 148 149 while ((cur = curthread->cleanup) != NULL && 150 (done || (uintptr_t)cur <= cfa)) { 151 __pthread_cleanup_pop_imp(1); 152 } 153 154 if (done) { 155 /* Tell libc that it should call non-trivial TLS dtors. */ 156 __cxa_thread_call_dtors(); 157 158 exit_thread(); /* Never return! */ 159 } 160 161 return (_URC_NO_REASON); 162} 163 164static void 165thread_unwind(void) 166{ 167 struct pthread *curthread = _get_curthread(); 168 169 curthread->ex.exception_class = 0; 170 curthread->ex.exception_cleanup = thread_unwind_cleanup; 171 _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL); 172 PANIC("_Unwind_ForcedUnwind returned"); 173} 174 175#endif 176 177void 178_thread_exit(const char *fname, int lineno, const char *msg) 179{ 180 181 /* Write an error message to the standard error file descriptor: */ 182 _thread_printf(2, 183 "Fatal error '%s' at line %d in file %s (errno = %d)\n", 184 msg, lineno, fname, errno); 185 186 abort(); 187} 188 189void 190_pthread_exit(void *status) 191{ 192 _pthread_exit_mask(status, NULL); 193} 194 195void 196_pthread_exit_mask(void *status, sigset_t *mask) 197{ 198 struct pthread *curthread = _get_curthread(); 199 200 /* Check if this thread is already in the process of exiting: */ 201 if (curthread->cancelling) { 202 char msg[128]; 203 snprintf(msg, sizeof(msg), "Thread %p has called " 204 "pthread_exit() from a destructor. POSIX 1003.1 " 205 "1996 s16.2.5.2 does not allow this!", curthread); 206 PANIC(msg); 207 } 208 209 /* Flag this thread as exiting. */ 210 curthread->cancelling = 1; 211 curthread->no_cancel = 1; 212 curthread->cancel_async = 0; 213 curthread->cancel_point = 0; 214 if (mask != NULL) 215 __sys_sigprocmask(SIG_SETMASK, mask, NULL); 216 if (curthread->unblock_sigcancel) { 217 sigset_t set; 218 219 curthread->unblock_sigcancel = 0; 220 SIGEMPTYSET(set); 221 SIGADDSET(set, SIGCANCEL); 222 __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); 223 } 224 225 /* Save the return value: */ 226 curthread->ret = status; 227#ifdef _PTHREAD_FORCED_UNWIND 228 229#ifdef PIC 230 thread_uw_init(); 231#endif /* PIC */ 232 233#ifdef PIC 234 if (uwl_forcedunwind != NULL) { 235#else 236 if (_Unwind_ForcedUnwind != NULL) { 237#endif 238 if (curthread->unwind_disabled) { 239 if (message_printed == 0) { 240 message_printed = 1; 241 _thread_printf(2, "Warning: old _pthread_cleanup_push was called, " 242 "stack unwinding is disabled.\n"); 243 } 244 goto cleanup; 245 } 246 thread_unwind(); 247 248 } else { 249cleanup: 250 while (curthread->cleanup != NULL) { 251 __pthread_cleanup_pop_imp(1); 252 } 253 __cxa_thread_call_dtors(); 254 255 exit_thread(); 256 } 257 258#else 259 while (curthread->cleanup != NULL) { 260 __pthread_cleanup_pop_imp(1); 261 } 262 __cxa_thread_call_dtors(); 263 264 exit_thread(); 265#endif /* _PTHREAD_FORCED_UNWIND */ 266} 267 268static void 269exit_thread(void) 270{ 271 struct pthread *curthread = _get_curthread(); 272 273 /* Check if there is thread specific data: */ 274 if (curthread->specific != NULL) { 275 /* Run the thread-specific data destructors: */ 276 _thread_cleanupspecific(); 277 } 278 279 if (!_thr_isthreaded()) 280 exit(0); 281 282 if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { 283 exit(0); 284 /* Never reach! */ 285 } 286 287 /* Tell malloc that the thread is exiting. */ 288 _malloc_thread_cleanup(); 289 290 THR_LOCK(curthread); 291 curthread->state = PS_DEAD; 292 if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 293 curthread->cycle++; 294 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 295 } 296 if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 297 _thr_report_death(curthread); 298 /* 299 * Thread was created with initial refcount 1, we drop the 300 * reference count to allow it to be garbage collected. 301 */ 302 curthread->refcount--; 303 _thr_try_gc(curthread, curthread); /* thread lock released */ 304 305#if defined(_PTHREADS_INVARIANTS) 306 if (THR_IN_CRITICAL(curthread)) 307 PANIC("thread exits with resources held!"); 308#endif 309 /* 310 * Kernel will do wakeup at the address, so joiner thread 311 * will be resumed if it is sleeping at the address. 312 */ 313 thr_exit(&curthread->tid); 314 PANIC("thr_exit() returned"); 315 /* Never reach! */ 316} 317