thr_join.c revision 75369
133965Sjdp/* 2104834Sobrien * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 377298Sobrien * All rights reserved. 433965Sjdp * 533965Sjdp * Redistribution and use in source and binary forms, with or without 633965Sjdp * modification, are permitted provided that the following conditions 733965Sjdp * are met: 833965Sjdp * 1. Redistributions of source code must retain the above copyright 933965Sjdp * notice, this list of conditions and the following disclaimer. 1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1133965Sjdp * notice, this list of conditions and the following disclaimer in the 1233965Sjdp * documentation and/or other materials provided with the distribution. 1333965Sjdp * 3. All advertising materials mentioning features or use of this software 1433965Sjdp * must display the following acknowledgement: 1533965Sjdp * This product includes software developed by John Birrell. 1633965Sjdp * 4. Neither the name of the author nor the names of any co-contributors 1733965Sjdp * may be used to endorse or promote products derived from this software 1833965Sjdp * without specific prior written permission. 1933965Sjdp * 2033965Sjdp * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 2133965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22104834Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2333965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2433965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2533965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2677298Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2733965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2833965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2933965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3033965Sjdp * SUCH DAMAGE. 3177298Sobrien * 3233965Sjdp * $FreeBSD: head/lib/libkse/thread/thr_join.c 75369 2001-04-10 04:19:21Z deischen $ 3333965Sjdp */ 3433965Sjdp#include <errno.h> 3533965Sjdp#include <pthread.h> 3677298Sobrien#include "pthread_private.h" 3733965Sjdp 3833965Sjdp__weak_reference(_pthread_join, pthread_join); 3933965Sjdp 4033965Sjdpint 4177298Sobrien_pthread_join(pthread_t pthread, void **thread_return) 4233965Sjdp{ 4333965Sjdp struct pthread *curthread = _get_curthread(); 4433965Sjdp int ret = 0; 4533965Sjdp 4633965Sjdp _thread_enter_cancellation_point(); 4733965Sjdp 4833965Sjdp /* Check if the caller has specified an invalid thread: */ 4933965Sjdp if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { 5033965Sjdp /* Invalid thread: */ 5133965Sjdp _thread_leave_cancellation_point(); 5233965Sjdp return(EINVAL); 5333965Sjdp } 5433965Sjdp 5533965Sjdp /* Check if the caller has specified itself: */ 5633965Sjdp if (pthread == curthread) { 5777298Sobrien /* Avoid a deadlock condition: */ 5833965Sjdp _thread_leave_cancellation_point(); 5977298Sobrien return(EDEADLK); 6033965Sjdp } 6133965Sjdp 6277298Sobrien /* 6333965Sjdp * Find the thread in the list of active threads or in the 6433965Sjdp * list of dead threads: 6533965Sjdp */ 6633965Sjdp if ((_find_thread(pthread) != 0) && (_find_dead_thread(pthread) != 0)) 6777298Sobrien /* Return an error: */ 6833965Sjdp ret = ESRCH; 6933965Sjdp 7033965Sjdp /* Check if this thread has been detached: */ 7177298Sobrien else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) 7233965Sjdp /* Return an error: */ 7377298Sobrien ret = ESRCH; 7433965Sjdp 7533965Sjdp /* Check if the thread is not dead: */ 7633965Sjdp else if (pthread->state != PS_DEAD) { 7733965Sjdp PTHREAD_ASSERT_NOT_IN_SYNCQ(curthread); 7833965Sjdp 7977298Sobrien /* 8077298Sobrien * Enter a loop in case this thread is woken prematurely 8177298Sobrien * in order to invoke a signal handler: 8277298Sobrien */ 8377298Sobrien for (;;) { 8433965Sjdp /* Clear the interrupted flag: */ 8533965Sjdp curthread->interrupted = 0; 8633965Sjdp 8733965Sjdp /* 8833965Sjdp * Protect against being context switched out while 8977298Sobrien * adding this thread to the join queue. 9077298Sobrien */ 9133965Sjdp _thread_kern_sig_defer(); 9277298Sobrien 9377298Sobrien /* Add the running thread to the join queue: */ 9433965Sjdp TAILQ_INSERT_TAIL(&(pthread->join_queue), 9577298Sobrien curthread, sqe); 9677298Sobrien curthread->flags |= PTHREAD_FLAGS_IN_JOINQ; 9733965Sjdp curthread->data.thread = pthread; 9877298Sobrien 9933965Sjdp /* Schedule the next thread: */ 10033965Sjdp _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__); 10133965Sjdp 10233965Sjdp if ((curthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) { 10333965Sjdp TAILQ_REMOVE(&(pthread->join_queue), 10433965Sjdp curthread, sqe); 10533965Sjdp curthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ; 10633965Sjdp } 10733965Sjdp curthread->data.thread = NULL; 10833965Sjdp 10933965Sjdp _thread_kern_sig_undefer(); 11033965Sjdp 11177298Sobrien if (curthread->interrupted != 0) { 11277298Sobrien if (curthread->continuation != NULL) 11333965Sjdp curthread->continuation(curthread); 11433965Sjdp /* 11533965Sjdp * This thread was interrupted, probably to 11633965Sjdp * invoke a signal handler. Make sure the 11733965Sjdp * target thread is still joinable. 11833965Sjdp */ 11933965Sjdp if (((_find_thread(pthread) != 0) && 12033965Sjdp (_find_dead_thread(pthread) != 0)) || 12133965Sjdp ((pthread->attr.flags & 12233965Sjdp PTHREAD_DETACHED) != 0)) { 12333965Sjdp /* Return an error: */ 12433965Sjdp ret = ESRCH; 12533965Sjdp 12633965Sjdp /* We're done; break out of the loop. */ 12733965Sjdp break; 12833965Sjdp } 12933965Sjdp else if (pthread->state == PS_DEAD) { 13077298Sobrien /* We're done; break out of the loop. */ 13177298Sobrien break; 13233965Sjdp } 13333965Sjdp } else { 13433965Sjdp /* 13533965Sjdp * The thread return value and error are set 13633965Sjdp * by the thread we're joining to when it 13733965Sjdp * exits or detaches: 13833965Sjdp */ 13933965Sjdp ret = curthread->error; 14033965Sjdp if ((ret == 0) && (thread_return != NULL)) 14133965Sjdp *thread_return = curthread->ret; 14233965Sjdp 14333965Sjdp /* We're done; break out of the loop. */ 14433965Sjdp break; 14533965Sjdp } 14633965Sjdp } 14733965Sjdp /* Check if the return value is required: */ 14833965Sjdp } else if (thread_return != NULL) 14933965Sjdp /* Return the thread's return value: */ 15033965Sjdp *thread_return = pthread->ret; 15133965Sjdp 15233965Sjdp _thread_leave_cancellation_point(); 15333965Sjdp 15433965Sjdp /* Return the completion status: */ 15533965Sjdp return (ret); 15633965Sjdp} 15733965Sjdp 15833965Sjdpvoid 15933965Sjdp_join_backout(pthread_t pthread) 16033965Sjdp{ 16133965Sjdp struct pthread *curthread = _get_curthread(); 16233965Sjdp 16377298Sobrien _thread_kern_sig_defer(); 16477298Sobrien if ((pthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) { 16533965Sjdp TAILQ_REMOVE(&pthread->data.thread->join_queue, pthread, sqe); 16633965Sjdp curthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ; 16733965Sjdp } 16833965Sjdp _thread_kern_sig_undefer(); 16933965Sjdp} 17033965Sjdp