thr_join.c revision 78873
1202412Sbrueffer/*
2202412Sbrueffer * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3202412Sbrueffer * All rights reserved.
4202412Sbrueffer *
5202412Sbrueffer * Redistribution and use in source and binary forms, with or without
6202412Sbrueffer * modification, are permitted provided that the following conditions
7202412Sbrueffer * are met:
8202412Sbrueffer * 1. Redistributions of source code must retain the above copyright
9202412Sbrueffer *    notice, this list of conditions and the following disclaimer.
10202412Sbrueffer * 2. Redistributions in binary form must reproduce the above copyright
11202412Sbrueffer *    notice, this list of conditions and the following disclaimer in the
12202412Sbrueffer *    documentation and/or other materials provided with the distribution.
13202412Sbrueffer * 3. All advertising materials mentioning features or use of this software
14202412Sbrueffer *    must display the following acknowledgement:
15202412Sbrueffer *	This product includes software developed by John Birrell.
16202412Sbrueffer * 4. Neither the name of the author nor the names of any co-contributors
17202412Sbrueffer *    may be used to endorse or promote products derived from this software
18202412Sbrueffer *    without specific prior written permission.
19202412Sbrueffer *
20202412Sbrueffer * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21202412Sbrueffer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22202412Sbrueffer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23202412Sbrueffer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24202412Sbrueffer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25202412Sbrueffer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26202412Sbrueffer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27301407Slandonf * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28202412Sbrueffer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29202412Sbrueffer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30202412Sbrueffer * SUCH DAMAGE.
31202412Sbrueffer *
32202412Sbrueffer * $FreeBSD: head/lib/libkse/thread/thr_join.c 78873 2001-06-27 11:41:15Z jasone $
33202412Sbrueffer */
34202412Sbrueffer#include <errno.h>
35202412Sbrueffer#include <pthread.h>
36202412Sbrueffer#include "pthread_private.h"
37299097Sadrian
38202412Sbrueffer__weak_reference(_pthread_join, pthread_join);
39202412Sbrueffer
40202412Sbruefferint
41202412Sbrueffer_pthread_join(pthread_t pthread, void **thread_return)
42202412Sbrueffer{
43202412Sbrueffer	struct pthread	*curthread = _get_curthread();
44202412Sbrueffer	int ret = 0;
45202412Sbrueffer	pthread_t thread;
46202412Sbrueffer
47202412Sbrueffer	_thread_enter_cancellation_point();
48202412Sbrueffer
49202412Sbrueffer	/* Check if the caller has specified an invalid thread: */
50299097Sadrian	if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) {
51299097Sadrian		/* Invalid thread: */
52299097Sadrian		_thread_leave_cancellation_point();
53299097Sadrian		return(EINVAL);
54299097Sadrian	}
55202412Sbrueffer
56299097Sadrian	/* Check if the caller has specified itself: */
57301589Strasz	if (pthread == curthread) {
58301589Strasz		/* Avoid a deadlock condition: */
59202412Sbrueffer		_thread_leave_cancellation_point();
60202412Sbrueffer		return(EDEADLK);
61202412Sbrueffer	}
62202412Sbrueffer
63202412Sbrueffer	/*
64202412Sbrueffer	 * Lock the garbage collector mutex to ensure that the garbage
65202412Sbrueffer	 * collector is not using the dead thread list.
66202412Sbrueffer	 */
67202412Sbrueffer	if (pthread_mutex_lock(&_gc_mutex) != 0)
68202412Sbrueffer		PANIC("Cannot lock gc mutex");
69202412Sbrueffer
70299097Sadrian	/*
71299097Sadrian	 * Defer signals to protect the thread list from access
72202412Sbrueffer	 * by the signal handler:
73202412Sbrueffer	 */
74202412Sbrueffer	_thread_kern_sig_defer();
75202412Sbrueffer
76202412Sbrueffer	/*
77299097Sadrian	 * Unlock the garbage collector mutex, now that the garbage collector
78299097Sadrian	 * can't be run:
79299097Sadrian	 */
80299097Sadrian	if (pthread_mutex_unlock(&_gc_mutex) != 0)
81299097Sadrian		PANIC("Cannot lock gc mutex");
82202412Sbrueffer
83202412Sbrueffer	/*
84202412Sbrueffer	 * Search for the specified thread in the list of active threads.  This
85202412Sbrueffer	 * is done manually here rather than calling _find_thread() because
86299097Sadrian	 * the searches in _thread_list and _dead_list (as well as setting up
87267938Sbapt	 * join/detach state) have to be done atomically.
88202412Sbrueffer	 */
89267938Sbapt	TAILQ_FOREACH(thread, &_thread_list, tle) {
90299097Sadrian		if (thread == pthread)
91301407Slandonf			break;
92299097Sadrian	}
93301407Slandonf	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		/* Schedule the next thread: */
125		_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
126
127		/*
128		 * The thread return value and error are set by the thread we're
129		 * joining to when it exits or detaches:
130		 */
131		ret = curthread->error;
132		if ((ret == 0) && (thread_return != NULL))
133			*thread_return = curthread->ret;
134	} else {
135		/*
136		 * The thread exited (is dead) without being detached, and no
137		 * thread has joined it.
138		 */
139
140		/* Check if the return value is required: */
141		if (thread_return != NULL) {
142			/* Return the thread's return value: */
143			*thread_return = pthread->ret;
144		}
145
146		/* Make the thread collectable by the garbage collector. */
147		pthread->attr.flags |= PTHREAD_DETACHED;
148
149		/* Undefer and handle pending signals, yielding if necessary: */
150		_thread_kern_sig_undefer();
151	}
152
153	_thread_leave_cancellation_point();
154
155	/* Return the completion status: */
156	return (ret);
157}
158