2 * Copyright (c) 1995 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
32 #include "namespace.h"
35 #include "un-namespace.h"
36 #include "thr_private.h"
38 __weak_reference(_pthread_join, pthread_join);
41 _pthread_join(pthread_t pthread, void **thread_return)
43 struct pthread *curthread = _get_curthread();
48 _thr_cancel_enter(curthread);
50 /* Check if the caller has specified an invalid thread: */
51 if (pthread == NULL || pthread->magic != THR_MAGIC) {
53 _thr_cancel_leave(curthread, 1);
57 /* Check if the caller has specified itself: */
58 if (pthread == curthread) {
59 /* Avoid a deadlock condition: */
60 _thr_cancel_leave(curthread, 1);
65 * Find the thread in the list of active threads or in the
66 * list of dead threads:
68 if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) {
69 /* Return an error: */
70 _thr_cancel_leave(curthread, 1);
74 THR_SCHED_LOCK(curthread, pthread);
75 /* Check if this thread has been detached: */
76 if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
77 THR_SCHED_UNLOCK(curthread, pthread);
78 /* Remove the reference and return an error: */
79 _thr_ref_delete(curthread, pthread);
82 /* Lock the target thread while checking its state. */
83 if (pthread->state == PS_DEAD) {
84 /* Return the thread's return value: */
87 /* Detach the thread. */
88 pthread->attr.flags |= PTHREAD_DETACHED;
90 /* Unlock the thread. */
91 THR_SCHED_UNLOCK(curthread, pthread);
94 * Remove the thread from the list of active
95 * threads and add it to the GC list.
97 crit = _kse_critical_enter();
98 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
99 THR_LIST_REMOVE(pthread);
100 THR_GCLIST_ADD(pthread);
101 KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
102 _kse_critical_leave(crit);
104 /* Remove the reference. */
105 _thr_ref_delete(curthread, pthread);
106 if (thread_return != NULL)
107 *thread_return = tmp;
109 else if (pthread->joiner != NULL) {
110 /* Unlock the thread and remove the reference. */
111 THR_SCHED_UNLOCK(curthread, pthread);
112 _thr_ref_delete(curthread, pthread);
114 /* Multiple joiners are not supported. */
118 /* Set the running thread to be the joiner: */
119 pthread->joiner = curthread;
121 /* Keep track of which thread we're joining to: */
122 curthread->join_status.thread = pthread;
124 /* Unlock the thread and remove the reference. */
125 THR_SCHED_UNLOCK(curthread, pthread);
126 _thr_ref_delete(curthread, pthread);
128 THR_SCHED_LOCK(curthread, curthread);
129 while (curthread->join_status.thread == pthread) {
130 THR_SET_STATE(curthread, PS_JOIN);
131 THR_SCHED_UNLOCK(curthread, curthread);
132 /* Schedule the next thread: */
133 _thr_sched_switch(curthread);
134 THR_SCHED_LOCK(curthread, curthread);
136 THR_SCHED_UNLOCK(curthread, curthread);
138 if ((curthread->cancelflags & THR_CANCELLING) &&
139 !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) {
140 if (_thr_ref_add(curthread, pthread, 1) == 0) {
141 THR_SCHED_LOCK(curthread, pthread);
142 pthread->joiner = NULL;
143 THR_SCHED_UNLOCK(curthread, pthread);
144 _thr_ref_delete(curthread, pthread);
146 _pthread_exit(PTHREAD_CANCELED);
150 * The thread return value and error are set by the
151 * thread we're joining to when it exits or detaches:
153 ret = curthread->join_status.error;
154 if ((ret == 0) && (thread_return != NULL))
155 *thread_return = curthread->join_status.ret;
158 _thr_cancel_leave(curthread, 1);
160 /* Return the completion status: */