thr_exit.c revision 301136
1157088Simp/* 2157088Simp * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3157088Simp * All rights reserved. 4157088Simp * 5157088Simp * Redistribution and use in source and binary forms, with or without 6157088Simp * modification, are permitted provided that the following conditions 7157088Simp * are met: 8157088Simp * 1. Redistributions of source code must retain the above copyright 9157088Simp * notice, this list of conditions and the following disclaimer. 10157088Simp * 2. Redistributions in binary form must reproduce the above copyright 11157088Simp * notice, this list of conditions and the following disclaimer in the 12157088Simp * documentation and/or other materials provided with the distribution. 13185265Simp * 3. Neither the name of the author nor the names of any co-contributors 14185265Simp * may be used to endorse or promote products derived from this software 15185265Simp * without specific prior written permission. 16185265Simp * 17185265Simp * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18185265Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19185265Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20185265Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21185265Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22185265Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23185265Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24157088Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25157088Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26157088Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27157088Simp * SUCH DAMAGE. 28157088Simp */ 29157088Simp 30157088Simp#include <sys/cdefs.h> 31157088Simp__FBSDID("$FreeBSD: head/lib/libthr/thread/thr_exit.c 301136 2016-06-01 16:12:26Z cem $"); 32157088Simp 33157088Simp#include "namespace.h" 34157088Simp#include <errno.h> 35157088Simp#ifdef _PTHREAD_FORCED_UNWIND 36157088Simp#include <dlfcn.h> 37157088Simp#endif 38157088Simp#include <stdarg.h> 39238788Sandrew#include <stdio.h> 40157088Simp#include <stdlib.h> 41157088Simp#include <pthread.h> 42157088Simp#include <sys/types.h> 43157088Simp#include <sys/signalvar.h> 44157088Simp#include "un-namespace.h" 45157088Simp 46238788Sandrew#include "libc_private.h" 47157088Simp#include "thr_private.h" 48157088Simp 49157088Simpvoid _pthread_exit(void *status); 50157088Simp 51157088Simpstatic void exit_thread(void) __dead2; 52157088Simp 53157088Simp__weak_reference(_pthread_exit, pthread_exit); 54157088Simp 55157088Simp#ifdef _PTHREAD_FORCED_UNWIND 56157088Simpstatic int message_printed; 57157088Simp 58157088Simpstatic void thread_unwind(void) __dead2; 59157088Simp#ifdef PIC 60157088Simpstatic void thread_uw_init(void); 61157088Simpstatic _Unwind_Reason_Code thread_unwind_stop(int version, 62157088Simp _Unwind_Action actions, 63157088Simp int64_t exc_class, 64157088Simp struct _Unwind_Exception *exc_obj, 65157088Simp struct _Unwind_Context *context, void *stop_parameter); 66157088Simp/* unwind library pointers */ 67157088Simpstatic _Unwind_Reason_Code (*uwl_forcedunwind)(struct _Unwind_Exception *, 68157088Simp _Unwind_Stop_Fn, void *); 69213496Scognetstatic unsigned long (*uwl_getcfa)(struct _Unwind_Context *); 70213496Scognet 71213496Scognetstatic void 72213496Scognetthread_uw_init(void) 73213496Scognet{ 74157088Simp static int inited = 0; 75157088Simp Dl_info dlinfo; 76157088Simp void *handle; 77157088Simp void *forcedunwind, *getcfa; 78157088Simp 79157088Simp if (inited) 80238788Sandrew return; 81238788Sandrew handle = RTLD_DEFAULT; 82238788Sandrew if ((forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind")) != NULL) { 83238788Sandrew if (dladdr(forcedunwind, &dlinfo)) { 84157088Simp /* 85157088Simp * Make sure the address is always valid by holding the library, 86157088Simp * also assume functions are in same library. 87157088Simp */ 88157088Simp if ((handle = dlopen(dlinfo.dli_fname, RTLD_LAZY)) != NULL) { 89157088Simp forcedunwind = dlsym(handle, "_Unwind_ForcedUnwind"); 90157088Simp getcfa = dlsym(handle, "_Unwind_GetCFA"); 91157088Simp if (forcedunwind != NULL && getcfa != NULL) { 92157088Simp uwl_getcfa = getcfa; 93213496Scognet atomic_store_rel_ptr((volatile void *)&uwl_forcedunwind, 94213496Scognet (uintptr_t)forcedunwind); 95213496Scognet } else { 96213498Scognet dlclose(handle); 97213496Scognet } 98213496Scognet } 99213496Scognet } 100238788Sandrew } 101238788Sandrew inited = 1; 102238788Sandrew} 103238788Sandrew 104157088Simp_Unwind_Reason_Code 105157088Simp_Unwind_ForcedUnwind(struct _Unwind_Exception *ex, _Unwind_Stop_Fn stop_func, 106157088Simp void *stop_arg) 107157088Simp{ 108157088Simp return (*uwl_forcedunwind)(ex, stop_func, stop_arg); 109157088Simp} 110157088Simp 111157088Simpunsigned long 112238788Sandrew_Unwind_GetCFA(struct _Unwind_Context *context) 113157088Simp{ 114157088Simp return (*uwl_getcfa)(context); 115157088Simp} 116157088Simp#else 117157088Simp#pragma weak _Unwind_GetCFA 118157088Simp#pragma weak _Unwind_ForcedUnwind 119157088Simp#endif /* PIC */ 120157088Simp 121157088Simpstatic void 122157088Simpthread_unwind_cleanup(_Unwind_Reason_Code code, struct _Unwind_Exception *e) 123157088Simp{ 124157088Simp /* 125157088Simp * Specification said that _Unwind_Resume should not be used here, 126157088Simp * instead, user should rethrow the exception. For C++ user, they 127157088Simp * should put "throw" sentence in catch(...) block. 128157088Simp */ 129157088Simp PANIC("exception should be rethrown"); 130157088Simp} 131157088Simp 132157088Simpstatic _Unwind_Reason_Code 133157088Simpthread_unwind_stop(int version, _Unwind_Action actions, 134157088Simp int64_t exc_class, 135157088Simp struct _Unwind_Exception *exc_obj, 136157088Simp struct _Unwind_Context *context, void *stop_parameter) 137157088Simp{ 138157088Simp struct pthread *curthread = _get_curthread(); 139157088Simp 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 exit_thread(); /* Never return! */ 158 159 return (_URC_NO_REASON); 160} 161 162static void 163thread_unwind(void) 164{ 165 struct pthread *curthread = _get_curthread(); 166 167 curthread->ex.exception_class = 0; 168 curthread->ex.exception_cleanup = thread_unwind_cleanup; 169 _Unwind_ForcedUnwind(&curthread->ex, thread_unwind_stop, NULL); 170 PANIC("_Unwind_ForcedUnwind returned"); 171} 172 173#endif 174 175void 176_thread_exitf(const char *fname, int lineno, const char *fmt, ...) 177{ 178 va_list ap; 179 180 /* Write an error message to the standard error file descriptor: */ 181 _thread_printf(STDERR_FILENO, "Fatal error '"); 182 183 va_start(ap, fmt); 184 _thread_vprintf(STDERR_FILENO, fmt, ap); 185 va_end(ap); 186 187 _thread_printf(STDERR_FILENO, "' at line %d in file %s (errno = %d)\n", 188 lineno, fname, errno); 189 190 abort(); 191} 192 193void 194_thread_exit(const char *fname, int lineno, const char *msg) 195{ 196 197 _thread_exitf(fname, lineno, "%s", msg); 198} 199 200void 201_pthread_exit(void *status) 202{ 203 _pthread_exit_mask(status, NULL); 204} 205 206void 207_pthread_exit_mask(void *status, sigset_t *mask) 208{ 209 struct pthread *curthread = _get_curthread(); 210 211 /* Check if this thread is already in the process of exiting: */ 212 if (curthread->cancelling) 213 PANIC("Thread %p has called " 214 "pthread_exit() from a destructor. POSIX 1003.1 " 215 "1996 s16.2.5.2 does not allow this!", curthread); 216 217 /* Flag this thread as exiting. */ 218 curthread->cancelling = 1; 219 curthread->no_cancel = 1; 220 curthread->cancel_async = 0; 221 curthread->cancel_point = 0; 222 if (mask != NULL) 223 __sys_sigprocmask(SIG_SETMASK, mask, NULL); 224 if (curthread->unblock_sigcancel) { 225 sigset_t set; 226 227 curthread->unblock_sigcancel = 0; 228 SIGEMPTYSET(set); 229 SIGADDSET(set, SIGCANCEL); 230 __sys_sigprocmask(SIG_UNBLOCK, mask, NULL); 231 } 232 233 /* Save the return value: */ 234 curthread->ret = status; 235#ifdef _PTHREAD_FORCED_UNWIND 236 237#ifdef PIC 238 thread_uw_init(); 239#endif /* PIC */ 240 241#ifdef PIC 242 if (uwl_forcedunwind != NULL) { 243#else 244 if (_Unwind_ForcedUnwind != NULL) { 245#endif 246 if (curthread->unwind_disabled) { 247 if (message_printed == 0) { 248 message_printed = 1; 249 _thread_printf(2, "Warning: old _pthread_cleanup_push was called, " 250 "stack unwinding is disabled.\n"); 251 } 252 goto cleanup; 253 } 254 thread_unwind(); 255 256 } else { 257cleanup: 258 while (curthread->cleanup != NULL) { 259 __pthread_cleanup_pop_imp(1); 260 } 261 exit_thread(); 262 } 263 264#else 265 while (curthread->cleanup != NULL) { 266 __pthread_cleanup_pop_imp(1); 267 } 268 269 exit_thread(); 270#endif /* _PTHREAD_FORCED_UNWIND */ 271} 272 273static void 274exit_thread(void) 275{ 276 struct pthread *curthread = _get_curthread(); 277 278 /* Check if there is thread specific data: */ 279 if (curthread->specific != NULL) { 280 /* Run the thread-specific data destructors: */ 281 _thread_cleanupspecific(); 282 } 283 284 if (!_thr_isthreaded()) 285 exit(0); 286 287 if (atomic_fetchadd_int(&_thread_active_threads, -1) == 1) { 288 exit(0); 289 /* Never reach! */ 290 } 291 292 /* Tell malloc that the thread is exiting. */ 293 _malloc_thread_cleanup(); 294 295 THR_LOCK(curthread); 296 curthread->state = PS_DEAD; 297 if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 298 curthread->cycle++; 299 _thr_umtx_wake(&curthread->cycle, INT_MAX, 0); 300 } 301 if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 302 _thr_report_death(curthread); 303 /* 304 * Thread was created with initial refcount 1, we drop the 305 * reference count to allow it to be garbage collected. 306 */ 307 curthread->refcount--; 308 _thr_try_gc(curthread, curthread); /* thread lock released */ 309 310#if defined(_PTHREADS_INVARIANTS) 311 if (THR_IN_CRITICAL(curthread)) 312 PANIC("thread %p exits with resources held!", curthread); 313#endif 314 /* 315 * Kernel will do wakeup at the address, so joiner thread 316 * will be resumed if it is sleeping at the address. 317 */ 318 thr_exit(&curthread->tid); 319 PANIC("thr_exit() returned"); 320 /* Never reach! */ 321} 322