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