1d4d7df5cSMike Makonnen /*- 2*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*5e53a4f9SPedro F. Giffuni * 4a091d823SDavid Xu * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 5d4d7df5cSMike Makonnen * All rights reserved. 6d4d7df5cSMike Makonnen * 7d4d7df5cSMike Makonnen * Redistribution and use in source and binary forms, with or without 8d4d7df5cSMike Makonnen * modification, are permitted provided that the following conditions 9d4d7df5cSMike Makonnen * are met: 10d4d7df5cSMike Makonnen * 1. Redistributions of source code must retain the above copyright 11d4d7df5cSMike Makonnen * notice, this list of conditions and the following disclaimer. 12d4d7df5cSMike Makonnen * 2. Redistributions in binary form must reproduce the above copyright 13d4d7df5cSMike Makonnen * notice, this list of conditions and the following disclaimer in the 14d4d7df5cSMike Makonnen * documentation and/or other materials provided with the distribution. 15d4d7df5cSMike Makonnen * 16d4d7df5cSMike Makonnen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17d4d7df5cSMike Makonnen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18d4d7df5cSMike Makonnen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19d4d7df5cSMike Makonnen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20d4d7df5cSMike Makonnen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21d4d7df5cSMike Makonnen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22d4d7df5cSMike Makonnen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23d4d7df5cSMike Makonnen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24d4d7df5cSMike Makonnen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25d4d7df5cSMike Makonnen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26d4d7df5cSMike Makonnen * SUCH DAMAGE. 27d4d7df5cSMike Makonnen */ 28d4d7df5cSMike Makonnen 2932793011SKonstantin Belousov #include <sys/cdefs.h> 3032793011SKonstantin Belousov __FBSDID("$FreeBSD$"); 3132793011SKonstantin Belousov 3237a6356bSDavid Xu #include "namespace.h" 33a091d823SDavid Xu #include <errno.h> 34d4d7df5cSMike Makonnen #include <stdlib.h> 35a091d823SDavid Xu #include <pthread.h> 3637a6356bSDavid Xu #include "un-namespace.h" 37d4d7df5cSMike Makonnen 38d4d7df5cSMike Makonnen #include "thr_private.h" 39d4d7df5cSMike Makonnen 409e821f27SKonstantin Belousov _Static_assert(sizeof(struct pthread_barrier) <= PAGE_SIZE, 419e821f27SKonstantin Belousov "pthread_barrier is too large for off-page"); 429e821f27SKonstantin Belousov 43d4d7df5cSMike Makonnen __weak_reference(_pthread_barrier_init, pthread_barrier_init); 44d4d7df5cSMike Makonnen __weak_reference(_pthread_barrier_wait, pthread_barrier_wait); 45a091d823SDavid Xu __weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy); 46d4d7df5cSMike Makonnen 47d4d7df5cSMike Makonnen int 48d4d7df5cSMike Makonnen _pthread_barrier_destroy(pthread_barrier_t *barrier) 49d4d7df5cSMike Makonnen { 50a091d823SDavid Xu pthread_barrier_t bar; 51e70bf9d5SDavid Xu struct pthread *curthread; 521bdbd705SKonstantin Belousov int pshared; 53a091d823SDavid Xu 54a091d823SDavid Xu if (barrier == NULL || *barrier == NULL) 55d4d7df5cSMike Makonnen return (EINVAL); 56a091d823SDavid Xu 571bdbd705SKonstantin Belousov if (*barrier == THR_PSHARED_PTR) { 581bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 0); 591bdbd705SKonstantin Belousov if (bar == NULL) { 601bdbd705SKonstantin Belousov *barrier = NULL; 611bdbd705SKonstantin Belousov return (0); 621bdbd705SKonstantin Belousov } 631bdbd705SKonstantin Belousov pshared = 1; 641bdbd705SKonstantin Belousov } else { 65a091d823SDavid Xu bar = *barrier; 661bdbd705SKonstantin Belousov pshared = 0; 671bdbd705SKonstantin Belousov } 681bdbd705SKonstantin Belousov curthread = _get_curthread(); 69e70bf9d5SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 70e70bf9d5SDavid Xu if (bar->b_destroying) { 71e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 72d4d7df5cSMike Makonnen return (EBUSY); 73e70bf9d5SDavid Xu } 74e70bf9d5SDavid Xu bar->b_destroying = 1; 75e70bf9d5SDavid Xu do { 76e70bf9d5SDavid Xu if (bar->b_waiters > 0) { 77e70bf9d5SDavid Xu bar->b_destroying = 0; 78e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 79e70bf9d5SDavid Xu return (EBUSY); 80e70bf9d5SDavid Xu } 81e70bf9d5SDavid Xu if (bar->b_refcount != 0) { 82e70bf9d5SDavid Xu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 83e70bf9d5SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 84e70bf9d5SDavid Xu } else 85e70bf9d5SDavid Xu break; 86e70bf9d5SDavid Xu } while (1); 87e70bf9d5SDavid Xu bar->b_destroying = 0; 88e70bf9d5SDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 89e70bf9d5SDavid Xu 90d4d7df5cSMike Makonnen *barrier = NULL; 911bdbd705SKonstantin Belousov if (pshared) 921bdbd705SKonstantin Belousov __thr_pshared_destroy(barrier); 931bdbd705SKonstantin Belousov else 94a091d823SDavid Xu free(bar); 95d4d7df5cSMike Makonnen return (0); 96d4d7df5cSMike Makonnen } 97d4d7df5cSMike Makonnen 98d4d7df5cSMike Makonnen int 99d4d7df5cSMike Makonnen _pthread_barrier_init(pthread_barrier_t *barrier, 10037a6356bSDavid Xu const pthread_barrierattr_t *attr, unsigned count) 101d4d7df5cSMike Makonnen { 102a091d823SDavid Xu pthread_barrier_t bar; 1031bdbd705SKonstantin Belousov int pshared; 10437a6356bSDavid Xu 1051c9158aaSPedro F. Giffuni if (barrier == NULL || count == 0 || count > INT_MAX) 106d4d7df5cSMike Makonnen return (EINVAL); 107a091d823SDavid Xu 1081bdbd705SKonstantin Belousov if (attr == NULL || *attr == NULL || 1091bdbd705SKonstantin Belousov (*attr)->pshared == PTHREAD_PROCESS_PRIVATE) { 11083d74204SKonstantin Belousov bar = calloc(1, sizeof(struct pthread_barrier)); 111a091d823SDavid Xu if (bar == NULL) 112d4d7df5cSMike Makonnen return (ENOMEM); 1131bdbd705SKonstantin Belousov *barrier = bar; 1141bdbd705SKonstantin Belousov pshared = 0; 1151bdbd705SKonstantin Belousov } else { 1161bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 1); 1171bdbd705SKonstantin Belousov if (bar == NULL) 1181bdbd705SKonstantin Belousov return (EFAULT); 1191bdbd705SKonstantin Belousov *barrier = THR_PSHARED_PTR; 1201bdbd705SKonstantin Belousov pshared = 1; 1211bdbd705SKonstantin Belousov } 122a091d823SDavid Xu 123bddd24cdSDavid Xu _thr_umutex_init(&bar->b_lock); 1244d617f2dSDavid Xu _thr_ucond_init(&bar->b_cv); 1251bdbd705SKonstantin Belousov if (pshared) { 1261bdbd705SKonstantin Belousov bar->b_lock.m_flags |= USYNC_PROCESS_SHARED; 1271bdbd705SKonstantin Belousov bar->b_cv.c_flags |= USYNC_PROCESS_SHARED; 1281bdbd705SKonstantin Belousov } 129a091d823SDavid Xu bar->b_count = count; 130d4d7df5cSMike Makonnen return (0); 131d4d7df5cSMike Makonnen } 132d4d7df5cSMike Makonnen 133d4d7df5cSMike Makonnen int 134d4d7df5cSMike Makonnen _pthread_barrier_wait(pthread_barrier_t *barrier) 135d4d7df5cSMike Makonnen { 1361bdbd705SKonstantin Belousov struct pthread *curthread; 137a091d823SDavid Xu pthread_barrier_t bar; 1384d617f2dSDavid Xu int64_t cycle; 139a091d823SDavid Xu int ret; 140d4d7df5cSMike Makonnen 141a091d823SDavid Xu if (barrier == NULL || *barrier == NULL) 142d4d7df5cSMike Makonnen return (EINVAL); 143d4d7df5cSMike Makonnen 1441bdbd705SKonstantin Belousov if (*barrier == THR_PSHARED_PTR) { 1451bdbd705SKonstantin Belousov bar = __thr_pshared_offpage(barrier, 0); 1461bdbd705SKonstantin Belousov if (bar == NULL) 1471bdbd705SKonstantin Belousov return (EINVAL); 1481bdbd705SKonstantin Belousov } else { 149a091d823SDavid Xu bar = *barrier; 1501bdbd705SKonstantin Belousov } 1511bdbd705SKonstantin Belousov curthread = _get_curthread(); 152bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 153a091d823SDavid Xu if (++bar->b_waiters == bar->b_count) { 154a091d823SDavid Xu /* Current thread is lastest thread */ 155a091d823SDavid Xu bar->b_waiters = 0; 156a091d823SDavid Xu bar->b_cycle++; 1574d617f2dSDavid Xu _thr_ucond_broadcast(&bar->b_cv); 158bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 159a091d823SDavid Xu ret = PTHREAD_BARRIER_SERIAL_THREAD; 160a091d823SDavid Xu } else { 161a091d823SDavid Xu cycle = bar->b_cycle; 162e70bf9d5SDavid Xu bar->b_refcount++; 163d4d7df5cSMike Makonnen do { 1644d617f2dSDavid Xu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 165a8a343d2SDavid Xu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 166a091d823SDavid Xu /* test cycle to avoid bogus wakeup */ 167a091d823SDavid Xu } while (cycle == bar->b_cycle); 168e70bf9d5SDavid Xu if (--bar->b_refcount == 0 && bar->b_destroying) 169e70bf9d5SDavid Xu _thr_ucond_broadcast(&bar->b_cv); 1704d617f2dSDavid Xu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 171a091d823SDavid Xu ret = 0; 172d4d7df5cSMike Makonnen } 173a091d823SDavid Xu return (ret); 174d4d7df5cSMike Makonnen } 175