thr_join.c revision 81750
1/*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/lib/libkse/thread/thr_join.c 81750 2001-08-16 06:31:32Z jasone $
33 */
34#include <errno.h>
35#include <pthread.h>
36#include "pthread_private.h"
37
38__weak_reference(_pthread_join, pthread_join);
39
40int
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 lock 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		/* Undefer and handle pending signals, yielding if necessary: */
107		_thread_kern_sig_undefer();
108
109		/* Return an error: */
110		ret = ESRCH;
111
112	} else if (pthread->joiner != NULL) {
113		/* Undefer and handle pending signals, yielding if necessary: */
114		_thread_kern_sig_undefer();
115
116		/* Multiple joiners are not supported. */
117		ret = ENOTSUP;
118
119	/* Check if the thread is not dead: */
120	} else if (pthread->state != PS_DEAD) {
121		/* Set the running thread to be the joiner: */
122		pthread->joiner = curthread;
123
124		/* Keep track of which thread we're joining to: */
125		curthread->data.thread = pthread;
126
127		/* Schedule the next thread: */
128		_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
129
130		/*
131		 * The thread return value and error are set by the thread we're
132		 * joining to when it exits or detaches:
133		 */
134		ret = curthread->error;
135		if ((ret == 0) && (thread_return != NULL))
136			*thread_return = curthread->ret;
137	} else {
138		/*
139		 * The thread exited (is dead) without being detached, and no
140		 * thread has joined it.
141		 */
142
143		/* Check if the return value is required: */
144		if (thread_return != NULL) {
145			/* Return the thread's return value: */
146			*thread_return = pthread->ret;
147		}
148
149		/* Make the thread collectable by the garbage collector. */
150		pthread->attr.flags |= PTHREAD_DETACHED;
151
152		/* Undefer and handle pending signals, yielding if necessary: */
153		_thread_kern_sig_undefer();
154	}
155
156	_thread_leave_cancellation_point();
157
158	/* Return the completion status: */
159	return (ret);
160}
161