113546Sjulian/* 213546Sjulian * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 313546Sjulian * All rights reserved. 413546Sjulian * 513546Sjulian * Redistribution and use in source and binary forms, with or without 613546Sjulian * modification, are permitted provided that the following conditions 713546Sjulian * are met: 813546Sjulian * 1. Redistributions of source code must retain the above copyright 913546Sjulian * notice, this list of conditions and the following disclaimer. 1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1113546Sjulian * notice, this list of conditions and the following disclaimer in the 1213546Sjulian * documentation and/or other materials provided with the distribution. 13165967Simp * 3. Neither the name of the author nor the names of any co-contributors 1413546Sjulian * may be used to endorse or promote products derived from this software 1513546Sjulian * without specific prior written permission. 1613546Sjulian * 1713546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 1813546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1913546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2049439Sdeischen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2113546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2213546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2313546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2413546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2513546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2613546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2713546Sjulian * SUCH DAMAGE. 2813546Sjulian * 2950476Speter * $FreeBSD$ 3013546Sjulian */ 31174112Sdeischen 32174112Sdeischen#include "namespace.h" 3313546Sjulian#include <errno.h> 3413546Sjulian#include <pthread.h> 35174112Sdeischen#include "un-namespace.h" 36103388Smini#include "thr_private.h" 3713546Sjulian 3875369Sdeischen__weak_reference(_pthread_join, pthread_join); 3971581Sdeischen 4013546Sjulianint 4171581Sdeischen_pthread_join(pthread_t pthread, void **thread_return) 4213546Sjulian{ 43113661Sdeischen struct pthread *curthread = _get_curthread(); 44117300Sdavidxu void *tmp; 45113661Sdeischen kse_critical_t crit; 46113661Sdeischen int ret = 0; 4753812Salfred 48123312Sdavidxu _thr_cancel_enter(curthread); 4913546Sjulian 5035008Sjb /* Check if the caller has specified an invalid thread: */ 51113658Sdeischen if (pthread == NULL || pthread->magic != THR_MAGIC) { 5235008Sjb /* Invalid thread: */ 53123312Sdavidxu _thr_cancel_leave(curthread, 1); 54113658Sdeischen return (EINVAL); 5553812Salfred } 5635008Sjb 5735008Sjb /* Check if the caller has specified itself: */ 5871581Sdeischen if (pthread == curthread) { 5935008Sjb /* Avoid a deadlock condition: */ 60123312Sdavidxu _thr_cancel_leave(curthread, 1); 61113658Sdeischen return (EDEADLK); 6253812Salfred } 6335008Sjb 6435509Sjb /* 65113658Sdeischen * Find the thread in the list of active threads or in the 66113658Sdeischen * list of dead threads: 6735509Sjb */ 68113658Sdeischen if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/1)) != 0) { 69113658Sdeischen /* Return an error: */ 70123312Sdavidxu _thr_cancel_leave(curthread, 1); 71113658Sdeischen return (ESRCH); 7278873Sjasone } 7378873Sjasone 74114187Sdeischen THR_SCHED_LOCK(curthread, pthread); 75113658Sdeischen /* Check if this thread has been detached: */ 76113658Sdeischen if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { 77114187Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 78113658Sdeischen /* Remove the reference and return an error: */ 79113658Sdeischen _thr_ref_delete(curthread, pthread); 80164715Sdavidxu ret = EINVAL; 81113658Sdeischen } else { 82113658Sdeischen /* Lock the target thread while checking its state. */ 83114187Sdeischen if (pthread->state == PS_DEAD) { 84117300Sdavidxu /* Return the thread's return value: */ 85117300Sdavidxu tmp = pthread->ret; 8635509Sjb 87113661Sdeischen /* Detach the thread. */ 88113661Sdeischen pthread->attr.flags |= PTHREAD_DETACHED; 89113661Sdeischen 90113661Sdeischen /* Unlock the thread. */ 91113658Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 92113661Sdeischen 93113661Sdeischen /* 94113661Sdeischen * Remove the thread from the list of active 95113661Sdeischen * threads and add it to the GC list. 96113661Sdeischen */ 97113661Sdeischen crit = _kse_critical_enter(); 98113661Sdeischen KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock); 99113661Sdeischen THR_LIST_REMOVE(pthread); 100113661Sdeischen THR_GCLIST_ADD(pthread); 101113661Sdeischen KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock); 102113661Sdeischen _kse_critical_leave(crit); 103113661Sdeischen 104113661Sdeischen /* Remove the reference. */ 105113658Sdeischen _thr_ref_delete(curthread, pthread); 106117300Sdavidxu if (thread_return != NULL) 107117300Sdavidxu *thread_return = tmp; 108113658Sdeischen } 109113658Sdeischen else if (pthread->joiner != NULL) { 110113658Sdeischen /* Unlock the thread and remove the reference. */ 111113658Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 112113658Sdeischen _thr_ref_delete(curthread, pthread); 11378873Sjasone 114113658Sdeischen /* Multiple joiners are not supported. */ 115113658Sdeischen ret = ENOTSUP; 116113658Sdeischen } 117113658Sdeischen else { 118113658Sdeischen /* Set the running thread to be the joiner: */ 119113658Sdeischen pthread->joiner = curthread; 12076909Sjasone 121113658Sdeischen /* Keep track of which thread we're joining to: */ 122113658Sdeischen curthread->join_status.thread = pthread; 12367097Sdeischen 124113658Sdeischen /* Unlock the thread and remove the reference. */ 125113658Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 126113658Sdeischen _thr_ref_delete(curthread, pthread); 12781750Sjasone 128115080Sdeischen THR_SCHED_LOCK(curthread, curthread); 129114187Sdeischen while (curthread->join_status.thread == pthread) { 130113658Sdeischen THR_SET_STATE(curthread, PS_JOIN); 131115080Sdeischen THR_SCHED_UNLOCK(curthread, curthread); 132113658Sdeischen /* Schedule the next thread: */ 133113658Sdeischen _thr_sched_switch(curthread); 134115080Sdeischen THR_SCHED_LOCK(curthread, curthread); 135113658Sdeischen } 136115080Sdeischen THR_SCHED_UNLOCK(curthread, curthread); 13753812Salfred 138115278Sdeischen if ((curthread->cancelflags & THR_CANCELLING) && 139115278Sdeischen !(curthread->cancelflags & PTHREAD_CANCEL_DISABLE)) { 140115278Sdeischen if (_thr_ref_add(curthread, pthread, 1) == 0) { 141115278Sdeischen THR_SCHED_LOCK(curthread, pthread); 142115278Sdeischen pthread->joiner = NULL; 143115278Sdeischen THR_SCHED_UNLOCK(curthread, pthread); 144115278Sdeischen _thr_ref_delete(curthread, pthread); 145115278Sdeischen } 146174112Sdeischen _pthread_exit(PTHREAD_CANCELED); 147115278Sdeischen } 148115278Sdeischen 149113658Sdeischen /* 150113658Sdeischen * The thread return value and error are set by the 151113658Sdeischen * thread we're joining to when it exits or detaches: 152113658Sdeischen */ 153113658Sdeischen ret = curthread->join_status.error; 154113658Sdeischen if ((ret == 0) && (thread_return != NULL)) 155113658Sdeischen *thread_return = curthread->join_status.ret; 15676909Sjasone } 15776909Sjasone } 158123312Sdavidxu _thr_cancel_leave(curthread, 1); 15913546Sjulian 16013546Sjulian /* Return the completion status: */ 16135509Sjb return (ret); 16213546Sjulian} 163