thr_join.c revision 127569
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/libthr/thread/thr_join.c 127569 2004-03-29 13:53:43Z mtm $
33 */
34#include <errno.h>
35#include <pthread.h>
36#include <stdlib.h>
37#include "thr_private.h"
38
39__weak_reference(_pthread_join, pthread_join);
40
41int
42_pthread_join(pthread_t pthread, void **thread_return)
43{
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->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	 * Search for the specified thread in the list of active threads.  This
65	 * is done manually here rather than calling _find_thread() because
66	 * the searches in _thread_list and _dead_list (as well as setting up
67	 * join/detach state) have to be done atomically.
68	 */
69	DEAD_LIST_LOCK;
70	THREAD_LIST_LOCK;
71	TAILQ_FOREACH(thread, &_thread_list, tle)
72		if (thread == pthread) {
73			UMTX_LOCK(&pthread->lock);
74			break;
75		}
76
77	if (thread == NULL)
78		/*
79		 * Search for the specified thread in the list of dead threads:
80		 */
81		TAILQ_FOREACH(thread, &_dead_list, dle)
82			if (thread == pthread) {
83				UMTX_LOCK(&pthread->lock);
84				break;
85			}
86
87	/* Check if the thread was not found or has been detached: */
88	if (thread == NULL) {
89		THREAD_LIST_UNLOCK;
90		DEAD_LIST_UNLOCK;
91		ret = ESRCH;
92		goto out;
93	}
94	if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) {
95		UMTX_UNLOCK(&pthread->lock);
96		THREAD_LIST_UNLOCK;
97		DEAD_LIST_UNLOCK;
98		ret = EINVAL;
99		goto out;
100	}
101
102	if (pthread->joiner != NULL) {
103		/* Multiple joiners are not supported. */
104		/* XXXTHR - support multiple joiners. */
105		UMTX_UNLOCK(&pthread->lock);
106		THREAD_LIST_UNLOCK;
107		DEAD_LIST_UNLOCK;
108		ret = ENOTSUP;
109		goto out;
110
111	}
112
113	/* Check if the thread is not dead: */
114	if (pthread->state != PS_DEAD) {
115		/* Set the running thread to be the joiner: */
116		pthread->joiner = curthread;
117		UMTX_UNLOCK(&pthread->lock);
118		_thread_critical_enter(curthread);
119
120		/* Keep track of which thread we're joining to: */
121		curthread->join_status.thread = pthread;
122
123		while (curthread->join_status.thread == pthread) {
124			PTHREAD_SET_STATE(curthread, PS_JOIN);
125			/* Wait for our signal to wake up. */
126			_thread_critical_exit(curthread);
127			THREAD_LIST_UNLOCK;
128			DEAD_LIST_UNLOCK;
129			ret = _thread_suspend(curthread, NULL);
130			if (ret != 0 && ret != EAGAIN && ret != EINTR)
131				PANIC("Unable to suspend in join.");
132
133			/*
134			 * XXX - For correctness reasons.
135			 * We must aquire these in the same order and also
136			 * importantly, release in the same order, order because
137			 * otherwise we might deadlock with the joined thread
138			 * when we attempt to release one of these locks.
139			 */
140			DEAD_LIST_LOCK;
141			THREAD_LIST_LOCK;
142			_thread_critical_enter(curthread);
143		}
144
145		/*
146		 * The thread return value and error are set by the thread we're
147		 * joining to when it exits or detaches:
148		 */
149		ret = curthread->join_status.error;
150		if ((ret == 0) && (thread_return != NULL))
151			*thread_return = curthread->join_status.ret;
152		_thread_critical_exit(curthread);
153		THREAD_LIST_UNLOCK;
154		DEAD_LIST_UNLOCK;
155	} else {
156		/*
157		 * The thread exited (is dead) without being detached, and no
158		 * thread has joined it.
159		 */
160
161		/* Check if the return value is required: */
162		if (thread_return != NULL) {
163			/* Return the thread's return value: */
164			*thread_return = pthread->ret;
165		}
166
167		/* Free all remaining memory allocated to the thread. */
168		pthread->attr.flags |= PTHREAD_DETACHED;
169		UMTX_UNLOCK(&pthread->lock);
170		TAILQ_REMOVE(&_dead_list, pthread, dle);
171		deadlist_free_onethread(pthread);
172		THREAD_LIST_UNLOCK;
173		DEAD_LIST_UNLOCK;
174	}
175
176out:
177	_thread_leave_cancellation_point();
178
179	/* Return the completion status: */
180	return (ret);
181}
182