1d4d7df5cSMike Makonnen /*- 2a091d823SDavid Xu * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 3d4d7df5cSMike Makonnen * All rights reserved. 4d4d7df5cSMike Makonnen * 5d4d7df5cSMike Makonnen * Redistribution and use in source and binary forms, with or without 6d4d7df5cSMike Makonnen * modification, are permitted provided that the following conditions 7d4d7df5cSMike Makonnen * are met: 8d4d7df5cSMike Makonnen * 1. Redistributions of source code must retain the above copyright 9d4d7df5cSMike Makonnen * notice, this list of conditions and the following disclaimer. 10d4d7df5cSMike Makonnen * 2. Redistributions in binary form must reproduce the above copyright 11d4d7df5cSMike Makonnen * notice, this list of conditions and the following disclaimer in the 12d4d7df5cSMike Makonnen * documentation and/or other materials provided with the distribution. 13d4d7df5cSMike Makonnen * 14d4d7df5cSMike Makonnen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15d4d7df5cSMike Makonnen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d4d7df5cSMike Makonnen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d4d7df5cSMike Makonnen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18d4d7df5cSMike Makonnen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d4d7df5cSMike Makonnen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d4d7df5cSMike Makonnen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d4d7df5cSMike Makonnen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d4d7df5cSMike Makonnen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d4d7df5cSMike Makonnen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d4d7df5cSMike Makonnen * SUCH DAMAGE. 25d4d7df5cSMike Makonnen * 26d4d7df5cSMike Makonnen * $FreeBSD$ 27d4d7df5cSMike Makonnen */ 28d4d7df5cSMike Makonnen 2937a6356bSDavid Xu #include "namespace.h" 30a091d823SDavid Xu #include <errno.h> 31d4d7df5cSMike Makonnen #include <stdlib.h> 32a091d823SDavid Xu #include <pthread.h> 3337a6356bSDavid Xu #include "un-namespace.h" 34d4d7df5cSMike Makonnen 35d4d7df5cSMike Makonnen #include "thr_private.h" 36d4d7df5cSMike Makonnen 37*9e821f27SKonstantin Belousov _Static_assert(sizeof(struct pthread_barrier) <= PAGE_SIZE, 38*9e821f27SKonstantin Belousov "pthread_barrier is too large for off-page"); 39*9e821f27SKonstantin Belousov 40d4d7df5cSMike Makonnen __weak_reference(_pthread_barrier_init, pthread_barrier_init); 41d4d7df5cSMike Makonnen __weak_reference(_pthread_barrier_wait, pthread_barrier_wait); 42a091d823SDavid Xu __weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy); 43d4d7df5cSMike Makonnen 44d4d7df5cSMike Makonnen int 45d4d7df5cSMike Makonnen _pthread_barrier_destroy(pthread_barrier_t *barrier) 46d4d7df5cSMike Makonnen { 47a091d823SDavid Xu pthread_barrier_t bar; 48e70bf9d5SDavid Xu struct pthread *curthread; 491bdbd705SKonstantin Belousov int pshared; 50a091d823SDavid Xu 51a091d823SDavid Xu if (barrier == NULL || *barrier == NULL) 52d4d7df5cSMike Makonnen return (EINVAL); 53a091d823SDavid Xu 541bdbd705SKonstantin Belousov if (*barrier == THR_PSHARED_PTR) { 551bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 0); 561bdbd705SKonstantin Belousov if (bar == NULL) { 571bdbd705SKonstantin Belousov *barrier = NULL; 581bdbd705SKonstantin Belousov return (0); 591bdbd705SKonstantin Belousov } 601bdbd705SKonstantin Belousov pshared = 1; 611bdbd705SKonstantin Belousov } else { 62a091d823SDavid Xu bar = *barrier; 631bdbd705SKonstantin Belousov pshared = 0; 641bdbd705SKonstantin Belousov } 651bdbd705SKonstantin Belousov curthread = _get_curthread(); 66e70bf9d5SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 67e70bf9d5SDavid Xu if (bar->b_destroying) { 68e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 69d4d7df5cSMike Makonnen return (EBUSY); 70e70bf9d5SDavid Xu } 71e70bf9d5SDavid Xu bar->b_destroying = 1; 72e70bf9d5SDavid Xu do { 73e70bf9d5SDavid Xu if (bar->b_waiters > 0) { 74e70bf9d5SDavid Xu bar->b_destroying = 0; 75e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 76e70bf9d5SDavid Xu return (EBUSY); 77e70bf9d5SDavid Xu } 78e70bf9d5SDavid Xu if (bar->b_refcount != 0) { 79e70bf9d5SDavid Xu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 80e70bf9d5SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 81e70bf9d5SDavid Xu } else 82e70bf9d5SDavid Xu break; 83e70bf9d5SDavid Xu } while (1); 84e70bf9d5SDavid Xu bar->b_destroying = 0; 85e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 86e70bf9d5SDavid Xu 87d4d7df5cSMike Makonnen *barrier = NULL; 881bdbd705SKonstantin Belousov if (pshared) 891bdbd705SKonstantin Belousov __thr_pshared_destroy(barrier); 901bdbd705SKonstantin Belousov else 91a091d823SDavid Xu free(bar); 92d4d7df5cSMike Makonnen return (0); 93d4d7df5cSMike Makonnen } 94d4d7df5cSMike Makonnen 95d4d7df5cSMike Makonnen int 96d4d7df5cSMike Makonnen _pthread_barrier_init(pthread_barrier_t *barrier, 9737a6356bSDavid Xu const pthread_barrierattr_t *attr, unsigned count) 98d4d7df5cSMike Makonnen { 99a091d823SDavid Xu pthread_barrier_t bar; 1001bdbd705SKonstantin Belousov int pshared; 10137a6356bSDavid Xu 102a091d823SDavid Xu if (barrier == NULL || count <= 0) 103d4d7df5cSMike Makonnen return (EINVAL); 104a091d823SDavid Xu 1051bdbd705SKonstantin Belousov if (attr == NULL || *attr == NULL || 1061bdbd705SKonstantin Belousov (*attr)->pshared == PTHREAD_PROCESS_PRIVATE) { 10783d74204SKonstantin Belousov bar = calloc(1, sizeof(struct pthread_barrier)); 108a091d823SDavid Xu if (bar == NULL) 109d4d7df5cSMike Makonnen return (ENOMEM); 1101bdbd705SKonstantin Belousov *barrier = bar; 1111bdbd705SKonstantin Belousov pshared = 0; 1121bdbd705SKonstantin Belousov } else { 1131bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 1); 1141bdbd705SKonstantin Belousov if (bar == NULL) 1151bdbd705SKonstantin Belousov return (EFAULT); 1161bdbd705SKonstantin Belousov *barrier = THR_PSHARED_PTR; 1171bdbd705SKonstantin Belousov pshared = 1; 1181bdbd705SKonstantin Belousov } 119a091d823SDavid Xu 120bddd24cdSDavid Xu _thr_umutex_init(&bar->b_lock); 1214d617f2dSDavid Xu _thr_ucond_init(&bar->b_cv); 1221bdbd705SKonstantin Belousov if (pshared) { 1231bdbd705SKonstantin Belousov bar->b_lock.m_flags |= USYNC_PROCESS_SHARED; 1241bdbd705SKonstantin Belousov bar->b_cv.c_flags |= USYNC_PROCESS_SHARED; 1251bdbd705SKonstantin Belousov } 126a091d823SDavid Xu bar->b_count = count; 127d4d7df5cSMike Makonnen return (0); 128d4d7df5cSMike Makonnen } 129d4d7df5cSMike Makonnen 130d4d7df5cSMike Makonnen int 131d4d7df5cSMike Makonnen _pthread_barrier_wait(pthread_barrier_t *barrier) 132d4d7df5cSMike Makonnen { 1331bdbd705SKonstantin Belousov struct pthread *curthread; 134a091d823SDavid Xu pthread_barrier_t bar; 1354d617f2dSDavid Xu int64_t cycle; 136a091d823SDavid Xu int ret; 137d4d7df5cSMike Makonnen 138a091d823SDavid Xu if (barrier == NULL || *barrier == NULL) 139d4d7df5cSMike Makonnen return (EINVAL); 140d4d7df5cSMike Makonnen 1411bdbd705SKonstantin Belousov if (*barrier == THR_PSHARED_PTR) { 1421bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 0); 1431bdbd705SKonstantin Belousov if (bar == NULL) 1441bdbd705SKonstantin Belousov return (EINVAL); 1451bdbd705SKonstantin Belousov } else { 146a091d823SDavid Xu bar = *barrier; 1471bdbd705SKonstantin Belousov } 1481bdbd705SKonstantin Belousov curthread = _get_curthread(); 149bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 150a091d823SDavid Xu if (++bar->b_waiters == bar->b_count) { 151a091d823SDavid Xu /* Current thread is lastest thread */ 152a091d823SDavid Xu bar->b_waiters = 0; 153a091d823SDavid Xu bar->b_cycle++; 1544d617f2dSDavid Xu _thr_ucond_broadcast(&bar->b_cv); 155bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 156a091d823SDavid Xu ret = PTHREAD_BARRIER_SERIAL_THREAD; 157a091d823SDavid Xu } else { 158a091d823SDavid Xu cycle = bar->b_cycle; 159e70bf9d5SDavid Xu bar->b_refcount++; 160d4d7df5cSMike Makonnen do { 1614d617f2dSDavid Xu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 162a8a343d2SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 163a091d823SDavid Xu /* test cycle to avoid bogus wakeup */ 164a091d823SDavid Xu } while (cycle == bar->b_cycle); 165e70bf9d5SDavid Xu if (--bar->b_refcount == 0 && bar->b_destroying) 166e70bf9d5SDavid Xu _thr_ucond_broadcast(&bar->b_cv); 1674d617f2dSDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 168a091d823SDavid Xu ret = 0; 169d4d7df5cSMike Makonnen } 170a091d823SDavid Xu return (ret); 171d4d7df5cSMike Makonnen } 172