xref: /freebsd/lib/libthr/thread/thr_exit.c (revision cdcffc3f1ca65ddc5d0b30afa493654afd7e895a)
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;
84*cdcffc3fSDavid Xu 	curthread->cancel_enable = 0;
85*cdcffc3fSDavid Xu 	curthread->cancel_async = 0;
86a091d823SDavid Xu 
87a091d823SDavid Xu 	_thr_exit_cleanup();
88bb535300SJeff Roberson 
89bb535300SJeff Roberson 	/* Save the return value: */
90bb535300SJeff Roberson 	curthread->ret = status;
91bb535300SJeff Roberson 	while (curthread->cleanup != NULL) {
929ba01c86SDavid Xu 		_pthread_cleanup_pop(1);
93bb535300SJeff Roberson 	}
9437a6356bSDavid Xu 
95bb535300SJeff Roberson 	/* Check if there is thread specific data: */
96bb535300SJeff Roberson 	if (curthread->specific != NULL) {
97bb535300SJeff Roberson 		/* Run the thread-specific data destructors: */
98bb535300SJeff Roberson 		_thread_cleanupspecific();
99bb535300SJeff Roberson 	}
100bb535300SJeff Roberson 
101a091d823SDavid Xu 	if (!_thr_isthreaded())
1024e3f7b6eSMike Makonnen 		exit(0);
103f97591bfSMike Makonnen 
104a091d823SDavid Xu 	THREAD_LIST_LOCK(curthread);
105a091d823SDavid Xu 	_thread_active_threads--;
106a091d823SDavid Xu 	if (_thread_active_threads == 0) {
107a091d823SDavid Xu 		THREAD_LIST_UNLOCK(curthread);
108a091d823SDavid Xu 		exit(0);
109a091d823SDavid Xu 		/* Never reach! */
110bb535300SJeff Roberson 	}
1115b3842aeSJason Evans 	THREAD_LIST_UNLOCK(curthread);
1125b3842aeSJason Evans 
1135b3842aeSJason Evans 	/* Tell malloc that the thread is exiting. */
1145b3842aeSJason Evans 	_malloc_thread_cleanup();
1155b3842aeSJason Evans 
1165b3842aeSJason Evans 	THREAD_LIST_LOCK(curthread);
117bc414752SDavid Xu 	THR_LOCK(curthread);
118bc414752SDavid Xu 	curthread->state = PS_DEAD;
1192ea1f90aSDavid Xu 	if (curthread->flags & THR_FLAGS_NEED_SUSPEND) {
1202ea1f90aSDavid Xu 		curthread->cycle++;
1218d6a11a0SDavid Xu 		_thr_umtx_wake(&curthread->cycle, INT_MAX, 0);
1222ea1f90aSDavid Xu 	}
123bc414752SDavid Xu 	THR_UNLOCK(curthread);
124bc414752SDavid Xu 	/*
125bc414752SDavid Xu 	 * Thread was created with initial refcount 1, we drop the
126bc414752SDavid Xu 	 * reference count to allow it to be garbage collected.
127bc414752SDavid Xu 	 */
128bc414752SDavid Xu 	curthread->refcount--;
129a091d823SDavid Xu 	if (curthread->tlflags & TLFLAGS_DETACHED)
130a091d823SDavid Xu 		THR_GCLIST_ADD(curthread);
131a091d823SDavid Xu 	THREAD_LIST_UNLOCK(curthread);
132697b4b49SDavid Xu 	if (!curthread->force_exit && SHOULD_REPORT_EVENT(curthread, TD_DEATH))
133d245d9e1SDavid Xu 		_thr_report_death(curthread);
134d7f119abSDavid Xu 
135d7f119abSDavid Xu 	/*
136d7f119abSDavid Xu 	 * Kernel will do wakeup at the address, so joiner thread
137d7f119abSDavid Xu 	 * will be resumed if it is sleeping at the address.
138d7f119abSDavid Xu 	 */
139d245d9e1SDavid Xu 	thr_exit(&curthread->tid);
140a091d823SDavid Xu 	PANIC("thr_exit() returned");
141a091d823SDavid Xu 	/* Never reach! */
1421c6f6301SMike Makonnen }
143