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