1 /* $OpenBSD: uthread_join.c,v 1.11 2003/12/31 21:11:45 marc Exp $ */
2 /*
3 * Copyright (c) 1995 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_join.c,v 1.9 1999/08/28 00:03:37 peter Exp $
34 */
35 #include <errno.h>
36 #ifdef _THREAD_SAFE
37 #include <pthread.h>
38 #include "pthread_private.h"
39
40 int
pthread_join(pthread_t pthread,void ** thread_return)41 pthread_join(pthread_t pthread, void **thread_return)
42 {
43 struct pthread *curthread = _get_curthread();
44 int ret = 0;
45 pthread_t thread;
46
47 _thread_enter_cancellation_point();
48
49 /* Check if the caller has specified an invalid thread: */
50 if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) {
51 /* Invalid thread: */
52 _thread_leave_cancellation_point();
53 return (EINVAL);
54 }
55
56 /* Check if the caller has specified itself: */
57 if (pthread == curthread) {
58 /* Avoid a deadlock condition: */
59 _thread_leave_cancellation_point();
60 return (EDEADLK);
61 }
62
63 /*
64 * Lock the garbage collector mutex to ensure that the garbage
65 * collector is not using the dead thread list.
66 */
67 if (pthread_mutex_lock(&_gc_mutex) != 0)
68 PANIC("Cannot lock gc mutex");
69
70 /*
71 * Defer signals to protect the thread list from access
72 * by the signal handler:
73 */
74 _thread_kern_sig_defer();
75
76 /*
77 * Unlock the garbage collector mutex, now that the garbage collector
78 * can't be run:
79 */
80 if (pthread_mutex_unlock(&_gc_mutex) != 0)
81 PANIC("Cannot unlock gc mutex");
82
83 /*
84 * Search for the specified thread in the list of active threads. This
85 * is done manually here rather than calling _find_thread() because
86 * the searches in _thread_list and _dead_list (as well as setting up
87 * join/detach state) have to be done atomically.
88 */
89 TAILQ_FOREACH(thread, &_thread_list, tle) {
90 if (thread == pthread)
91 break;
92 }
93 if (thread == NULL) {
94 /*
95 * Search for the specified thread in the list of dead threads:
96 */
97 TAILQ_FOREACH(thread, &_dead_list, dle) {
98 if (thread == pthread)
99 break;
100 }
101 }
102
103 /* Check if the thread was not found or has been detached: */
104 if (thread == NULL ||
105 ((pthread->attr.flags & PTHREAD_DETACHED) != 0))
106 /* Return an error: */
107 ret = ESRCH;
108
109 else if (pthread->joiner != NULL)
110 /* Multiple joiners are not supported. */
111 ret = ENOTSUP;
112
113 /* Check if the thread is not dead: */
114 else if (pthread->state != PS_DEAD) {
115 /* Set the running thread to be the joiner: */
116 pthread->joiner = curthread;
117
118 /* Keep track of which thread we're joining to: */
119 curthread->join_status.thread = pthread;
120
121 while (curthread->join_status.thread == pthread) {
122 /* Schedule the next thread: */
123 _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
124 }
125
126 /*
127 * The thread return value and error are set by the thread we're
128 * joining to when it exits or detaches:
129 */
130 ret = curthread->join_status.error;
131 if ((ret == 0) && (thread_return != NULL))
132 *thread_return = curthread->join_status.ret;
133 } else {
134 /*
135 * The thread exited (is dead) without being detached, and no
136 * thread has joined it.
137 */
138
139 /* Check if the return value is required: */
140 if (thread_return != NULL) {
141 /* Return the thread's return value: */
142 *thread_return = pthread->ret;
143 }
144
145 /* Make the thread collectable by the garbage collector. */
146 pthread->attr.flags |= PTHREAD_DETACHED;
147
148 }
149 /* Undefer and handle pending signals, yielding if necessary: */
150 _thread_kern_sig_undefer();
151
152 _thread_leave_cancellation_point();
153
154 /* Return the completion status: */
155 return (ret);
156 }
157 #endif
158