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 2732793011SKonstantin Belousov #include <sys/cdefs.h> 2832793011SKonstantin Belousov __FBSDID("$FreeBSD$"); 2932793011SKonstantin Belousov 3037a6356bSDavid Xu #include "namespace.h" 31a091d823SDavid Xu #include <errno.h> 32d4d7df5cSMike Makonnen #include <stdlib.h> 33a091d823SDavid Xu #include <pthread.h> 3437a6356bSDavid Xu #include "un-namespace.h" 35d4d7df5cSMike Makonnen 36d4d7df5cSMike Makonnen #include "thr_private.h" 37d4d7df5cSMike Makonnen 389e821f27SKonstantin Belousov _Static_assert(sizeof(struct pthread_barrier) <= PAGE_SIZE, 399e821f27SKonstantin Belousov "pthread_barrier is too large for off-page"); 409e821f27SKonstantin Belousov 41d4d7df5cSMike Makonnen __weak_reference(_pthread_barrier_init, pthread_barrier_init); 42d4d7df5cSMike Makonnen __weak_reference(_pthread_barrier_wait, pthread_barrier_wait); 43a091d823SDavid Xu __weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy); 44d4d7df5cSMike Makonnen 45d4d7df5cSMike Makonnen int 46d4d7df5cSMike Makonnen _pthread_barrier_destroy(pthread_barrier_t *barrier) 47d4d7df5cSMike Makonnen { 48a091d823SDavid Xu pthread_barrier_t bar; 49e70bf9d5SDavid Xu struct pthread *curthread; 501bdbd705SKonstantin Belousov int pshared; 51a091d823SDavid Xu 52a091d823SDavid Xu if (barrier == NULL || *barrier == NULL) 53d4d7df5cSMike Makonnen return (EINVAL); 54a091d823SDavid Xu 551bdbd705SKonstantin Belousov if (*barrier == THR_PSHARED_PTR) { 561bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 0); 571bdbd705SKonstantin Belousov if (bar == NULL) { 581bdbd705SKonstantin Belousov *barrier = NULL; 591bdbd705SKonstantin Belousov return (0); 601bdbd705SKonstantin Belousov } 611bdbd705SKonstantin Belousov pshared = 1; 621bdbd705SKonstantin Belousov } else { 63a091d823SDavid Xu bar = *barrier; 641bdbd705SKonstantin Belousov pshared = 0; 651bdbd705SKonstantin Belousov } 661bdbd705SKonstantin Belousov curthread = _get_curthread(); 67e70bf9d5SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 68e70bf9d5SDavid Xu if (bar->b_destroying) { 69e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 70d4d7df5cSMike Makonnen return (EBUSY); 71e70bf9d5SDavid Xu } 72e70bf9d5SDavid Xu bar->b_destroying = 1; 73e70bf9d5SDavid Xu do { 74e70bf9d5SDavid Xu if (bar->b_waiters > 0) { 75e70bf9d5SDavid Xu bar->b_destroying = 0; 76e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 77e70bf9d5SDavid Xu return (EBUSY); 78e70bf9d5SDavid Xu } 79e70bf9d5SDavid Xu if (bar->b_refcount != 0) { 80e70bf9d5SDavid Xu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 81e70bf9d5SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 82e70bf9d5SDavid Xu } else 83e70bf9d5SDavid Xu break; 84e70bf9d5SDavid Xu } while (1); 85e70bf9d5SDavid Xu bar->b_destroying = 0; 86e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 87e70bf9d5SDavid Xu 88d4d7df5cSMike Makonnen *barrier = NULL; 891bdbd705SKonstantin Belousov if (pshared) 901bdbd705SKonstantin Belousov __thr_pshared_destroy(barrier); 911bdbd705SKonstantin Belousov else 92a091d823SDavid Xu free(bar); 93d4d7df5cSMike Makonnen return (0); 94d4d7df5cSMike Makonnen } 95d4d7df5cSMike Makonnen 96d4d7df5cSMike Makonnen int 97d4d7df5cSMike Makonnen _pthread_barrier_init(pthread_barrier_t *barrier, 9837a6356bSDavid Xu const pthread_barrierattr_t *attr, unsigned count) 99d4d7df5cSMike Makonnen { 100a091d823SDavid Xu pthread_barrier_t bar; 1011bdbd705SKonstantin Belousov int pshared; 10237a6356bSDavid Xu 103*1c9158aaSPedro F. Giffuni if (barrier == NULL || count == 0 || count > INT_MAX) 104d4d7df5cSMike Makonnen return (EINVAL); 105a091d823SDavid Xu 1061bdbd705SKonstantin Belousov if (attr == NULL || *attr == NULL || 1071bdbd705SKonstantin Belousov (*attr)->pshared == PTHREAD_PROCESS_PRIVATE) { 10883d74204SKonstantin Belousov bar = calloc(1, sizeof(struct pthread_barrier)); 109a091d823SDavid Xu if (bar == NULL) 110d4d7df5cSMike Makonnen return (ENOMEM); 1111bdbd705SKonstantin Belousov *barrier = bar; 1121bdbd705SKonstantin Belousov pshared = 0; 1131bdbd705SKonstantin Belousov } else { 1141bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 1); 1151bdbd705SKonstantin Belousov if (bar == NULL) 1161bdbd705SKonstantin Belousov return (EFAULT); 1171bdbd705SKonstantin Belousov *barrier = THR_PSHARED_PTR; 1181bdbd705SKonstantin Belousov pshared = 1; 1191bdbd705SKonstantin Belousov } 120a091d823SDavid Xu 121bddd24cdSDavid Xu _thr_umutex_init(&bar->b_lock); 1224d617f2dSDavid Xu _thr_ucond_init(&bar->b_cv); 1231bdbd705SKonstantin Belousov if (pshared) { 1241bdbd705SKonstantin Belousov bar->b_lock.m_flags |= USYNC_PROCESS_SHARED; 1251bdbd705SKonstantin Belousov bar->b_cv.c_flags |= USYNC_PROCESS_SHARED; 1261bdbd705SKonstantin Belousov } 127a091d823SDavid Xu bar->b_count = count; 128d4d7df5cSMike Makonnen return (0); 129d4d7df5cSMike Makonnen } 130d4d7df5cSMike Makonnen 131d4d7df5cSMike Makonnen int 132d4d7df5cSMike Makonnen _pthread_barrier_wait(pthread_barrier_t *barrier) 133d4d7df5cSMike Makonnen { 1341bdbd705SKonstantin Belousov struct pthread *curthread; 135a091d823SDavid Xu pthread_barrier_t bar; 1364d617f2dSDavid Xu int64_t cycle; 137a091d823SDavid Xu int ret; 138d4d7df5cSMike Makonnen 139a091d823SDavid Xu if (barrier == NULL || *barrier == NULL) 140d4d7df5cSMike Makonnen return (EINVAL); 141d4d7df5cSMike Makonnen 1421bdbd705SKonstantin Belousov if (*barrier == THR_PSHARED_PTR) { 1431bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 0); 1441bdbd705SKonstantin Belousov if (bar == NULL) 1451bdbd705SKonstantin Belousov return (EINVAL); 1461bdbd705SKonstantin Belousov } else { 147a091d823SDavid Xu bar = *barrier; 1481bdbd705SKonstantin Belousov } 1491bdbd705SKonstantin Belousov curthread = _get_curthread(); 150bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 151a091d823SDavid Xu if (++bar->b_waiters == bar->b_count) { 152a091d823SDavid Xu /* Current thread is lastest thread */ 153a091d823SDavid Xu bar->b_waiters = 0; 154a091d823SDavid Xu bar->b_cycle++; 1554d617f2dSDavid Xu _thr_ucond_broadcast(&bar->b_cv); 156bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 157a091d823SDavid Xu ret = PTHREAD_BARRIER_SERIAL_THREAD; 158a091d823SDavid Xu } else { 159a091d823SDavid Xu cycle = bar->b_cycle; 160e70bf9d5SDavid Xu bar->b_refcount++; 161d4d7df5cSMike Makonnen do { 1624d617f2dSDavid Xu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 163a8a343d2SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 164a091d823SDavid Xu /* test cycle to avoid bogus wakeup */ 165a091d823SDavid Xu } while (cycle == bar->b_cycle); 166e70bf9d5SDavid Xu if (--bar->b_refcount == 0 && bar->b_destroying) 167e70bf9d5SDavid Xu _thr_ucond_broadcast(&bar->b_cv); 1684d617f2dSDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 169a091d823SDavid Xu ret = 0; 170d4d7df5cSMike Makonnen } 171a091d823SDavid Xu return (ret); 172d4d7df5cSMike Makonnen } 173