1bb535300SJeff Roberson /* 2df2cf821SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3bb535300SJeff Roberson * All rights reserved. 4bb535300SJeff Roberson * 5bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 6bb535300SJeff Roberson * modification, are permitted provided that the following conditions 7bb535300SJeff Roberson * are met: 8bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 9df2cf821SDavid Xu * notice unmodified, this list of conditions, and the following 10df2cf821SDavid Xu * disclaimer. 11bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 12bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 13bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 14bb535300SJeff Roberson * 15df2cf821SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16df2cf821SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17df2cf821SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18df2cf821SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19df2cf821SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20df2cf821SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21df2cf821SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22df2cf821SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23df2cf821SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24df2cf821SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bb535300SJeff Roberson * 26bb535300SJeff Roberson * $FreeBSD$ 27df2cf821SDavid Xu * 28bb535300SJeff Roberson */ 29a091d823SDavid Xu 3037a6356bSDavid Xu #include "namespace.h" 31bb535300SJeff Roberson #include <errno.h> 32bb535300SJeff Roberson #include <pthread.h> 3337a6356bSDavid Xu #include "un-namespace.h" 34a091d823SDavid Xu 35bb535300SJeff Roberson #include "thr_private.h" 36bb535300SJeff Roberson 3737a6356bSDavid Xu int _pthread_timedjoin_np(pthread_t pthread, void **thread_return, 3837a6356bSDavid Xu const struct timespec *abstime); 399e49a237SDavid Xu static int join_common(pthread_t, void **, const struct timespec *); 409e49a237SDavid Xu 41bb535300SJeff Roberson __weak_reference(_pthread_join, pthread_join); 429e49a237SDavid Xu __weak_reference(_pthread_timedjoin_np, pthread_timedjoin_np); 43bb535300SJeff Roberson 44a091d823SDavid Xu static void backout_join(void *arg) 45a091d823SDavid Xu { 46a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 47a091d823SDavid Xu struct pthread *pthread = (struct pthread *)arg; 48a091d823SDavid Xu 49a091d823SDavid Xu THREAD_LIST_LOCK(curthread); 50a091d823SDavid Xu pthread->joiner = NULL; 51a091d823SDavid Xu THREAD_LIST_UNLOCK(curthread); 52a091d823SDavid Xu } 53a091d823SDavid Xu 54bb535300SJeff Roberson int 55bb535300SJeff Roberson _pthread_join(pthread_t pthread, void **thread_return) 56bb535300SJeff Roberson { 579e49a237SDavid Xu return (join_common(pthread, thread_return, NULL)); 589e49a237SDavid Xu } 599e49a237SDavid Xu 609e49a237SDavid Xu int 619e49a237SDavid Xu _pthread_timedjoin_np(pthread_t pthread, void **thread_return, 629e49a237SDavid Xu const struct timespec *abstime) 639e49a237SDavid Xu { 649e49a237SDavid Xu if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 659e49a237SDavid Xu abstime->tv_nsec >= 1000000000) 669e49a237SDavid Xu return (EINVAL); 679e49a237SDavid Xu 689e49a237SDavid Xu return (join_common(pthread, thread_return, abstime)); 699e49a237SDavid Xu } 709e49a237SDavid Xu 71635f917aSDavid Xu /* 72635f917aSDavid Xu * Cancellation behavior: 73635f917aSDavid Xu * if the thread is canceled, joinee is not recycled. 74635f917aSDavid Xu */ 759e49a237SDavid Xu static int 769e49a237SDavid Xu join_common(pthread_t pthread, void **thread_return, 779e49a237SDavid Xu const struct timespec *abstime) 789e49a237SDavid Xu { 79a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 809e49a237SDavid Xu struct timespec ts, ts2, *tsp; 81a091d823SDavid Xu void *tmp; 82d7f119abSDavid Xu long tid; 83a091d823SDavid Xu int ret = 0; 84bb535300SJeff Roberson 85a091d823SDavid Xu if (pthread == NULL) 86bb535300SJeff Roberson return (EINVAL); 87bb535300SJeff Roberson 884cd18a22SMike Makonnen if (pthread == curthread) 89bb535300SJeff Roberson return (EDEADLK); 90bb535300SJeff Roberson 91a091d823SDavid Xu THREAD_LIST_LOCK(curthread); 92a091d823SDavid Xu if ((ret = _thr_find_thread(curthread, pthread, 1)) != 0) { 93bb535300SJeff Roberson ret = ESRCH; 94a091d823SDavid Xu } else if ((pthread->tlflags & TLFLAGS_DETACHED) != 0) { 956f54e829SDavid Xu ret = EINVAL; 96a091d823SDavid Xu } else if (pthread->joiner != NULL) { 97bb535300SJeff Roberson /* Multiple joiners are not supported. */ 98bb535300SJeff Roberson ret = ENOTSUP; 99bb535300SJeff Roberson } 100a091d823SDavid Xu if (ret) { 101a091d823SDavid Xu THREAD_LIST_UNLOCK(curthread); 102a091d823SDavid Xu return (ret); 103a091d823SDavid Xu } 104bb535300SJeff Roberson /* Set the running thread to be the joiner: */ 105bb535300SJeff Roberson pthread->joiner = curthread; 106bb535300SJeff Roberson 107a091d823SDavid Xu THREAD_LIST_UNLOCK(curthread); 108bb535300SJeff Roberson 109a091d823SDavid Xu THR_CLEANUP_PUSH(curthread, backout_join, pthread); 110*02c3c858SDavid Xu _thr_cancel_enter(curthread); 1114cd18a22SMike Makonnen 112d7f119abSDavid Xu tid = pthread->tid; 113d7f119abSDavid Xu while (pthread->tid != TID_TERMINATED) { 114635f917aSDavid Xu _thr_testcancel(curthread); 1159e49a237SDavid Xu if (abstime != NULL) { 1169e49a237SDavid Xu clock_gettime(CLOCK_REALTIME, &ts); 1179e49a237SDavid Xu TIMESPEC_SUB(&ts2, abstime, &ts); 1189e49a237SDavid Xu if (ts2.tv_sec < 0) { 1199e49a237SDavid Xu ret = ETIMEDOUT; 1209e49a237SDavid Xu break; 1219e49a237SDavid Xu } 1229e49a237SDavid Xu tsp = &ts2; 1239e49a237SDavid Xu } else 1249e49a237SDavid Xu tsp = NULL; 125d7f119abSDavid Xu ret = _thr_umtx_wait(&pthread->tid, tid, tsp); 1269e49a237SDavid Xu if (ret == ETIMEDOUT) 1279e49a237SDavid Xu break; 128bb535300SJeff Roberson } 129bb535300SJeff Roberson 130*02c3c858SDavid Xu _thr_cancel_leave(curthread, 0); 131a091d823SDavid Xu THR_CLEANUP_POP(curthread, 0); 132bb535300SJeff Roberson 1339e49a237SDavid Xu if (ret == ETIMEDOUT) { 1349e49a237SDavid Xu THREAD_LIST_LOCK(curthread); 1359e49a237SDavid Xu pthread->joiner = NULL; 1369e49a237SDavid Xu THREAD_LIST_UNLOCK(curthread); 1379e49a237SDavid Xu } else { 138597dc824SDavid Xu ret = 0; 139a091d823SDavid Xu tmp = pthread->ret; 140a091d823SDavid Xu THREAD_LIST_LOCK(curthread); 141a091d823SDavid Xu pthread->tlflags |= TLFLAGS_DETACHED; 1429e49a237SDavid Xu pthread->joiner = NULL; 143a091d823SDavid Xu THR_GCLIST_ADD(pthread); 144a091d823SDavid Xu THREAD_LIST_UNLOCK(curthread); 145bb535300SJeff Roberson 146a091d823SDavid Xu if (thread_return != NULL) 147a091d823SDavid Xu *thread_return = tmp; 1489e49a237SDavid Xu } 149bb535300SJeff Roberson return (ret); 150bb535300SJeff Roberson } 151