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.
13165967Simp * 3. Neither the name of the author nor the names of any co-contributors
1413546Sjulian *    may be used to endorse or promote products derived from this software
1513546Sjulian *    without specific prior written permission.
1613546Sjulian *
1713546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
1813546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2049439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2113546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713546Sjulian * SUCH DAMAGE.
2813546Sjulian *
2950476Speter * $FreeBSD$
3013546Sjulian */
31174112Sdeischen
32174112Sdeischen#include "namespace.h"
3313546Sjulian#include <errno.h>
3417706Sjulian#include <unistd.h>
3517706Sjulian#include <fcntl.h>
3653812Salfred#include <stdio.h>
3753812Salfred#include <stdlib.h>
3813546Sjulian#include <string.h>
3913546Sjulian#include <pthread.h>
40174112Sdeischen#include "un-namespace.h"
41103388Smini#include "thr_private.h"
4213546Sjulian
43113658Sdeischenvoid	_pthread_exit(void *status);
4467097Sdeischen
4575369Sdeischen__weak_reference(_pthread_exit, pthread_exit);
4671581Sdeischen
4713546Sjulianvoid
48174112Sdeischen_thr_exit(const char *fname, int lineno, const char *msg)
4913546Sjulian{
5013546Sjulian
51115399Skan	/* Write an error message to the standard error file descriptor: */
52115399Skan	_thread_printf(2,
5372374Sdeischen	    "Fatal error '%s' at line %d in file %s (errno = %d)\n",
54113658Sdeischen	    msg, lineno, fname, errno);
5513546Sjulian
5648046Sjb	abort();
5713546Sjulian}
5813546Sjulian
5953812Salfred/*
6053812Salfred * Only called when a thread is cancelled.  It may be more useful
6153812Salfred * to call it from pthread_exit() if other ways of asynchronous or
6253812Salfred * abnormal thread termination can be found.
6353812Salfred */
6413546Sjulianvoid
65113658Sdeischen_thr_exit_cleanup(void)
6653812Salfred{
6771581Sdeischen	struct pthread	*curthread = _get_curthread();
6871581Sdeischen
6953812Salfred	/*
7053812Salfred	 * POSIX states that cancellation/termination of a thread should
7153812Salfred	 * not release any visible resources (such as mutexes) and that
7253812Salfred	 * it is the applications responsibility.  Resources that are
7353812Salfred	 * internal to the threads library, including file and fd locks,
7453812Salfred	 * are not visible to the application and need to be released.
7553812Salfred	 */
7653812Salfred	/* Unlock all private mutexes: */
7771581Sdeischen	_mutex_unlock_private(curthread);
7853812Salfred
7953812Salfred	/*
8053812Salfred	 * This still isn't quite correct because we don't account
8153812Salfred	 * for held spinlocks (see libc/stdlib/malloc.c).
8253812Salfred	 */
8353812Salfred}
8453812Salfred
8553812Salfredvoid
8671581Sdeischen_pthread_exit(void *status)
8713546Sjulian{
88113658Sdeischen	struct pthread *curthread = _get_curthread();
89120074Sdavidxu	kse_critical_t crit;
90120074Sdavidxu	struct kse *curkse;
9113546Sjulian
9236827Sjb	/* Check if this thread is already in the process of exiting: */
93113658Sdeischen	if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
9436827Sjb		char msg[128];
95113658Sdeischen		snprintf(msg, sizeof(msg), "Thread %p has called "
96113658Sdeischen		    "pthread_exit() from a destructor. POSIX 1003.1 "
97113658Sdeischen		    "1996 s16.2.5.2 does not allow this!", curthread);
9836827Sjb		PANIC(msg);
9936827Sjb	}
10036827Sjb
101113658Sdeischen	/*
102113658Sdeischen	 * Flag this thread as exiting.  Threads should now be prevented
103113658Sdeischen	 * from joining to this thread.
104113658Sdeischen	 */
105114187Sdeischen	THR_SCHED_LOCK(curthread, curthread);
106113658Sdeischen	curthread->flags |= THR_FLAGS_EXITING;
107114187Sdeischen	THR_SCHED_UNLOCK(curthread, curthread);
108136847Sdavidxu
109136847Sdavidxu	/*
110136847Sdavidxu	 * To avoid signal-lost problem, if signals had already been
111136847Sdavidxu	 * delivered to us, handle it. we have already set EXITING flag
112136847Sdavidxu	 * so no new signals should be delivered to us.
113136847Sdavidxu	 * XXX this is not enough if signal was delivered just before
114136847Sdavidxu	 * thread called sigprocmask and masked it! in this case, we
115136847Sdavidxu	 * might have to re-post the signal by kill() if the signal
116136847Sdavidxu	 * is targeting process (not for a specified thread).
117136847Sdavidxu	 * Kernel has same signal-lost problem, a signal may be delivered
118136847Sdavidxu	 * to a thread which is on the way to call sigprocmask or thr_exit()!
119136847Sdavidxu	 */
120136847Sdavidxu	if (curthread->check_pending)
121136847Sdavidxu		_thr_sig_check_pending(curthread);
12213546Sjulian	/* Save the return value: */
12371581Sdeischen	curthread->ret = status;
12471581Sdeischen	while (curthread->cleanup != NULL) {
125174112Sdeischen		_pthread_cleanup_pop(1);
12613546Sjulian	}
12771581Sdeischen	if (curthread->attr.cleanup_attr != NULL) {
12871581Sdeischen		curthread->attr.cleanup_attr(curthread->attr.arg_attr);
12913546Sjulian	}
13013546Sjulian	/* Check if there is thread specific data: */
13192730Sdeischen	if (curthread->specific != NULL) {
13213546Sjulian		/* Run the thread-specific data destructors: */
13313546Sjulian		_thread_cleanupspecific();
13413546Sjulian	}
135120074Sdavidxu	if (!_kse_isthreaded())
136120074Sdavidxu		exit(0);
137120074Sdavidxu	crit = _kse_critical_enter();
138120074Sdavidxu	curkse = _get_curkse();
139120074Sdavidxu	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
140120074Sdavidxu	/* Use thread_list_lock */
141132120Sdavidxu	_thread_active_threads--;
142133563Sdeischen	if ((_thread_scope_system <= 0 && _thread_active_threads == 1) ||
143133563Sdeischen	    (_thread_scope_system > 0 && _thread_active_threads == 0)) {
144120074Sdavidxu		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
145120074Sdavidxu		_kse_critical_leave(crit);
146120074Sdavidxu		exit(0);
147120074Sdavidxu		/* Never reach! */
148120074Sdavidxu	}
149120074Sdavidxu	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
15044963Sjb
15167097Sdeischen	/* This thread will never be re-scheduled. */
152120074Sdavidxu	KSE_LOCK(curkse);
153113658Sdeischen	THR_SET_STATE(curthread, PS_DEAD);
154115080Sdeischen	_thr_sched_switch_unlocked(curthread);
155114187Sdeischen	/* Never reach! */
15668516Sdeischen
15768516Sdeischen	/* This point should not be reached. */
15868516Sdeischen	PANIC("Dead thread has resumed");
15913546Sjulian}
160