thr_exit.c revision 44963
113546Sjulian/*
235509Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
1313546Sjulian * 3. All advertising materials mentioning features or use of this software
1413546Sjulian *    must display the following acknowledgement:
1513546Sjulian *	This product includes software developed by John Birrell.
1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors
1713546Sjulian *    may be used to endorse or promote products derived from this software
1813546Sjulian *    without specific prior written permission.
1913546Sjulian *
2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2313546Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013546Sjulian * SUCH DAMAGE.
3113546Sjulian *
3213546Sjulian */
3313546Sjulian#include <errno.h>
3417706Sjulian#include <unistd.h>
3517706Sjulian#include <fcntl.h>
3613546Sjulian#include <string.h>
3713546Sjulian#ifdef _THREAD_SAFE
3813546Sjulian#include <pthread.h>
3913546Sjulian#include "pthread_private.h"
4013546Sjulian
4117706Sjulianvoid _exit(int status)
4217706Sjulian{
4317706Sjulian	int		flags;
4417706Sjulian	int             i;
4517706Sjulian	struct itimerval itimer;
4617706Sjulian
4717706Sjulian	/* Disable the interval timer: */
4817706Sjulian	itimer.it_interval.tv_sec  = 0;
4917706Sjulian	itimer.it_interval.tv_usec = 0;
5017706Sjulian	itimer.it_value.tv_sec     = 0;
5117706Sjulian	itimer.it_value.tv_usec    = 0;
5244963Sjb	setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL);
5317706Sjulian
5417706Sjulian	/* Close the pthread kernel pipe: */
5517706Sjulian	_thread_sys_close(_thread_kern_pipe[0]);
5617706Sjulian	_thread_sys_close(_thread_kern_pipe[1]);
5717706Sjulian
5817706Sjulian	/*
5917706Sjulian	 * Enter a loop to set all file descriptors to blocking
6017706Sjulian	 * if they were not created as non-blocking:
6117706Sjulian	 */
6217706Sjulian	for (i = 0; i < _thread_dtablesize; i++) {
6317706Sjulian		/* Check if this file descriptor is in use: */
6417706Sjulian		if (_thread_fd_table[i] != NULL &&
6517706Sjulian			!(_thread_fd_table[i]->flags & O_NONBLOCK)) {
6617706Sjulian			/* Get the current flags: */
6717706Sjulian			flags = _thread_sys_fcntl(i, F_GETFL, NULL);
6817706Sjulian			/* Clear the nonblocking file descriptor flag: */
6917706Sjulian			_thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
7017706Sjulian		}
7117706Sjulian	}
7217706Sjulian
7317706Sjulian	/* Call the _exit syscall: */
7417706Sjulian	_thread_sys__exit(status);
7517706Sjulian}
7617706Sjulian
7713546Sjulianvoid
7813546Sjulian_thread_exit(char *fname, int lineno, char *string)
7913546Sjulian{
8013546Sjulian	char            s[256];
8113546Sjulian
8213546Sjulian	/* Prepare an error message string: */
8313546Sjulian	strcpy(s, "Fatal error '");
8413546Sjulian	strcat(s, string);
8513546Sjulian	strcat(s, "' at line ? ");
8613546Sjulian	strcat(s, "in file ");
8713546Sjulian	strcat(s, fname);
8813546Sjulian	strcat(s, " (errno = ?");
8913546Sjulian	strcat(s, ")\n");
9013546Sjulian
9113546Sjulian	/* Write the string to the standard error file descriptor: */
9213546Sjulian	_thread_sys_write(2, s, strlen(s));
9313546Sjulian
9413546Sjulian	/* Force this process to exit: */
9513546Sjulian	_exit(1);
9613546Sjulian}
9713546Sjulian
9813546Sjulianvoid
9913546Sjulianpthread_exit(void *status)
10013546Sjulian{
10113546Sjulian	int             sig;
10213546Sjulian	long            l;
10313546Sjulian	pthread_t       pthread;
10413546Sjulian
10536827Sjb	/* Check if this thread is already in the process of exiting: */
10636827Sjb	if ((_thread_run->flags & PTHREAD_EXITING) != 0) {
10736827Sjb		char msg[128];
10836827Sjb		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);
10936827Sjb		PANIC(msg);
11036827Sjb	}
11136827Sjb
11236827Sjb	/* Flag this thread as exiting: */
11336827Sjb	_thread_run->flags |= PTHREAD_EXITING;
11436827Sjb
11513546Sjulian	/* Save the return value: */
11613546Sjulian	_thread_run->ret = status;
11713546Sjulian
11813546Sjulian	while (_thread_run->cleanup != NULL) {
11922315Sjulian		pthread_cleanup_pop(1);
12013546Sjulian	}
12113546Sjulian
12213546Sjulian	if (_thread_run->attr.cleanup_attr != NULL) {
12313546Sjulian		_thread_run->attr.cleanup_attr(_thread_run->attr.arg_attr);
12413546Sjulian	}
12513546Sjulian	/* Check if there is thread specific data: */
12613546Sjulian	if (_thread_run->specific_data != NULL) {
12713546Sjulian		/* Run the thread-specific data destructors: */
12813546Sjulian		_thread_cleanupspecific();
12913546Sjulian	}
13044963Sjb
13144963Sjb	/*
13244963Sjb	 * Guard against preemption by a scheduling signal.  A change of
13344963Sjb	 * thread state modifies the waiting and priority queues.
13444963Sjb	 */
13544963Sjb	_thread_kern_sched_defer();
13644963Sjb
13713546Sjulian	/* Check if there are any threads joined to this one: */
13813546Sjulian	while ((pthread = _thread_queue_deq(&(_thread_run->join_queue))) != NULL) {
13913546Sjulian		/* Wake the joined thread and let it detach this thread: */
14022315Sjulian		PTHREAD_NEW_STATE(pthread,PS_RUNNING);
14113546Sjulian	}
14213546Sjulian
14339807Sjb	/*
14444963Sjb	 * Reenable preemption and yield if a scheduling signal
14544963Sjb	 * occurred while in the critical region.
14644963Sjb	 */
14744963Sjb	_thread_kern_sched_undefer();
14844963Sjb
14944963Sjb	/*
15039807Sjb	 * Lock the garbage collector mutex to ensure that the garbage
15139807Sjb	 * collector is not using the dead thread list.
15239807Sjb	 */
15339807Sjb	if (pthread_mutex_lock(&_gc_mutex) != 0)
15439807Sjb		PANIC("Cannot lock gc mutex");
15535509Sjb
15639807Sjb	/* Add this thread to the list of dead threads. */
15739807Sjb	_thread_run->nxt_dead = _thread_dead;
15839807Sjb	_thread_dead = _thread_run;
15913546Sjulian
16013546Sjulian	/*
16139807Sjb	 * Signal the garbage collector thread that there is something
16239807Sjb	 * to clean up.
16313546Sjulian	 */
16439807Sjb	if (pthread_cond_signal(&_gc_cond) != 0)
16539807Sjb		PANIC("Cannot signal gc cond");
16613546Sjulian
16739807Sjb	/* Unlock the garbage collector mutex: */
16839807Sjb	if (pthread_mutex_unlock(&_gc_mutex) != 0)
16939807Sjb		PANIC("Cannot lock gc mutex");
17035509Sjb
17139807Sjb	/* This this thread will never be re-scheduled. */
17213546Sjulian	_thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
17313546Sjulian
17413546Sjulian	/* This point should not be reached. */
17513546Sjulian	PANIC("Dead thread has resumed");
17613546Sjulian}
17713546Sjulian#endif
178