thr_exit.c revision 297706
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: head/lib/libthr/thread/thr_exit.c 297706 2016-04-08 11:15:26Z kib $"); 32 33#include "namespace.h" 34#include <errno.h> 35#ifdef _PTHREAD_FORCED_UNWIND 36#include <dlfcn.h> 37#endif 38#include <stdio.h> 39#include <stdlib.h> 40#include <pthread.h> 41#include <sys/types.h> 42#include <sys/signalvar.h> 43#include "un-namespace.h" 44 45#include "libc_private.h" 46#include "thr_private.h" 47 48void _pthread_exit(void *status); 49 50static void exit_thread(void) __dead2; 51 52__weak_reference(_pthread_exit, pthread_exit); 53 54#ifdef _PTHREAD_FORCED_UNWIND 55static int message_printed; 56 57static void thread_unwind(void) __dead2; 58#ifdef PIC 59static void thread_uw_init(void); 60static _Unwind_Reason_Code thread_unwind_stop(int version, 61 _Unwind_Action actions, 62 int64_t exc_class, 63 struct _Unwind_Exception *exc_obj, 64 struct _Unwind_Context *context, void *stop_parameter); 65/* unwind library pointers */ 66static _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *, 67 _Unwind_Stop_Fn, void *); 68static unsigned long (*uwl_getcfa)(struct _Unwind_Context *); 69 70static void 71thread_uw_init(void) 72{ 73 static int inited = 0; 74 Dl_info dlinfo; 75 void *handle; 76 void *forcedunwind, *getcfa; 77 78 if (inited) 79 return; 80 handle = RTLD_DEFAULT; 81 if ((forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) != NULL) { 82 if (dladdr(forcedunwind, &dlinfo)) { 83 /* 84 * Make sure the address is always valid by holding the library, 85 * also assume functions are in same library. 86 */ 87 if ((handle = dlopen(dlinfo.dli_fname, RTLD_LAZY)) != NULL) { 88 forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind"); 89 getcfa = dlsym(handle, "_Unwind_GetCFA"); 90 if (forcedunwind != NULL && getcfa != NULL) { 91 uwl_getcfa = getcfa; 92 atomic_store_rel_ptr((volatile void *)&uwl_forcedunwind, 93 (uintptr_t)forcedunwind); 94 } else { 95 dlclose(handle); 96 } 97 } 98 } 99 } 100 inited = 1; 101} 102 103_Unwind_Reason_Code 104_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func, 105 void *stop_arg) 106{ 107 return (*uwl_forcedunwind)(ex, stop_func, stop_arg); 108} 109 110unsigned long 111_Unwind_GetCFA(struct _Unwind_Context *context) 112{ 113 return (*uwl_getcfa)(context); 114} 115#else 116#pragma weak _Unwind_GetCFA 117#pragma weak _Unwind_ForcedUnwind 118#endif /* PIC */ 119 120static void 121thread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e) 122{ 123 /* 124 * Specification said that _Unwind_Resume should not be used here, 125 * instead, user should rethrow the exception. For C++ user, they 126 * should put "throw" sentence in catch(...) block. 127 */ 128 PANIC("exception should be rethrown"); 129} 130 131static _Unwind_Reason_Code 132thread_unwind_stop(int version, _Unwind_Action actions, 133 int64_t exc_class, 134 struct _Unwind_Exception *exc_obj, 135 struct _Unwind_Context *context, void *stop_parameter) 136{ 137 struct pthread *curthread = _get_curthread(); 138 struct pthread_cleanup *cur; 139 uintptr_t cfa; 140 int done = 0; 141 142 /* XXX assume stack grows down to lower address */ 143 144 cfa = _Unwind_GetCFA(context); 145 if (actions & _UA_END_OF_STACK || 146 cfa >= (uintptr_t)curthread->unwind_stackend) { 147 done = 1; 148 } 149 150 while ((cur = curthread->cleanup) != NULL && 151 (done || (uintptr_t)cur <= cfa)) { 152 __pthread_cleanup_pop_imp(1); 153 } 154 155 if (done) 156 exit_thread(); /* Never return! */ 157 158 return (_URC_NO_REASON); 159} 160 161static void 162thread_unwind(void) 163{ 164 struct pthread *curthread = _get_curthread(); 165 166 curthread->ex.exception_class = 0; 167 curthread->ex.exception_cleanup = thread_unwind_cleanup; 168 _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL); 169 PANIC("_Unwind_ForcedUnwind returned"); 170} 171 172#endif 173 174void 175_thread_exit(const char *fname, int lineno, const char *msg) 176{ 177 178 /* Write an error message to the standard error file descriptor: */ 179 _thread_printf(2, 180 "Fatal error '%s' at line %d in file %s (errno = %d)\n", 181 msg, lineno, fname, errno); 182 183 abort(); 184} 185 186void 187_pthread_exit(void *status) 188{ 189 _pthread_exit_mask(status, NULL); 190} 191 192void 193_pthread_exit_mask(void *status, sigset_t *mask) 194{ 195 struct pthread *curthread = _get_curthread(); 196 197 /* Check if this thread is already in the process of exiting: */ 198 if (curthread->cancelling) { 199 char msg[128]; 200 snprintf(msg, sizeof(msg), "Thread %p has called " 201 "pthread_exit() from a destructor. POSIX 1003.1 " 202 "1996 s16.2.5.2 does not allow this!", curthread); 203 PANIC(msg); 204 } 205 206 /* Flag this thread as exiting. */ 207 curthread->cancelling = 1; 208 curthread->no_cancel = 1; 209 curthread->cancel_async = 0; 210 curthread->cancel_point = 0; 211 if (mask != NULL) 212 __sys_sigprocmask(SIG_SETMASK, mask, NULL); 213 if (curthread->unblock_sigcancel) { 214 sigset_t set; 215 216 curthread->unblock_sigcancel = 0; 217 SIGEMPTYSET(set); 218 SIGADDSET(set, SIGCANCEL); 219 __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); 220 } 221 222 /* Save the return value: */ 223 curthread->ret = status; 224#ifdef _PTHREAD_FORCED_UNWIND 225 226#ifdef PIC 227 thread_uw_init(); 228#endif /* PIC */ 229 230#ifdef PIC 231 if (uwl_forcedunwind != NULL) { 232#else 233 if (_Unwind_ForcedUnwind != NULL) { 234#endif 235 if (curthread->unwind_disabled) { 236 if (message_printed == 0) { 237 message_printed = 1; 238 _thread_printf(2, "Warning: old _pthread_cleanup_push was called, " 239 "stack unwinding is disabled.\n"); 240 } 241 goto cleanup; 242 } 243 thread_unwind(); 244 245 } else { 246cleanup: 247 while (curthread->cleanup != NULL) { 248 __pthread_cleanup_pop_imp(1); 249 } 250 exit_thread(); 251 } 252 253#else 254 while (curthread->cleanup != NULL) { 255 __pthread_cleanup_pop_imp(1); 256 } 257 258 exit_thread(); 259#endif /* _PTHREAD_FORCED_UNWIND */ 260} 261 262static void 263exit_thread(void) 264{ 265 struct pthread *curthread = _get_curthread(); 266 267 /* Check if there is thread specific data: */ 268 if (curthread->specific != NULL) { 269 /* Run the thread-specific data destructors: */ 270 _thread_cleanupspecific(); 271 } 272 273 if (!_thr_isthreaded()) 274 exit(0); 275 276 if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { 277 exit(0); 278 /* Never reach! */ 279 } 280 281 /* Tell malloc that the thread is exiting. */ 282 _malloc_thread_cleanup(); 283 284 THR_LOCK(curthread); 285 curthread->state = PS_DEAD; 286 if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 287 curthread->cycle++; 288 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 289 } 290 if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 291 _thr_report_death(curthread); 292 /* 293 * Thread was created with initial refcount 1, we drop the 294 * reference count to allow it to be garbage collected. 295 */ 296 curthread->refcount--; 297 _thr_try_gc(curthread, curthread); /* thread lock released */ 298 299#if defined(_PTHREADS_INVARIANTS) 300 if (THR_IN_CRITICAL(curthread)) 301 PANIC("thread exits with resources held!"); 302#endif 303 /* 304 * Kernel will do wakeup at the address, so joiner thread 305 * will be resumed if it is sleeping at the address. 306 */ 307 thr_exit(&curthread->tid); 308 PANIC("thr_exit() returned"); 309 /* Never reach! */ 310} 311