1 /*	$OpenBSD: uthread_exit.c,v 1.17 2002/11/07 02:56:20 marc Exp $	*/
2 /*
3  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by John Birrell.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: uthread_exit.c,v 1.12 1999/08/30 15:45:42 dt Exp $
34  */
35 #include <errno.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <string.h>
39 #include <signal.h>
40 #include <sys/types.h>
41 #ifdef _THREAD_SAFE
42 #include <pthread.h>
43 #include "pthread_private.h"
44 
45 void
_exit(int status)46 _exit(int status)
47 {
48 	int		flags;
49 	int             i;
50 	struct itimerval itimer;
51 
52 	/* Disable the interval timer: */
53 	itimer.it_interval.tv_sec  = 0;
54 	itimer.it_interval.tv_usec = 0;
55 	itimer.it_value.tv_sec     = 0;
56 	itimer.it_value.tv_usec    = 0;
57 	setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL);
58 
59 	/* Close the pthread kernel pipe: */
60 	_thread_sys_close(_thread_kern_pipe[0]);
61 	_thread_sys_close(_thread_kern_pipe[1]);
62 
63 	/*
64 	 * Enter a loop to set all file descriptors to blocking
65 	 * if they were not created as non-blocking:
66 	 */
67 	for (i = 0; i < _thread_dtablesize; i++) {
68 		/* Check if this file descriptor is in use: */
69 		if (_thread_fd_table[i] != NULL &&
70 			!(_thread_fd_table[i]->flags & O_NONBLOCK)) {
71 			/* Get the current flags: */
72 			flags = _thread_sys_fcntl(i, F_GETFL, NULL);
73 			/* Clear the nonblocking file descriptor flag: */
74 			_thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
75 		}
76 	}
77 
78 	/* Call the _exit syscall: */
79 	_thread_sys__exit(status);
80 }
81 
82 static void
numlcat(char * s,int l,size_t sz)83 numlcat(char *s, int l, size_t sz)
84 {
85 	char digit[2];
86 
87 	/* Inefficient. */
88 	if (l < 0) {
89 		l = -l;
90 		strlcat(s, "-", sz);
91 	}
92 	if (l >= 10)
93 		numlcat(s, l / 10, sz);
94 	digit[0] = "0123456789"[l % 10];
95 	digit[1] = '\0';
96 	strlcat(s, digit, sz);
97 }
98 
99 void
_thread_exit(const char * fname,int lineno,const char * string)100 _thread_exit(const char *fname, int lineno, const char *string)
101 {
102 	char            s[256];
103 
104 	/* Prepare an error message string: */
105 	s[0] = '\0';
106 	strlcat(s, "pid ", sizeof s);
107 	numlcat(s, (int)_thread_sys_getpid(), sizeof s);
108 	strlcat(s, ": Fatal error '", sizeof s);
109 	strlcat(s, string, sizeof s);
110 	strlcat(s, "' at line ", sizeof s);
111 	numlcat(s, lineno, sizeof s);
112 	strlcat(s, " in file ", sizeof s);
113 	strlcat(s, fname, sizeof s);
114 	strlcat(s, " (errno = ", sizeof s);
115 	numlcat(s, errno, sizeof s);
116 	strlcat(s, ")\n", sizeof s);
117 
118 	/* Write the string to the standard error file descriptor: */
119 	_thread_sys_write(2, s, strlen(s));
120 
121 	/* Force this process to exit: */
122 	/* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */
123 #if defined(_PTHREADS_INVARIANTS)
124 	{
125 		struct sigaction sa;
126 		sigset_t s;
127 
128 		/* Ignore everything except ABORT */
129 		sigfillset(&s);
130 		sigdelset(&s, SIGABRT);
131 		_thread_sys_sigprocmask(SIG_SETMASK, &s, NULL);
132 
133 		/* Set the abort handler to default (dump core) */
134 		sa.sa_handler = SIG_DFL;
135 		sigemptyset(&sa.sa_mask);
136 		sa.sa_flags = SA_SIGINFO;
137 		(void)_thread_sys_sigaction(SIGABRT, &sa, NULL);
138 		(void)_thread_sys_kill(_thread_sys_getpid(), SIGABRT);
139 		for (;;) ;
140 	}
141 #else
142 	_exit(1);
143 #endif
144 }
145 
146 void
pthread_exit(void * status)147 pthread_exit(void *status)
148 {
149 	struct pthread	*curthread = _get_curthread();
150 	pthread_t pthread;
151 
152 	/* Check if this thread is already in the process of exiting: */
153 	if ((curthread->flags & PTHREAD_EXITING) != 0) {
154 		PANIC("Thread has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!");
155 	}
156 
157 	/* Flag this thread as exiting: */
158 	curthread->flags |= PTHREAD_EXITING;
159 
160 	/* Save the return value: */
161 	curthread->ret = status;
162 
163 	while (curthread->cleanup != NULL) {
164 		pthread_cleanup_pop(1);
165 	}
166 	if (curthread->attr.cleanup_attr != NULL) {
167 		curthread->attr.cleanup_attr(curthread->attr.arg_attr);
168 	}
169 	/* Check if there is thread specific data: */
170 	if (curthread->specific_data != NULL) {
171 		/* Run the thread-specific data destructors: */
172 		_thread_cleanupspecific();
173 	}
174 
175 	/*
176 	 * Lock the garbage collector mutex to ensure that the garbage
177 	 * collector is not using the dead thread list.
178 	 */
179 	if (pthread_mutex_lock(&_gc_mutex) != 0)
180 		PANIC("Cannot lock gc mutex");
181 
182 	/* Add this thread to the list of dead threads. */
183 	TAILQ_INSERT_HEAD(&_dead_list, curthread, dle);
184 
185 	/*
186 	 * Signal the garbage collector thread that there is something
187 	 * to clean up.
188 	 */
189 	if (pthread_cond_signal(&_gc_cond) != 0)
190 		PANIC("Cannot signal gc cond");
191 
192 	/*
193 	 * Avoid a race condition where a scheduling signal can occur
194 	 * causing the garbage collector thread to run.  If this happens,
195 	 * the current thread can be cleaned out from under us.
196 	 */
197 	_thread_kern_sig_defer();
198 
199 	/* Unlock the garbage collector mutex: */
200 	if (pthread_mutex_unlock(&_gc_mutex) != 0)
201 		PANIC("Cannot unlock gc mutex");
202 
203 	/* Check if there is a thread joining this one: */
204 	if (curthread->joiner != NULL) {
205 		pthread = curthread->joiner;
206 		curthread->joiner = NULL;
207 
208 		switch (pthread->suspended) {
209 		case SUSP_JOIN:
210 			/*
211 			 * The joining thread is suspended.  Change the
212 			 * suspension state to make the thread runnable when it
213 			 * is resumed:
214 			 */
215 			pthread->suspended = SUSP_NO;
216 			break;
217 		case SUSP_NO:
218 			/* Make the joining thread runnable: */
219 			PTHREAD_NEW_STATE(pthread, PS_RUNNING);
220 			break;
221 		default:
222 			PANIC("Unreachable code reached");
223 		}
224 
225 		/* Set the return value for the joining thread: */
226 		pthread->join_status.ret = curthread->ret;
227 		pthread->join_status.error = 0;
228 		pthread->join_status.thread = NULL;
229 
230 		/* Make this thread collectable by the garbage collector. */
231 		PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) ==
232 		    0), "Cannot join a detached thread");
233 		curthread->attr.flags |= PTHREAD_DETACHED;
234 	}
235 
236 	/* Remove this thread from the thread list: */
237 	TAILQ_REMOVE(&_thread_list, curthread, tle);
238 
239 	/* This thread will never be re-scheduled. */
240 	_thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
241 
242 	/* This point should not be reached. */
243 	PANIC("Dead thread has resumed");
244 }
245 #endif
246