thr_exit.c revision 304524
1/* 2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: stable/11/lib/libthr/thread/thr_exit.c 304524 2016-08-20 11:58:23Z kib $"); 32 33#include "namespace.h" 34#include <errno.h> 35#ifdef _PTHREAD_FORCED_UNWIND 36#include <dlfcn.h> 37#endif 38#include <stdarg.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <pthread.h> 42#include <sys/types.h> 43#include <sys/signalvar.h> 44#include "un-namespace.h" 45 46#include "libc_private.h" 47#include "thr_private.h" 48 49void _pthread_exit(void *status); 50 51static void exit_thread(void) __dead2; 52 53__weak_reference(_pthread_exit, pthread_exit); 54 55#ifdef _PTHREAD_FORCED_UNWIND 56static int message_printed; 57 58static void thread_unwind(void) __dead2; 59#ifdef PIC 60static void thread_uw_init(void); 61static _Unwind_Reason_Code thread_unwind_stop(int version, 62 _Unwind_Action actions, 63 int64_t exc_class, 64 struct _Unwind_Exception *exc_obj, 65 struct _Unwind_Context *context, void *stop_parameter); 66/* unwind library pointers */ 67static _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *, 68 _Unwind_Stop_Fn, void *); 69static unsigned long (*uwl_getcfa)(struct _Unwind_Context *); 70 71static void 72thread_uw_init(void) 73{ 74 static int inited = 0; 75 Dl_info dlinfo; 76 void *handle; 77 void *forcedunwind, *getcfa; 78 79 if (inited) 80 return; 81 handle = RTLD_DEFAULT; 82 if ((forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) != NULL) { 83 if (dladdr(forcedunwind, &dlinfo)) { 84 /* 85 * Make sure the address is always valid by holding the library, 86 * also assume functions are in same library. 87 */ 88 if ((handle = dlopen(dlinfo.dli_fname, RTLD_LAZY)) != NULL) { 89 forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind"); 90 getcfa = dlsym(handle, "_Unwind_GetCFA"); 91 if (forcedunwind != NULL && getcfa != NULL) { 92 uwl_getcfa = getcfa; 93 atomic_store_rel_ptr((volatile void *)&uwl_forcedunwind, 94 (uintptr_t)forcedunwind); 95 } else { 96 dlclose(handle); 97 } 98 } 99 } 100 } 101 inited = 1; 102} 103 104_Unwind_Reason_Code 105_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func, 106 void *stop_arg) 107{ 108 return (*uwl_forcedunwind)(ex, stop_func, stop_arg); 109} 110 111unsigned long 112_Unwind_GetCFA(struct _Unwind_Context *context) 113{ 114 return (*uwl_getcfa)(context); 115} 116#else 117#pragma weak _Unwind_GetCFA 118#pragma weak _Unwind_ForcedUnwind 119#endif /* PIC */ 120 121static void 122thread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e) 123{ 124 /* 125 * Specification said that _Unwind_Resume should not be used here, 126 * instead, user should rethrow the exception. For C++ user, they 127 * should put "throw" sentence in catch(...) block. 128 */ 129 PANIC("exception should be rethrown"); 130} 131 132static _Unwind_Reason_Code 133thread_unwind_stop(int version, _Unwind_Action actions, 134 int64_t exc_class, 135 struct _Unwind_Exception *exc_obj, 136 struct _Unwind_Context *context, void *stop_parameter) 137{ 138 struct pthread *curthread = _get_curthread(); 139 struct pthread_cleanup *cur; 140 uintptr_t cfa; 141 int done = 0; 142 143 /* XXX assume stack grows down to lower address */ 144 145 cfa = _Unwind_GetCFA(context); 146 if (actions & _UA_END_OF_STACK || 147 cfa >= (uintptr_t)curthread->unwind_stackend) { 148 done = 1; 149 } 150 151 while ((cur = curthread->cleanup) != NULL && 152 (done || (uintptr_t)cur <= cfa)) { 153 __pthread_cleanup_pop_imp(1); 154 } 155 156 if (done) { 157 /* Tell libc that it should call non-trivial TLS dtors. */ 158 __cxa_thread_call_dtors(); 159 160 exit_thread(); /* Never return! */ 161 } 162 163 return (_URC_NO_REASON); 164} 165 166static void 167thread_unwind(void) 168{ 169 struct pthread *curthread = _get_curthread(); 170 171 curthread->ex.exception_class = 0; 172 curthread->ex.exception_cleanup = thread_unwind_cleanup; 173 _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL); 174 PANIC("_Unwind_ForcedUnwind returned"); 175} 176 177#endif 178 179void 180_thread_exitf(const char *fname, int lineno, const char *fmt, ...) 181{ 182 va_list ap; 183 184 /* Write an error message to the standard error file descriptor: */ 185 _thread_printf(STDERR_FILENO, "Fatal error '"); 186 187 va_start(ap, fmt); 188 _thread_vprintf(STDERR_FILENO, fmt, ap); 189 va_end(ap); 190 191 _thread_printf(STDERR_FILENO, "' at line %d in file %s (errno = %d)\n", 192 lineno, fname, errno); 193 194 abort(); 195} 196 197void 198_thread_exit(const char *fname, int lineno, const char *msg) 199{ 200 201 _thread_exitf(fname, lineno, "%s", msg); 202} 203 204void 205_pthread_exit(void *status) 206{ 207 _pthread_exit_mask(status, NULL); 208} 209 210void 211_pthread_exit_mask(void *status, sigset_t *mask) 212{ 213 struct pthread *curthread = _get_curthread(); 214 215 /* Check if this thread is already in the process of exiting: */ 216 if (curthread->cancelling) 217 PANIC("Thread %p has called " 218 "pthread_exit() from a destructor. POSIX 1003.1 " 219 "1996 s16.2.5.2 does not allow this!", curthread); 220 221 /* Flag this thread as exiting. */ 222 curthread->cancelling = 1; 223 curthread->no_cancel = 1; 224 curthread->cancel_async = 0; 225 curthread->cancel_point = 0; 226 if (mask != NULL) 227 __sys_sigprocmask(SIG_SETMASK, mask, NULL); 228 if (curthread->unblock_sigcancel) { 229 sigset_t set; 230 231 curthread->unblock_sigcancel = 0; 232 SIGEMPTYSET(set); 233 SIGADDSET(set, SIGCANCEL); 234 __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); 235 } 236 237 /* Save the return value: */ 238 curthread->ret = status; 239#ifdef _PTHREAD_FORCED_UNWIND 240 241#ifdef PIC 242 thread_uw_init(); 243#endif /* PIC */ 244 245#ifdef PIC 246 if (uwl_forcedunwind != NULL) { 247#else 248 if (_Unwind_ForcedUnwind != NULL) { 249#endif 250 if (curthread->unwind_disabled) { 251 if (message_printed == 0) { 252 message_printed = 1; 253 _thread_printf(2, "Warning: old _pthread_cleanup_push was called, " 254 "stack unwinding is disabled.\n"); 255 } 256 goto cleanup; 257 } 258 thread_unwind(); 259 260 } else { 261cleanup: 262 while (curthread->cleanup != NULL) { 263 __pthread_cleanup_pop_imp(1); 264 } 265 __cxa_thread_call_dtors(); 266 267 exit_thread(); 268 } 269 270#else 271 while (curthread->cleanup != NULL) { 272 __pthread_cleanup_pop_imp(1); 273 } 274 __cxa_thread_call_dtors(); 275 276 exit_thread(); 277#endif /* _PTHREAD_FORCED_UNWIND */ 278} 279 280static void 281exit_thread(void) 282{ 283 struct pthread *curthread = _get_curthread(); 284 285 /* Check if there is thread specific data: */ 286 if (curthread->specific != NULL) { 287 /* Run the thread-specific data destructors: */ 288 _thread_cleanupspecific(); 289 } 290 291 if (!_thr_isthreaded()) 292 exit(0); 293 294 if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { 295 exit(0); 296 /* Never reach! */ 297 } 298 299 /* Tell malloc that the thread is exiting. */ 300 _malloc_thread_cleanup(); 301 302 THR_LOCK(curthread); 303 curthread->state = PS_DEAD; 304 if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 305 curthread->cycle++; 306 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 307 } 308 if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 309 _thr_report_death(curthread); 310 /* 311 * Thread was created with initial refcount 1, we drop the 312 * reference count to allow it to be garbage collected. 313 */ 314 curthread->refcount--; 315 _thr_try_gc(curthread, curthread); /* thread lock released */ 316 317#if defined(_PTHREADS_INVARIANTS) 318 if (THR_IN_CRITICAL(curthread)) 319 PANIC("thread %p exits with resources held!", curthread); 320#endif 321 /* 322 * Kernel will do wakeup at the address, so joiner thread 323 * will be resumed if it is sleeping at the address. 324 */ 325 thr_exit(&curthread->tid); 326 PANIC("thr_exit() returned"); 327 /* Never reach! */ 328} 329