2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "namespace.h"
39 #include "un-namespace.h"
40 #include "pthread_private.h"
42 __weak_reference(_pthread_exit, pthread_exit);
49 struct itimerval itimer;
51 /* Disable the interval timer: */
52 itimer.it_interval.tv_sec = 0;
53 itimer.it_interval.tv_usec = 0;
54 itimer.it_value.tv_sec = 0;
55 itimer.it_value.tv_usec = 0;
56 setitimer(_ITIMER_SCHED_TIMER, &itimer, NULL);
58 /* Close the pthread kernel pipe: */
59 __sys_close(_thread_kern_pipe[0]);
60 __sys_close(_thread_kern_pipe[1]);
63 * Enter a loop to set all file descriptors to blocking
64 * if they were not created as non-blocking:
66 for (i = 0; i < _thread_dtablesize; i++) {
67 /* Check if this file descriptor is in use: */
68 if (_thread_fd_table[i] != NULL &&
69 (_thread_fd_getflags(i) & O_NONBLOCK) == 0) {
70 /* Get the current flags: */
71 flags = __sys_fcntl(i, F_GETFL, NULL);
72 /* Clear the nonblocking file descriptor flag: */
73 __sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
77 /* Call the _exit syscall: */
82 _thread_exit(char *fname, int lineno, char *string)
86 /* Prepare an error message string: */
87 snprintf(s, sizeof(s),
88 "Fatal error '%s' at line %d in file %s (errno = %d)\n",
89 string, lineno, fname, errno);
91 /* Write the string to the standard error file descriptor: */
92 __sys_write(2, s, strlen(s));
94 /* Force this process to exit: */
95 /* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */
96 #if defined(_PTHREADS_INVARIANTS)
104 * Only called when a thread is cancelled. It may be more useful
105 * to call it from pthread_exit() if other ways of asynchronous or
106 * abnormal thread termination can be found.
109 _thread_exit_cleanup(void)
111 struct pthread *curthread = _get_curthread();
114 * POSIX states that cancellation/termination of a thread should
115 * not release any visible resources (such as mutexes) and that
116 * it is the applications responsibility. Resources that are
117 * internal to the threads library, including file and fd locks,
118 * are not visible to the application and need to be released.
120 /* Unlock all owned fd locks: */
121 _thread_fd_unlock_owned(curthread);
123 /* Unlock all private mutexes: */
124 _mutex_unlock_private(curthread);
127 * This still isn't quite correct because we don't account
128 * for held spinlocks (see libc/stdlib/malloc.c).
133 _pthread_exit(void *status)
135 struct pthread *curthread = _get_curthread();
138 /* Check if this thread is already in the process of exiting: */
139 if ((curthread->flags & PTHREAD_EXITING) != 0) {
141 snprintf(msg, sizeof(msg), "Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",curthread);
145 /* Flag this thread as exiting: */
146 curthread->flags |= PTHREAD_EXITING;
148 /* Save the return value: */
149 curthread->ret = status;
151 while (curthread->cleanup != NULL) {
152 pthread_cleanup_pop(1);
154 if (curthread->attr.cleanup_attr != NULL) {
155 curthread->attr.cleanup_attr(curthread->attr.arg_attr);
157 /* Check if there is thread specific data: */
158 if (curthread->specific != NULL) {
159 /* Run the thread-specific data destructors: */
160 _thread_cleanupspecific();
163 /* Free thread-specific poll_data structure, if allocated: */
164 if (curthread->poll_data.fds != NULL) {
165 free(curthread->poll_data.fds);
166 curthread->poll_data.fds = NULL;
170 * Lock the garbage collector mutex to ensure that the garbage
171 * collector is not using the dead thread list.
173 if (_pthread_mutex_lock(&_gc_mutex) != 0)
174 PANIC("Cannot lock gc mutex");
176 /* Add this thread to the list of dead threads. */
177 TAILQ_INSERT_HEAD(&_dead_list, curthread, dle);
180 * Signal the garbage collector thread that there is something
183 if (_pthread_cond_signal(&_gc_cond) != 0)
184 PANIC("Cannot signal gc cond");
187 * Avoid a race condition where a scheduling signal can occur
188 * causing the garbage collector thread to run. If this happens,
189 * the current thread can be cleaned out from under us.
191 _thread_kern_sig_defer();
193 /* Unlock the garbage collector mutex: */
194 if (_pthread_mutex_unlock(&_gc_mutex) != 0)
195 PANIC("Cannot unlock gc mutex");
197 /* Check if there is a thread joining this one: */
198 if (curthread->joiner != NULL) {
199 pthread = curthread->joiner;
200 curthread->joiner = NULL;
202 /* Make the joining thread runnable: */
203 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
205 /* Set the return value for the joining thread: */
206 pthread->join_status.ret = curthread->ret;
207 pthread->join_status.error = 0;
208 pthread->join_status.thread = NULL;
210 /* Make this thread collectable by the garbage collector. */
211 PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) ==
212 0), "Cannot join a detached thread");
213 curthread->attr.flags |= PTHREAD_DETACHED;
216 /* Remove this thread from the thread list: */
217 TAILQ_REMOVE(&_thread_list, curthread, tle);
219 /* This thread will never be re-scheduled. */
220 _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__);
222 /* This point should not be reached. */
223 PANIC("Dead thread has resumed");