xref: /freebsd/lib/libthr/thread/thr_exit.c (revision d6742bfbd3ecadd2bde38ccbb2351bd5c19ede1d)
1bb535300SJeff Roberson /*
2bb535300SJeff Roberson  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3bb535300SJeff Roberson  * All rights reserved.
4bb535300SJeff Roberson  *
5bb535300SJeff Roberson  * Redistribution and use in source and binary forms, with or without
6bb535300SJeff Roberson  * modification, are permitted provided that the following conditions
7bb535300SJeff Roberson  * are met:
8bb535300SJeff Roberson  * 1. Redistributions of source code must retain the above copyright
9bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer.
10bb535300SJeff Roberson  * 2. Redistributions in binary form must reproduce the above copyright
11bb535300SJeff Roberson  *    notice, this list of conditions and the following disclaimer in the
12bb535300SJeff Roberson  *    documentation and/or other materials provided with the distribution.
13fed32d75SWarner Losh  * 3. Neither the name of the author nor the names of any co-contributors
14bb535300SJeff Roberson  *    may be used to endorse or promote products derived from this software
15bb535300SJeff Roberson  *    without specific prior written permission.
16bb535300SJeff Roberson  *
17bb535300SJeff Roberson  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18bb535300SJeff Roberson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19bb535300SJeff Roberson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20bb535300SJeff Roberson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21bb535300SJeff Roberson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22bb535300SJeff Roberson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23bb535300SJeff Roberson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24bb535300SJeff Roberson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25bb535300SJeff Roberson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26bb535300SJeff Roberson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27bb535300SJeff Roberson  * SUCH DAMAGE.
28bb535300SJeff Roberson  *
29bb535300SJeff Roberson  * $FreeBSD$
30bb535300SJeff Roberson  */
31a091d823SDavid Xu 
32e03efb02SRuslan Ermilov #include "namespace.h"
33bb535300SJeff Roberson #include <errno.h>
34bb535300SJeff Roberson #include <stdio.h>
35bb535300SJeff Roberson #include <stdlib.h>
36bb535300SJeff Roberson #include <pthread.h>
37e03efb02SRuslan Ermilov #include "un-namespace.h"
38a091d823SDavid Xu 
39d6742bfbSJason Evans #include "libc_private.h"
40bb535300SJeff Roberson #include "thr_private.h"
41bb535300SJeff Roberson 
42a091d823SDavid Xu void	_pthread_exit(void *status);
43a091d823SDavid Xu 
44bb535300SJeff Roberson __weak_reference(_pthread_exit, pthread_exit);
45bb535300SJeff Roberson 
46bb535300SJeff Roberson void
4737a6356bSDavid Xu _thread_exit(const char *fname, int lineno, const char *msg)
48bb535300SJeff Roberson {
49bb535300SJeff Roberson 
50a091d823SDavid Xu 	/* Write an error message to the standard error file descriptor: */
51a091d823SDavid Xu 	_thread_printf(2,
52bb535300SJeff Roberson 	    "Fatal error '%s' at line %d in file %s (errno = %d)\n",
53a091d823SDavid Xu 	    msg, lineno, fname, errno);
54bb535300SJeff Roberson 
55bb535300SJeff Roberson 	abort();
56bb535300SJeff Roberson }
57bb535300SJeff Roberson 
58bb535300SJeff Roberson /*
59bb535300SJeff Roberson  * Only called when a thread is cancelled.  It may be more useful
60bb535300SJeff Roberson  * to call it from pthread_exit() if other ways of asynchronous or
61bb535300SJeff Roberson  * abnormal thread termination can be found.
62bb535300SJeff Roberson  */
63bb535300SJeff Roberson void
64a091d823SDavid Xu _thr_exit_cleanup(void)
65bb535300SJeff Roberson {
66bb535300SJeff Roberson }
67bb535300SJeff Roberson 
68bb535300SJeff Roberson void
69bb535300SJeff Roberson _pthread_exit(void *status)
70bb535300SJeff Roberson {
71a091d823SDavid Xu 	struct pthread *curthread = _get_curthread();
724cd18a22SMike Makonnen 
73bb535300SJeff Roberson 	/* Check if this thread is already in the process of exiting: */
74f08e1bf6SDavid Xu 	if (curthread->cancelling) {
75bb535300SJeff Roberson 		char msg[128];
76a091d823SDavid Xu 		snprintf(msg, sizeof(msg), "Thread %p has called "
77a091d823SDavid Xu 		    "pthread_exit() from a destructor. POSIX 1003.1 "
78a091d823SDavid Xu 		    "1996 s16.2.5.2 does not allow this!", curthread);
79bb535300SJeff Roberson 		PANIC(msg);
80bb535300SJeff Roberson 	}
81bb535300SJeff Roberson 
82a091d823SDavid Xu 	/* Flag this thread as exiting. */
83f08e1bf6SDavid Xu 	curthread->cancelling = 1;
84a091d823SDavid Xu 
85a091d823SDavid Xu 	_thr_exit_cleanup();
86bb535300SJeff Roberson 
87bb535300SJeff Roberson 	/* Save the return value: */
88bb535300SJeff Roberson 	curthread->ret = status;
89bb535300SJeff Roberson 	while (curthread->cleanup != NULL) {
909ba01c86SDavid Xu 		_pthread_cleanup_pop(1);
91bb535300SJeff Roberson 	}
9237a6356bSDavid Xu 
93bb535300SJeff Roberson 	/* Check if there is thread specific data: */
94bb535300SJeff Roberson 	if (curthread->specific != NULL) {
95bb535300SJeff Roberson 		/* Run the thread-specific data destructors: */
96bb535300SJeff Roberson 		_thread_cleanupspecific();
97bb535300SJeff Roberson 	}
98bb535300SJeff Roberson 
99d6742bfbSJason Evans 	/* Tell malloc that the thread is exiting. */
100d6742bfbSJason Evans 	_malloc_thread_cleanup();
101d6742bfbSJason Evans 
102a091d823SDavid Xu 	if (!_thr_isthreaded())
1034e3f7b6eSMike Makonnen 		exit(0);
104f97591bfSMike Makonnen 
105a091d823SDavid Xu 	THREAD_LIST_LOCK(curthread);
106a091d823SDavid Xu 	_thread_active_threads--;
107a091d823SDavid Xu 	if (_thread_active_threads == 0) {
108a091d823SDavid Xu 		THREAD_LIST_UNLOCK(curthread);
109a091d823SDavid Xu 		exit(0);
110a091d823SDavid Xu 		/* Never reach! */
111bb535300SJeff Roberson 	}
112bc414752SDavid Xu 	THR_LOCK(curthread);
113bc414752SDavid Xu 	curthread->state = PS_DEAD;
1142ea1f90aSDavid Xu 	if (curthread->flags & THR_FLAGS_NEED_SUSPEND) {
1152ea1f90aSDavid Xu 		curthread->cycle++;
1168d6a11a0SDavid Xu 		_thr_umtx_wake(&curthread->cycle, INT_MAX, 0);
1172ea1f90aSDavid Xu 	}
118bc414752SDavid Xu 	THR_UNLOCK(curthread);
119bc414752SDavid Xu 	/*
120bc414752SDavid Xu 	 * Thread was created with initial refcount 1, we drop the
121bc414752SDavid Xu 	 * reference count to allow it to be garbage collected.
122bc414752SDavid Xu 	 */
123bc414752SDavid Xu 	curthread->refcount--;
124a091d823SDavid Xu 	if (curthread->tlflags & TLFLAGS_DETACHED)
125a091d823SDavid Xu 		THR_GCLIST_ADD(curthread);
126a091d823SDavid Xu 	THREAD_LIST_UNLOCK(curthread);
127697b4b49SDavid Xu 	if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH))
128d245d9e1SDavid Xu 		_thr_report_death(curthread);
129d7f119abSDavid Xu 
130d7f119abSDavid Xu 	/*
131d7f119abSDavid Xu 	 * Kernel will do wakeup at the address, so joiner thread
132d7f119abSDavid Xu 	 * will be resumed if it is sleeping at the address.
133d7f119abSDavid Xu 	 */
134d245d9e1SDavid Xu 	thr_exit(&curthread->tid);
135a091d823SDavid Xu 	PANIC("thr_exit() returned");
136a091d823SDavid Xu 	/* Never reach! */
1371c6f6301SMike Makonnen }
138