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