thr_exit.c revision 132120
1319780Sdim/* 2319780Sdim * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3319780Sdim * All rights reserved. 4319780Sdim * 5319780Sdim * Redistribution and use in source and binary forms, with or without 6319780Sdim * modification, are permitted provided that the following conditions 7319780Sdim * are met: 8319780Sdim * 1. Redistributions of source code must retain the above copyright 9319780Sdim * notice, this list of conditions and the following disclaimer. 10319780Sdim * 2. Redistributions in binary form must reproduce the above copyright 11319780Sdim * notice, this list of conditions and the following disclaimer in the 12319780Sdim * documentation and/or other materials provided with the distribution. 13319780Sdim * 3. All advertising materials mentioning features or use of this software 14319780Sdim * must display the following acknowledgement: 15319780Sdim * This product includes software developed by John Birrell. 16319780Sdim * 4. Neither the name of the author nor the names of any co-contributors 17319780Sdim * may be used to endorse or promote products derived from this software 18319780Sdim * without specific prior written permission. 19319780Sdim * 20319780Sdim * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21319780Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22319780Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23319780Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24319780Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25319780Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26319780Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27319780Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28319780Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29319780Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30319780Sdim * SUCH DAMAGE. 31319780Sdim * 32319780Sdim * $FreeBSD: head/lib/libkse/thread/thr_exit.c 132120 2004-07-13 22:49:58Z davidxu $ 33319780Sdim */ 34319780Sdim#include <errno.h> 35319780Sdim#include <unistd.h> 36319780Sdim#include <fcntl.h> 37319780Sdim#include <stdio.h> 38319780Sdim#include <stdlib.h> 39319780Sdim#include <string.h> 40319780Sdim#include <pthread.h> 41319780Sdim#include "thr_private.h" 42319780Sdim 43319780Sdimvoid _pthread_exit(void *status); 44319780Sdim 45319780Sdim__weak_reference(_pthread_exit, pthread_exit); 46319780Sdim 47319780Sdimvoid 48319780Sdim_thr_exit(char *fname, int lineno, char *msg) 49320397Sdim{ 50320397Sdim 51320397Sdim /* Write an error message to the standard error file descriptor: */ 52320397Sdim _thread_printf(2, 53320397Sdim "Fatal error '%s' at line %d in file %s (errno = %d)\n", 54320397Sdim msg, lineno, fname, errno); 55319780Sdim 56319780Sdim abort(); 57319780Sdim} 58319780Sdim 59319780Sdim/* 60319780Sdim * Only called when a thread is cancelled. It may be more useful 61319780Sdim * to call it from pthread_exit() if other ways of asynchronous or 62319780Sdim * abnormal thread termination can be found. 63319780Sdim */ 64319780Sdimvoid 65319780Sdim_thr_exit_cleanup(void) 66319780Sdim{ 67319780Sdim struct pthread *curthread = _get_curthread(); 68319780Sdim 69319780Sdim /* 70319780Sdim * POSIX states that cancellation/termination of a thread should 71319780Sdim * not release any visible resources (such as mutexes) and that 72319780Sdim * it is the applications responsibility. Resources that are 73319780Sdim * internal to the threads library, including file and fd locks, 74319780Sdim * are not visible to the application and need to be released. 75319780Sdim */ 76319780Sdim /* Unlock all private mutexes: */ 77319780Sdim _mutex_unlock_private(curthread); 78319780Sdim 79319780Sdim /* 80319780Sdim * This still isn't quite correct because we don't account 81319780Sdim * for held spinlocks (see libc/stdlib/malloc.c). 82319780Sdim */ 83319780Sdim} 84319780Sdim 85319780Sdimvoid 86319780Sdim_pthread_exit(void *status) 87319780Sdim{ 88319780Sdim struct pthread *curthread = _get_curthread(); 89319780Sdim kse_critical_t crit; 90319780Sdim struct kse *curkse; 91319780Sdim 92319780Sdim /* Check if this thread is already in the process of exiting: */ 93319780Sdim if ((curthread->flags & THR_FLAGS_EXITING) != 0) { 94327952Sdim char msg[128]; 95319780Sdim snprintf(msg, sizeof(msg), "Thread %p has called " 96319780Sdim "pthread_exit() from a destructor. POSIX 1003.1 " 97319780Sdim "1996 s16.2.5.2 does not allow this!", curthread); 98327952Sdim PANIC(msg); 99319780Sdim } 100319780Sdim 101319780Sdim /* 102319780Sdim * Flag this thread as exiting. Threads should now be prevented 103319780Sdim * from joining to this thread. 104319780Sdim */ 105319780Sdim THR_SCHED_LOCK(curthread, curthread); 106319780Sdim curthread->flags |= THR_FLAGS_EXITING; 107319780Sdim THR_SCHED_UNLOCK(curthread, curthread); 108319780Sdim 109319780Sdim /* Save the return value: */ 110319780Sdim curthread->ret = status; 111319780Sdim while (curthread->cleanup != NULL) { 112319780Sdim pthread_cleanup_pop(1); 113319780Sdim } 114319780Sdim if (curthread->attr.cleanup_attr != NULL) { 115319780Sdim curthread->attr.cleanup_attr(curthread->attr.arg_attr); 116319780Sdim } 117319780Sdim /* Check if there is thread specific data: */ 118319780Sdim if (curthread->specific != NULL) { 119319780Sdim /* Run the thread-specific data destructors: */ 120319780Sdim _thread_cleanupspecific(); 121327952Sdim } 122319780Sdim if (!_kse_isthreaded()) 123319780Sdim exit(0); 124319780Sdim crit = _kse_critical_enter(); 125319780Sdim curkse = _get_curkse(); 126319780Sdim KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); 127319780Sdim /* Use thread_list_lock */ 128319780Sdim _thread_active_threads--; 129319780Sdim#ifdef SYSTEM_SCOPE_ONLY 130319780Sdim if (_thread_active_threads == 0) { 131319780Sdim#else 132319780Sdim if (_thread_active_threads == 1) { 133319780Sdim#endif 134319780Sdim KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 135319780Sdim _kse_critical_leave(crit); 136319780Sdim exit(0); 137319780Sdim /* Never reach! */ 138319780Sdim } 139319780Sdim KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 140319780Sdim 141319780Sdim /* This thread will never be re-scheduled. */ 142319780Sdim KSE_LOCK(curkse); 143319780Sdim THR_SET_STATE(curthread, PS_DEAD); 144319780Sdim _thr_sched_switch_unlocked(curthread); 145319780Sdim /* Never reach! */ 146319780Sdim 147319780Sdim /* This point should not be reached. */ 148319780Sdim PANIC("Dead thread has resumed"); 149319780Sdim} 150319780Sdim