thr_join.c revision 76909
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 76909 2001-05-20 23:08:33Z 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
46	_thread_enter_cancellation_point();
47
48	/* Check if the caller has specified an invalid thread: */
49	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) {
50		/* Invalid thread: */
51		_thread_leave_cancellation_point();
52		return(EINVAL);
53	}
54
55	/* Check if the caller has specified itself: */
56	if (pthread == curthread) {
57		/* Avoid a deadlock condition: */
58		_thread_leave_cancellation_point();
59		return(EDEADLK);
60	}
61
62	/*
63	 * Find the thread in the list of active threads or in the
64	 * list of dead threads:
65	 */
66	if ((_find_thread(pthread) != 0) && (_find_dead_thread(pthread) != 0))
67		/* Return an error: */
68		ret = ESRCH;
69
70	/* Check if this thread has been detached: */
71	else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0)
72		/* Return an error: */
73		ret = ESRCH;
74
75	else if (pthread->joiner != NULL)
76		/* Multiple joiners are not supported. */
77		ret = ENOTSUP;
78
79	/* Check if the thread is not dead: */
80	else if (pthread->state != PS_DEAD) {
81		/* Set the running thread to be the joiner: */
82		pthread->joiner = curthread;
83
84		/* Schedule the next thread: */
85		_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
86
87		/*
88		 * The thread return value and error are set by the thread we're
89		 * joining to when it exits or detaches:
90		 */
91		ret = curthread->error;
92		if ((ret == 0) && (thread_return != NULL))
93			*thread_return = curthread->ret;
94	} else {
95		/*
96		 * The thread exited (is dead) without being detached, and no
97		 * thread has joined it.
98		 */
99
100		/* Check if the return value is required: */
101		if (thread_return != NULL) {
102			/* Return the thread's return value: */
103			*thread_return = pthread->ret;
104		}
105
106		/*
107		 * Make the thread collectable by the garbage collector.  There
108		 * is a race here with the garbage collector if multiple threads
109		 * try to join the thread, but the behavior of multiple joiners
110		 * is undefined, so don't bother protecting against the race.
111		 */
112		pthread->attr.flags |= PTHREAD_DETACHED;
113	}
114
115	_thread_leave_cancellation_point();
116
117	/* Return the completion status: */
118	return (ret);
119}
120