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