thr_exit.c revision 132120
1319780Sdim/*
2319780Sdim * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3319780Sdim * All rights reserved.
4319780Sdim *
5319780Sdim * Redistribution and use in source and binary forms, with or without
6319780Sdim * modification, are permitted provided that the following conditions
7319780Sdim * are met:
8319780Sdim * 1. Redistributions of source code must retain the above copyright
9319780Sdim *    notice, this list of conditions and the following disclaimer.
10319780Sdim * 2. Redistributions in binary form must reproduce the above copyright
11319780Sdim *    notice, this list of conditions and the following disclaimer in the
12319780Sdim *    documentation and/or other materials provided with the distribution.
13319780Sdim * 3. All advertising materials mentioning features or use of this software
14319780Sdim *    must display the following acknowledgement:
15319780Sdim *	This product includes software developed by John Birrell.
16319780Sdim * 4. Neither the name of the author nor the names of any co-contributors
17319780Sdim *    may be used to endorse or promote products derived from this software
18319780Sdim *    without specific prior written permission.
19319780Sdim *
20319780Sdim * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21319780Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22319780Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23319780Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24319780Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25319780Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26319780Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27319780Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28319780Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29319780Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30319780Sdim * SUCH DAMAGE.
31319780Sdim *
32319780Sdim * $FreeBSD: head/lib/libkse/thread/thr_exit.c 132120 2004-07-13 22:49:58Z davidxu $
33319780Sdim */
34319780Sdim#include <errno.h>
35319780Sdim#include <unistd.h>
36319780Sdim#include <fcntl.h>
37319780Sdim#include <stdio.h>
38319780Sdim#include <stdlib.h>
39319780Sdim#include <string.h>
40319780Sdim#include <pthread.h>
41319780Sdim#include "thr_private.h"
42319780Sdim
43319780Sdimvoid	_pthread_exit(void *status);
44319780Sdim
45319780Sdim__weak_reference(_pthread_exit, pthread_exit);
46319780Sdim
47319780Sdimvoid
48319780Sdim_thr_exit(char *fname, int lineno, char *msg)
49320397Sdim{
50320397Sdim
51320397Sdim	/* Write an error message to the standard error file descriptor: */
52320397Sdim	_thread_printf(2,
53320397Sdim	    "Fatal error '%s' at line %d in file %s (errno = %d)\n",
54320397Sdim	    msg, lineno, fname, errno);
55319780Sdim
56319780Sdim	abort();
57319780Sdim}
58319780Sdim
59319780Sdim/*
60319780Sdim * Only called when a thread is cancelled.  It may be more useful
61319780Sdim * to call it from pthread_exit() if other ways of asynchronous or
62319780Sdim * abnormal thread termination can be found.
63319780Sdim */
64319780Sdimvoid
65319780Sdim_thr_exit_cleanup(void)
66319780Sdim{
67319780Sdim	struct pthread	*curthread = _get_curthread();
68319780Sdim
69319780Sdim	/*
70319780Sdim	 * POSIX states that cancellation/termination of a thread should
71319780Sdim	 * not release any visible resources (such as mutexes) and that
72319780Sdim	 * it is the applications responsibility.  Resources that are
73319780Sdim	 * internal to the threads library, including file and fd locks,
74319780Sdim	 * are not visible to the application and need to be released.
75319780Sdim	 */
76319780Sdim	/* Unlock all private mutexes: */
77319780Sdim	_mutex_unlock_private(curthread);
78319780Sdim
79319780Sdim	/*
80319780Sdim	 * This still isn't quite correct because we don't account
81319780Sdim	 * for held spinlocks (see libc/stdlib/malloc.c).
82319780Sdim	 */
83319780Sdim}
84319780Sdim
85319780Sdimvoid
86319780Sdim_pthread_exit(void *status)
87319780Sdim{
88319780Sdim	struct pthread *curthread = _get_curthread();
89319780Sdim	kse_critical_t crit;
90319780Sdim	struct kse *curkse;
91319780Sdim
92319780Sdim	/* Check if this thread is already in the process of exiting: */
93319780Sdim	if ((curthread->flags & THR_FLAGS_EXITING) != 0) {
94327952Sdim		char msg[128];
95319780Sdim		snprintf(msg, sizeof(msg), "Thread %p has called "
96319780Sdim		    "pthread_exit() from a destructor. POSIX 1003.1 "
97319780Sdim		    "1996 s16.2.5.2 does not allow this!", curthread);
98327952Sdim		PANIC(msg);
99319780Sdim	}
100319780Sdim
101319780Sdim	/*
102319780Sdim	 * Flag this thread as exiting.  Threads should now be prevented
103319780Sdim	 * from joining to this thread.
104319780Sdim	 */
105319780Sdim	THR_SCHED_LOCK(curthread, curthread);
106319780Sdim	curthread->flags |= THR_FLAGS_EXITING;
107319780Sdim	THR_SCHED_UNLOCK(curthread, curthread);
108319780Sdim
109319780Sdim	/* Save the return value: */
110319780Sdim	curthread->ret = status;
111319780Sdim	while (curthread->cleanup != NULL) {
112319780Sdim		pthread_cleanup_pop(1);
113319780Sdim	}
114319780Sdim	if (curthread->attr.cleanup_attr != NULL) {
115319780Sdim		curthread->attr.cleanup_attr(curthread->attr.arg_attr);
116319780Sdim	}
117319780Sdim	/* Check if there is thread specific data: */
118319780Sdim	if (curthread->specific != NULL) {
119319780Sdim		/* Run the thread-specific data destructors: */
120319780Sdim		_thread_cleanupspecific();
121327952Sdim	}
122319780Sdim	if (!_kse_isthreaded())
123319780Sdim		exit(0);
124319780Sdim	crit = _kse_critical_enter();
125319780Sdim	curkse = _get_curkse();
126319780Sdim	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
127319780Sdim	/* Use thread_list_lock */
128319780Sdim	_thread_active_threads--;
129319780Sdim#ifdef SYSTEM_SCOPE_ONLY
130319780Sdim	if (_thread_active_threads == 0) {
131319780Sdim#else
132319780Sdim	if (_thread_active_threads == 1) {
133319780Sdim#endif
134319780Sdim		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
135319780Sdim		_kse_critical_leave(crit);
136319780Sdim		exit(0);
137319780Sdim		/* Never reach! */
138319780Sdim	}
139319780Sdim	KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
140319780Sdim
141319780Sdim	/* This thread will never be re-scheduled. */
142319780Sdim	KSE_LOCK(curkse);
143319780Sdim	THR_SET_STATE(curthread, PS_DEAD);
144319780Sdim	_thr_sched_switch_unlocked(curthread);
145319780Sdim	/* Never reach! */
146319780Sdim
147319780Sdim	/* This point should not be reached. */
148319780Sdim	PANIC("Dead thread has resumed");
149319780Sdim}
150319780Sdim