thr_join.c revision 164715
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 164715 2006-11-28 11:05:31Z davidxu $ 33 */ 34#include <errno.h> 35#include <pthread.h> 36#include "thr_private.h" 37 38LT10_COMPAT_PRIVATE(_pthread_join); 39LT10_COMPAT_DEFAULT(pthread_join); 40 41__weak_reference(_pthread_join, pthread_join); 42 43int 44_pthread_join(pthread_t pthread, void **thread_return) 45{ 46 struct pthread *curthread = _get_curthread(); 47 void *tmp; 48 kse_critical_t crit; 49 int ret = 0; 50 51 _thr_cancel_enter(curthread); 52 53 /* Check if the caller has specified an invalid thread: */ 54 if (pthread == NULL || pthread->magic != THR_MAGIC) { 55 /* Invalid thread: */ 56 _thr_cancel_leave(curthread, 1); 57 return (EINVAL); 58 } 59 60 /* Check if the caller has specified itself: */ 61 if (pthread == curthread) { 62 /* Avoid a deadlock condition: */ 63 _thr_cancel_leave(curthread, 1); 64 return (EDEADLK); 65 } 66 67 /* 68 * Find the thread in the list of active threads or in the 69 * list of dead threads: 70 */ 71 if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) { 72 /* Return an error: */ 73 _thr_cancel_leave(curthread, 1); 74 return (ESRCH); 75 } 76 77 THR_SCHED_LOCK(curthread, pthread); 78 /* Check if this thread has been detached: */ 79 if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { 80 THR_SCHED_UNLOCK(curthread, pthread); 81 /* Remove the reference and return an error: */ 82 _thr_ref_delete(curthread, pthread); 83 ret = EINVAL; 84 } else { 85 /* Lock the target thread while checking its state. */ 86 if (pthread->state == PS_DEAD) { 87 /* Return the thread's return value: */ 88 tmp = pthread->ret; 89 90 /* Detach the thread. */ 91 pthread->attr.flags |= PTHREAD_DETACHED; 92 93 /* Unlock the thread. */ 94 THR_SCHED_UNLOCK(curthread, pthread); 95 96 /* 97 * Remove the thread from the list of active 98 * threads and add it to the GC list. 99 */ 100 crit = _kse_critical_enter(); 101 KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock); 102 THR_LIST_REMOVE(pthread); 103 THR_GCLIST_ADD(pthread); 104 KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock); 105 _kse_critical_leave(crit); 106 107 /* Remove the reference. */ 108 _thr_ref_delete(curthread, pthread); 109 if (thread_return != NULL) 110 *thread_return = tmp; 111 } 112 else if (pthread->joiner != NULL) { 113 /* Unlock the thread and remove the reference. */ 114 THR_SCHED_UNLOCK(curthread, pthread); 115 _thr_ref_delete(curthread, pthread); 116 117 /* Multiple joiners are not supported. */ 118 ret = ENOTSUP; 119 } 120 else { 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->join_status.thread = pthread; 126 127 /* Unlock the thread and remove the reference. */ 128 THR_SCHED_UNLOCK(curthread, pthread); 129 _thr_ref_delete(curthread, pthread); 130 131 THR_SCHED_LOCK(curthread, curthread); 132 while (curthread->join_status.thread == pthread) { 133 THR_SET_STATE(curthread, PS_JOIN); 134 THR_SCHED_UNLOCK(curthread, curthread); 135 /* Schedule the next thread: */ 136 _thr_sched_switch(curthread); 137 THR_SCHED_LOCK(curthread, curthread); 138 } 139 THR_SCHED_UNLOCK(curthread, curthread); 140 141 if ((curthread->cancelflags & THR_CANCELLING) && 142 !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) { 143 if (_thr_ref_add(curthread, pthread, 1) == 0) { 144 THR_SCHED_LOCK(curthread, pthread); 145 pthread->joiner = NULL; 146 THR_SCHED_UNLOCK(curthread, pthread); 147 _thr_ref_delete(curthread, pthread); 148 } 149 pthread_exit(PTHREAD_CANCELED); 150 } 151 152 /* 153 * The thread return value and error are set by the 154 * thread we're joining to when it exits or detaches: 155 */ 156 ret = curthread->join_status.error; 157 if ((ret == 0) && (thread_return != NULL)) 158 *thread_return = curthread->join_status.ret; 159 } 160 } 161 _thr_cancel_leave(curthread, 1); 162 163 /* Return the completion status: */ 164 return (ret); 165} 166