thr_join.c revision 71581
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 71581 2001-01-24 13:03:38Z deischen $ 33 */ 34#include <errno.h> 35#include <pthread.h> 36#include "pthread_private.h" 37 38#pragma weak 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 /* Check if the thread is not dead: */ 76 else if (pthread->state != PS_DEAD) { 77 PTHREAD_ASSERT_NOT_IN_SYNCQ(curthread); 78 79 /* 80 * Enter a loop in case this thread is woken prematurely 81 * in order to invoke a signal handler: 82 */ 83 for (;;) { 84 /* Clear the interrupted flag: */ 85 curthread->interrupted = 0; 86 87 /* 88 * Protect against being context switched out while 89 * adding this thread to the join queue. 90 */ 91 _thread_kern_sig_defer(); 92 93 /* Add the running thread to the join queue: */ 94 TAILQ_INSERT_TAIL(&(pthread->join_queue), 95 curthread, sqe); 96 curthread->flags |= PTHREAD_FLAGS_IN_JOINQ; 97 curthread->data.thread = pthread; 98 99 /* Schedule the next thread: */ 100 _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__); 101 102 if ((curthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) { 103 TAILQ_REMOVE(&(pthread->join_queue), 104 curthread, sqe); 105 curthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ; 106 } 107 curthread->data.thread = NULL; 108 109 _thread_kern_sig_undefer(); 110 111 if (curthread->interrupted != 0) { 112 if (curthread->continuation != NULL) 113 curthread->continuation(curthread); 114 /* 115 * This thread was interrupted, probably to 116 * invoke a signal handler. Make sure the 117 * target thread is still joinable. 118 */ 119 if (((_find_thread(pthread) != 0) && 120 (_find_dead_thread(pthread) != 0)) || 121 ((pthread->attr.flags & 122 PTHREAD_DETACHED) != 0)) { 123 /* Return an error: */ 124 ret = ESRCH; 125 126 /* We're done; break out of the loop. */ 127 break; 128 } 129 else if (pthread->state == PS_DEAD) { 130 /* We're done; break out of the loop. */ 131 break; 132 } 133 } else { 134 /* 135 * The thread return value and error are set 136 * by the thread we're joining to when it 137 * exits or detaches: 138 */ 139 ret = curthread->error; 140 if ((ret == 0) && (thread_return != NULL)) 141 *thread_return = curthread->ret; 142 143 /* We're done; break out of the loop. */ 144 break; 145 } 146 } 147 /* Check if the return value is required: */ 148 } else if (thread_return != NULL) 149 /* Return the thread's return value: */ 150 *thread_return = pthread->ret; 151 152 _thread_leave_cancellation_point(); 153 154 /* Return the completion status: */ 155 return (ret); 156} 157 158void 159_join_backout(pthread_t pthread) 160{ 161 struct pthread *curthread = _get_curthread(); 162 163 _thread_kern_sig_defer(); 164 if ((pthread->flags & PTHREAD_FLAGS_IN_JOINQ) != 0) { 165 TAILQ_REMOVE(&pthread->data.thread->join_queue, pthread, sqe); 166 curthread->flags &= ~PTHREAD_FLAGS_IN_JOINQ; 167 } 168 _thread_kern_sig_undefer(); 169} 170