1112918Sjeff/* 2153496Sdavidxu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3112918Sjeff * All rights reserved. 4112918Sjeff * 5112918Sjeff * Redistribution and use in source and binary forms, with or without 6112918Sjeff * modification, are permitted provided that the following conditions 7112918Sjeff * are met: 8112918Sjeff * 1. Redistributions of source code must retain the above copyright 9153496Sdavidxu * notice unmodified, this list of conditions, and the following 10153496Sdavidxu * disclaimer. 11112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright 12112918Sjeff * notice, this list of conditions and the following disclaimer in the 13112918Sjeff * documentation and/or other materials provided with the distribution. 14112918Sjeff * 15153496Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16153496Sdavidxu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17153496Sdavidxu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18153496Sdavidxu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19153496Sdavidxu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20153496Sdavidxu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21153496Sdavidxu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22153496Sdavidxu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23153496Sdavidxu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24153496Sdavidxu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25112918Sjeff * 26112918Sjeff * $FreeBSD$ 27153496Sdavidxu * 28112918Sjeff */ 29144518Sdavidxu 30157457Sdavidxu#include "namespace.h" 31112918Sjeff#include <errno.h> 32112918Sjeff#include <pthread.h> 33157457Sdavidxu#include "un-namespace.h" 34144518Sdavidxu 35112918Sjeff#include "thr_private.h" 36112918Sjeff 37157457Sdavidxuint _pthread_timedjoin_np(pthread_t pthread, void **thread_return, 38157457Sdavidxu const struct timespec *abstime); 39150901Sdavidxustatic int join_common(pthread_t, void **, const struct timespec *); 40150901Sdavidxu 41112918Sjeff__weak_reference(_pthread_join, pthread_join); 42150901Sdavidxu__weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np); 43112918Sjeff 44144518Sdavidxustatic void backout_join(void *arg) 45144518Sdavidxu{ 46212536Sdavidxu struct pthread *pthread = (struct pthread *)arg; 47144518Sdavidxu struct pthread *curthread = _get_curthread(); 48144518Sdavidxu 49212536Sdavidxu THR_THREAD_LOCK(curthread, pthread); 50144518Sdavidxu pthread->joiner = NULL; 51212840Sdavidxu THR_THREAD_UNLOCK(curthread, pthread); 52144518Sdavidxu} 53144518Sdavidxu 54112918Sjeffint 55112918Sjeff_pthread_join(pthread_t pthread, void **thread_return) 56112918Sjeff{ 57150901Sdavidxu return (join_common(pthread, thread_return, NULL)); 58150901Sdavidxu} 59150901Sdavidxu 60150901Sdavidxuint 61150901Sdavidxu_pthread_timedjoin_np(pthread_t pthread, void **thread_return, 62150901Sdavidxu const struct timespec *abstime) 63150901Sdavidxu{ 64150901Sdavidxu if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 65150901Sdavidxu abstime->tv_nsec >= 1000000000) 66150901Sdavidxu return (EINVAL); 67150901Sdavidxu 68150901Sdavidxu return (join_common(pthread, thread_return, abstime)); 69150901Sdavidxu} 70150901Sdavidxu 71211524Sdavidxu/* 72211524Sdavidxu * Cancellation behavior: 73211524Sdavidxu * if the thread is canceled, joinee is not recycled. 74211524Sdavidxu */ 75150901Sdavidxustatic int 76150901Sdavidxujoin_common(pthread_t pthread, void **thread_return, 77150901Sdavidxu const struct timespec *abstime) 78150901Sdavidxu{ 79144518Sdavidxu struct pthread *curthread = _get_curthread(); 80150901Sdavidxu struct timespec ts, ts2, *tsp; 81144518Sdavidxu void *tmp; 82151694Sdavidxu long tid; 83144518Sdavidxu int ret = 0; 84151694Sdavidxu 85144518Sdavidxu if (pthread == NULL) 86144518Sdavidxu return (EINVAL); 87112918Sjeff 88129484Smtm if (pthread == curthread) 89144518Sdavidxu return (EDEADLK); 90112918Sjeff 91212536Sdavidxu if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) 92212536Sdavidxu return (ESRCH); 93212536Sdavidxu 94212536Sdavidxu if ((pthread->flags & THR_FLAGS_DETACHED) != 0) { 95164715Sdavidxu ret = EINVAL; 96144518Sdavidxu } else if (pthread->joiner != NULL) { 97112918Sjeff /* Multiple joiners are not supported. */ 98112918Sjeff ret = ENOTSUP; 99112918Sjeff } 100144518Sdavidxu if (ret) { 101212536Sdavidxu THR_THREAD_UNLOCK(curthread, pthread); 102144518Sdavidxu return (ret); 103144518Sdavidxu } 104144518Sdavidxu /* Set the running thread to be the joiner: */ 105144518Sdavidxu pthread->joiner = curthread; 106112918Sjeff 107212536Sdavidxu THR_THREAD_UNLOCK(curthread, pthread); 108112918Sjeff 109144518Sdavidxu THR_CLEANUP_PUSH(curthread, backout_join, pthread); 110212076Sdavidxu _thr_cancel_enter(curthread); 111112918Sjeff 112151694Sdavidxu tid = pthread->tid; 113151694Sdavidxu while (pthread->tid != TID_TERMINATED) { 114211524Sdavidxu _thr_testcancel(curthread); 115150901Sdavidxu if (abstime != NULL) { 116150901Sdavidxu clock_gettime(CLOCK_REALTIME, &ts); 117150901Sdavidxu TIMESPEC_SUB(&ts2, abstime, &ts); 118150901Sdavidxu if (ts2.tv_sec < 0) { 119150901Sdavidxu ret = ETIMEDOUT; 120150901Sdavidxu break; 121150901Sdavidxu } 122150901Sdavidxu tsp = &ts2; 123150901Sdavidxu } else 124150901Sdavidxu tsp = NULL; 125151694Sdavidxu ret = _thr_umtx_wait(&pthread->tid, tid, tsp); 126150901Sdavidxu if (ret == ETIMEDOUT) 127150901Sdavidxu break; 128144518Sdavidxu } 129129484Smtm 130212076Sdavidxu _thr_cancel_leave(curthread, 0); 131144518Sdavidxu THR_CLEANUP_POP(curthread, 0); 132115314Smtm 133150901Sdavidxu if (ret == ETIMEDOUT) { 134212536Sdavidxu THR_THREAD_LOCK(curthread, pthread); 135150901Sdavidxu pthread->joiner = NULL; 136212536Sdavidxu THR_THREAD_UNLOCK(curthread, pthread); 137150901Sdavidxu } else { 138153526Sdavidxu ret = 0; 139150901Sdavidxu tmp = pthread->ret; 140212536Sdavidxu THR_THREAD_LOCK(curthread, pthread); 141212536Sdavidxu pthread->flags |= THR_FLAGS_DETACHED; 142150901Sdavidxu pthread->joiner = NULL; 143212536Sdavidxu _thr_try_gc(curthread, pthread); /* thread lock released */ 144112918Sjeff 145150901Sdavidxu if (thread_return != NULL) 146150901Sdavidxu *thread_return = tmp; 147150901Sdavidxu } 148112918Sjeff return (ret); 149112918Sjeff} 150