thr_exit.c revision 49439
1109998Smarkm/* 2109998Smarkm * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 3109998Smarkm * All rights reserved. 4109998Smarkm * 5109998Smarkm * Redistribution and use in source and binary forms, with or without 6109998Smarkm * modification, are permitted provided that the following conditions 7109998Smarkm * are met: 8109998Smarkm * 1. Redistributions of source code must retain the above copyright 9109998Smarkm * notice, this list of conditions and the following disclaimer. 10296341Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 11109998Smarkm * notice, this list of conditions and the following disclaimer in the 12109998Smarkm * documentation and/or other materials provided with the distribution. 13109998Smarkm * 3. All advertising materials mentioning features or use of this software 14109998Smarkm * must display the following acknowledgement: 15109998Smarkm * This product includes software developed by John Birrell. 16109998Smarkm * 4. Neither the name of the author nor the names of any co-contributors 17109998Smarkm * may be used to endorse or promote products derived from this software 18109998Smarkm * without specific prior written permission. 19109998Smarkm * 20109998Smarkm * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23109998Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24109998Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25109998Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28109998Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29109998Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30109998Smarkm * SUCH DAMAGE. 31109998Smarkm * 32109998Smarkm * $Id: uthread_exit.c,v 1.9 1999/06/20 08:28:17 jb Exp $ 33109998Smarkm */ 34109998Smarkm#include <errno.h> 35109998Smarkm#include <unistd.h> 36109998Smarkm#include <fcntl.h> 37109998Smarkm#include <string.h> 38109998Smarkm#ifdef _THREAD_SAFE 39109998Smarkm#include <pthread.h> 40109998Smarkm#include "pthread_private.h" 41109998Smarkm 42109998Smarkmvoid _exit(int status) 43109998Smarkm{ 44109998Smarkm int flags; 45109998Smarkm int i; 46109998Smarkm struct itimerval itimer; 47109998Smarkm 48109998Smarkm /* Disable the interval timer: */ 49109998Smarkm itimer.it_interval.tv_sec = 0; 50109998Smarkm itimer.it_interval.tv_usec = 0; 51109998Smarkm itimer.it_value.tv_sec = 0; 52109998Smarkm itimer.it_value.tv_usec = 0; 53109998Smarkm setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL); 54109998Smarkm 55296341Sdelphij /* Close the pthread kernel pipe: */ 56296341Sdelphij _thread_sys_close(_thread_kern_pipe[0]); 57296341Sdelphij _thread_sys_close(_thread_kern_pipe[1]); 58296341Sdelphij 59296341Sdelphij /* 60109998Smarkm * Enter a loop to set all file descriptors to blocking 61109998Smarkm * if they were not created as non-blocking: 62109998Smarkm */ 63109998Smarkm for (i = 0; i < _thread_dtablesize; i++) { 64296341Sdelphij /* Check if this file descriptor is in use: */ 65109998Smarkm if (_thread_fd_table[i] != NULL && 66296341Sdelphij !(_thread_fd_table[i]->flags & O_NONBLOCK)) { 67296341Sdelphij /* Get the current flags: */ 68296341Sdelphij flags = _thread_sys_fcntl(i, F_GETFL, NULL); 69296341Sdelphij /* Clear the nonblocking file descriptor flag: */ 70296341Sdelphij _thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK); 71296341Sdelphij } 72296341Sdelphij } 73109998Smarkm 74109998Smarkm /* Call the _exit syscall: */ 75296341Sdelphij _thread_sys__exit(status); 76296341Sdelphij} 77109998Smarkm 78296341Sdelphijvoid 79296341Sdelphij_thread_exit(char *fname, int lineno, char *string) 80109998Smarkm{ 81109998Smarkm char s[256]; 82109998Smarkm 83109998Smarkm /* Prepare an error message string: */ 84109998Smarkm strcpy(s, "Fatal error '"); 85109998Smarkm strcat(s, string); 86296341Sdelphij strcat(s, "' at line ? "); 87109998Smarkm strcat(s, "in file "); 88109998Smarkm strcat(s, fname); 89296341Sdelphij strcat(s, " (errno = ?"); 90296341Sdelphij strcat(s, ")\n"); 91296341Sdelphij 92109998Smarkm /* Write the string to the standard error file descriptor: */ 93109998Smarkm _thread_sys_write(2, s, strlen(s)); 94296341Sdelphij 95296341Sdelphij /* Force this process to exit: */ 96296341Sdelphij /* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */ 97296341Sdelphij#if defined(_PTHREADS_INVARIANTS) 98296341Sdelphij abort(); 99109998Smarkm#else 100296341Sdelphij _exit(1); 101296341Sdelphij#endif 102296341Sdelphij} 103296341Sdelphij 104296341Sdelphijvoid 105296341Sdelphijpthread_exit(void *status) 106296341Sdelphij{ 107296341Sdelphij int sig; 108296341Sdelphij long l; 109296341Sdelphij pthread_t pthread; 110296341Sdelphij 111296341Sdelphij /* Check if this thread is already in the process of exiting: */ 112296341Sdelphij if ((_thread_run->flags & PTHREAD_EXITING) != 0) { 113109998Smarkm char msg[128]; 114296341Sdelphij snprintf(msg,"Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",_thread_run); 115109998Smarkm PANIC(msg); 116109998Smarkm } 117296341Sdelphij 118109998Smarkm /* Flag this thread as exiting: */ 119109998Smarkm _thread_run->flags |= PTHREAD_EXITING; 120296341Sdelphij 121296341Sdelphij /* Save the return value: */ 122296341Sdelphij _thread_run->ret = status; 123109998Smarkm 124109998Smarkm while (_thread_run->cleanup != NULL) { 125109998Smarkm pthread_cleanup_pop(1); 126109998Smarkm } 127296341Sdelphij 128109998Smarkm if (_thread_run->attr.cleanup_attr != NULL) { 129296341Sdelphij _thread_run->attr.cleanup_attr(_thread_run->attr.arg_attr); 130296341Sdelphij } 131296341Sdelphij /* Check if there is thread specific data: */ 132296341Sdelphij if (_thread_run->specific_data != NULL) { 133296341Sdelphij /* Run the thread-specific data destructors: */ 134109998Smarkm _thread_cleanupspecific(); 135296341Sdelphij } 136109998Smarkm 137109998Smarkm /* 138109998Smarkm * Defer signals to protect the scheduling queues from access 139296341Sdelphij * by the signal handler: 140109998Smarkm */ 141296341Sdelphij _thread_kern_sig_defer(); 142296341Sdelphij 143296341Sdelphij /* Check if there are any threads joined to this one: */ 144296341Sdelphij while ((pthread = TAILQ_FIRST(&(_thread_run->join_queue))) != NULL) { 145296341Sdelphij /* Remove the thread from the queue: */ 146296341Sdelphij TAILQ_REMOVE(&_thread_run->join_queue, pthread, qe); 147296341Sdelphij 148109998Smarkm /* Wake the joined thread and let it detach this thread: */ 149296341Sdelphij PTHREAD_NEW_STATE(pthread,PS_RUNNING); 150109998Smarkm } 151296341Sdelphij 152296341Sdelphij /* 153296341Sdelphij * Undefer and handle pending signals, yielding if necessary: 154109998Smarkm */ 155109998Smarkm _thread_kern_sig_undefer(); 156109998Smarkm 157296341Sdelphij /* 158296341Sdelphij * Lock the garbage collector mutex to ensure that the garbage 159109998Smarkm * collector is not using the dead thread list. 160109998Smarkm */ 161109998Smarkm if (pthread_mutex_lock(&_gc_mutex) != 0) 162109998Smarkm PANIC("Cannot lock gc mutex"); 163296341Sdelphij 164296341Sdelphij /* Add this thread to the list of dead threads. */ 165296341Sdelphij TAILQ_INSERT_HEAD(&_dead_list, _thread_run, dle); 166296341Sdelphij 167296341Sdelphij /* 168296341Sdelphij * Defer signals to protect the scheduling queues from access 169296341Sdelphij * by the signal handler: 170296341Sdelphij */ 171296341Sdelphij _thread_kern_sig_defer(); 172296341Sdelphij 173296341Sdelphij /* Remove this thread from the thread list: */ 174109998Smarkm TAILQ_REMOVE(&_thread_list, _thread_run, tle); 175296341Sdelphij 176296341Sdelphij /* 177109998Smarkm * Undefer and handle pending signals, yielding if necessary: 178296341Sdelphij */ 179296341Sdelphij _thread_kern_sig_undefer(); 180296341Sdelphij 181296341Sdelphij /* 182296341Sdelphij * Signal the garbage collector thread that there is something 183109998Smarkm * to clean up. 184296341Sdelphij */ 185296341Sdelphij if (pthread_cond_signal(&_gc_cond) != 0) 186109998Smarkm PANIC("Cannot signal gc cond"); 187296341Sdelphij 188296341Sdelphij /* 189296341Sdelphij * Mark the thread as dead so it will not return if it 190296341Sdelphij * gets context switched out when the mutex is unlocked. 191296341Sdelphij */ 192109998Smarkm PTHREAD_SET_STATE(_thread_run, PS_DEAD); 193296341Sdelphij 194296341Sdelphij /* Unlock the garbage collector mutex: */ 195296341Sdelphij if (pthread_mutex_unlock(&_gc_mutex) != 0) 196296341Sdelphij PANIC("Cannot lock gc mutex"); 197109998Smarkm 198296341Sdelphij /* This this thread will never be re-scheduled. */ 199109998Smarkm _thread_kern_sched(NULL); 200296341Sdelphij 201296341Sdelphij /* This point should not be reached. */ 202296341Sdelphij PANIC("Dead thread has resumed"); 203296341Sdelphij} 204296341Sdelphij#endif 205296341Sdelphij