171b3fa15SDavid Xu /* 271b3fa15SDavid Xu * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 371b3fa15SDavid Xu * All rights reserved. 471b3fa15SDavid Xu * 571b3fa15SDavid Xu * Redistribution and use in source and binary forms, with or without 671b3fa15SDavid Xu * modification, are permitted provided that the following conditions 771b3fa15SDavid Xu * are met: 871b3fa15SDavid Xu * 1. Redistributions of source code must retain the above copyright 971b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer. 1071b3fa15SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 1171b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer in the 1271b3fa15SDavid Xu * documentation and/or other materials provided with the distribution. 13d3b15642Szrj * 3. Neither the name of the author nor the names of any co-contributors 1471b3fa15SDavid Xu * may be used to endorse or promote products derived from this software 1571b3fa15SDavid Xu * without specific prior written permission. 1671b3fa15SDavid Xu * 1771b3fa15SDavid Xu * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 1871b3fa15SDavid Xu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1971b3fa15SDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2071b3fa15SDavid Xu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2171b3fa15SDavid Xu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2271b3fa15SDavid Xu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2371b3fa15SDavid Xu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2471b3fa15SDavid Xu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2571b3fa15SDavid Xu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2671b3fa15SDavid Xu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2771b3fa15SDavid Xu * SUCH DAMAGE. 2871b3fa15SDavid Xu * 2971b3fa15SDavid Xu * $FreeBSD: src/lib/libpthread/thread/thr_exit.c,v 1.39 2004/10/23 23:37:54 davidxu Exp $ 3071b3fa15SDavid Xu */ 319e2ee207SJoerg Sonnenberger 32557d26c7SDavid Xu #include "namespace.h" 339e2ee207SJoerg Sonnenberger #include <machine/tls.h> 3471b3fa15SDavid Xu #include <errno.h> 3571b3fa15SDavid Xu #include <unistd.h> 3671b3fa15SDavid Xu #include <fcntl.h> 374a9b8501Szrj #include <stdarg.h> 3871b3fa15SDavid Xu #include <stdio.h> 3971b3fa15SDavid Xu #include <stdlib.h> 4071b3fa15SDavid Xu #include <string.h> 4171b3fa15SDavid Xu #include <pthread.h> 42557d26c7SDavid Xu #include "un-namespace.h" 4371b3fa15SDavid Xu 44*284b4eb2Szrj #include "libc_private.h" 45557d26c7SDavid Xu #include "thr_private.h" 4671b3fa15SDavid Xu 4790306d38Szrj static void exit_thread(void) __dead2; 4890306d38Szrj 4971b3fa15SDavid Xu void 504a9b8501Szrj _thread_exitf(const char *fname, int lineno, const char *fmt, ...) 5171b3fa15SDavid Xu { 524a9b8501Szrj va_list ap; 5371b3fa15SDavid Xu 5471b3fa15SDavid Xu /* Write an error message to the standard error file descriptor: */ 554a9b8501Szrj _thread_printf(STDERR_FILENO, "Fatal error '"); 564a9b8501Szrj 574a9b8501Szrj va_start(ap, fmt); 584a9b8501Szrj _thread_vprintf(STDERR_FILENO, fmt, ap); 594a9b8501Szrj va_end(ap); 604a9b8501Szrj 614a9b8501Szrj _thread_printf(STDERR_FILENO, "' at line %d in file %s (errno = %d)\n", 624a9b8501Szrj lineno, fname, errno); 6371b3fa15SDavid Xu 6471b3fa15SDavid Xu abort(); 6571b3fa15SDavid Xu } 6671b3fa15SDavid Xu 674a9b8501Szrj void 684a9b8501Szrj _thread_exit(const char *fname, int lineno, const char *msg) 694a9b8501Szrj { 704a9b8501Szrj _thread_exitf(fname, lineno, "%s", msg); 714a9b8501Szrj } 724a9b8501Szrj 7371b3fa15SDavid Xu /* 7471b3fa15SDavid Xu * Only called when a thread is cancelled. It may be more useful 7571b3fa15SDavid Xu * to call it from pthread_exit() if other ways of asynchronous or 7671b3fa15SDavid Xu * abnormal thread termination can be found. 7771b3fa15SDavid Xu */ 7871b3fa15SDavid Xu void 7971b3fa15SDavid Xu _thr_exit_cleanup(void) 8071b3fa15SDavid Xu { 819e2ee207SJoerg Sonnenberger struct pthread *curthread = tls_get_curthread(); 8271b3fa15SDavid Xu 8371b3fa15SDavid Xu /* 8471b3fa15SDavid Xu * POSIX states that cancellation/termination of a thread should 8571b3fa15SDavid Xu * not release any visible resources (such as mutexes) and that 8671b3fa15SDavid Xu * it is the applications responsibility. Resources that are 8771b3fa15SDavid Xu * internal to the threads library, including file and fd locks, 8871b3fa15SDavid Xu * are not visible to the application and need to be released. 8971b3fa15SDavid Xu */ 9071b3fa15SDavid Xu /* Unlock all private mutexes: */ 9171b3fa15SDavid Xu _mutex_unlock_private(curthread); 9271b3fa15SDavid Xu 9371b3fa15SDavid Xu /* 9471b3fa15SDavid Xu * This still isn't quite correct because we don't account 9571b3fa15SDavid Xu * for held spinlocks (see libc/stdlib/malloc.c). 9671b3fa15SDavid Xu */ 9771b3fa15SDavid Xu } 9871b3fa15SDavid Xu 9971b3fa15SDavid Xu void 10071b3fa15SDavid Xu _pthread_exit(void *status) 10171b3fa15SDavid Xu { 1029e2ee207SJoerg Sonnenberger struct pthread *curthread = tls_get_curthread(); 10371b3fa15SDavid Xu 10471b3fa15SDavid Xu /* Check if this thread is already in the process of exiting: */ 10571b3fa15SDavid Xu if ((curthread->cancelflags & THR_CANCEL_EXITING) != 0) { 1064a9b8501Szrj PANIC("Thread %p has called " 10771b3fa15SDavid Xu "pthread_exit() from a destructor. POSIX 1003.1 " 10871b3fa15SDavid Xu "1996 s16.2.5.2 does not allow this!", curthread); 10971b3fa15SDavid Xu } 11071b3fa15SDavid Xu 11171b3fa15SDavid Xu /* Flag this thread as exiting. */ 11271b3fa15SDavid Xu atomic_set_int(&curthread->cancelflags, THR_CANCEL_EXITING); 11371b3fa15SDavid Xu 11471b3fa15SDavid Xu _thr_exit_cleanup(); 11571b3fa15SDavid Xu 11671b3fa15SDavid Xu /* Save the return value: */ 11771b3fa15SDavid Xu curthread->ret = status; 11871b3fa15SDavid Xu while (curthread->cleanup != NULL) { 119557d26c7SDavid Xu _pthread_cleanup_pop(1); 12071b3fa15SDavid Xu } 121*284b4eb2Szrj /* Call TLS destructors, if any. */ 122*284b4eb2Szrj _thread_finalize(); 123e8382b15SDavid Xu 12490306d38Szrj exit_thread(); 12590306d38Szrj } 12690306d38Szrj 12790306d38Szrj __strong_reference(_pthread_exit, pthread_exit); 12890306d38Szrj 12990306d38Szrj static void 13090306d38Szrj exit_thread(void) 13190306d38Szrj { 13290306d38Szrj struct pthread *curthread = tls_get_curthread(); 13390306d38Szrj 13471b3fa15SDavid Xu /* Check if there is thread specific data: */ 13571b3fa15SDavid Xu if (curthread->specific != NULL) { 13671b3fa15SDavid Xu /* Run the thread-specific data destructors: */ 13771b3fa15SDavid Xu _thread_cleanupspecific(); 13871b3fa15SDavid Xu } 13971b3fa15SDavid Xu 14071b3fa15SDavid Xu if (!_thr_isthreaded()) 14171b3fa15SDavid Xu exit(0); 14271b3fa15SDavid Xu 14371b3fa15SDavid Xu THREAD_LIST_LOCK(curthread); 14471b3fa15SDavid Xu _thread_active_threads--; 14571b3fa15SDavid Xu if (_thread_active_threads == 0) { 14671b3fa15SDavid Xu THREAD_LIST_UNLOCK(curthread); 14771b3fa15SDavid Xu exit(0); 14871b3fa15SDavid Xu /* Never reach! */ 14971b3fa15SDavid Xu } 150c9ad2203SDavid Xu THR_LOCK(curthread); 151c9ad2203SDavid Xu curthread->state = PS_DEAD; 152c9ad2203SDavid Xu THR_UNLOCK(curthread); 153c9ad2203SDavid Xu curthread->refcount--; 15471b3fa15SDavid Xu if (curthread->tlflags & TLFLAGS_DETACHED) 15571b3fa15SDavid Xu THR_GCLIST_ADD(curthread); 15671b3fa15SDavid Xu THREAD_LIST_UNLOCK(curthread); 15771b3fa15SDavid Xu if (curthread->joiner) 15898247283SMatthew Dillon _thr_umtx_wake(&curthread->state, 0); 1593cd47da3SDavid Xu if (SHOULD_REPORT_EVENT(curthread, TD_DEATH)) 1603cd47da3SDavid Xu _thr_report_death(curthread); 161fbf2ef09SSimon Schubert /* Exit and set terminated to once we're really dead. */ 162fbf2ef09SSimon Schubert extexit(EXTEXIT_SETINT|EXTEXIT_LWP, 1, &curthread->terminated); 16371b3fa15SDavid Xu PANIC("thr_exit() returned"); 16471b3fa15SDavid Xu /* Never reach! */ 16571b3fa15SDavid Xu } 166