1126000Smtm/*- 2144518Sdavidxu * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 3126000Smtm * All rights reserved. 4126000Smtm * 5126000Smtm * Redistribution and use in source and binary forms, with or without 6126000Smtm * modification, are permitted provided that the following conditions 7126000Smtm * are met: 8126000Smtm * 1. Redistributions of source code must retain the above copyright 9126000Smtm * notice, this list of conditions and the following disclaimer. 10126000Smtm * 2. Redistributions in binary form must reproduce the above copyright 11126000Smtm * notice, this list of conditions and the following disclaimer in the 12126000Smtm * documentation and/or other materials provided with the distribution. 13126000Smtm * 14126000Smtm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15126000Smtm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16126000Smtm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17126000Smtm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18126000Smtm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19126000Smtm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20126000Smtm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21126000Smtm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22126000Smtm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23126000Smtm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24126000Smtm * SUCH DAMAGE. 25126000Smtm * 26126000Smtm * $FreeBSD: releng/10.2/lib/libthr/thread/thr_barrier.c 278668 2015-02-13 08:42:01Z kib $ 27126000Smtm */ 28126000Smtm 29157457Sdavidxu#include "namespace.h" 30144518Sdavidxu#include <errno.h> 31144518Sdavidxu#include <stdlib.h> 32126000Smtm#include <pthread.h> 33157457Sdavidxu#include "un-namespace.h" 34126000Smtm 35126000Smtm#include "thr_private.h" 36126000Smtm 37144518Sdavidxu__weak_reference(_pthread_barrier_init, pthread_barrier_init); 38144518Sdavidxu__weak_reference(_pthread_barrier_wait, pthread_barrier_wait); 39144518Sdavidxu__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy); 40126000Smtm 41126000Smtmint 42126000Smtm_pthread_barrier_destroy(pthread_barrier_t *barrier) 43126000Smtm{ 44144518Sdavidxu pthread_barrier_t bar; 45233022Sdavidxu struct pthread *curthread; 46144518Sdavidxu 47144518Sdavidxu if (barrier == NULL || *barrier == NULL) 48126000Smtm return (EINVAL); 49144518Sdavidxu 50233022Sdavidxu curthread = _get_curthread(); 51144518Sdavidxu bar = *barrier; 52233022Sdavidxu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 53233022Sdavidxu if (bar->b_destroying) { 54233022Sdavidxu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 55126000Smtm return (EBUSY); 56233022Sdavidxu } 57233022Sdavidxu bar->b_destroying = 1; 58233022Sdavidxu do { 59233022Sdavidxu if (bar->b_waiters > 0) { 60233022Sdavidxu bar->b_destroying = 0; 61233022Sdavidxu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 62233022Sdavidxu return (EBUSY); 63233022Sdavidxu } 64233022Sdavidxu if (bar->b_refcount != 0) { 65233022Sdavidxu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 66233022Sdavidxu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 67233022Sdavidxu } else 68233022Sdavidxu break; 69233022Sdavidxu } while (1); 70233022Sdavidxu bar->b_destroying = 0; 71233022Sdavidxu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 72233022Sdavidxu 73126000Smtm *barrier = NULL; 74144518Sdavidxu free(bar); 75126000Smtm return (0); 76126000Smtm} 77126000Smtm 78126000Smtmint 79126000Smtm_pthread_barrier_init(pthread_barrier_t *barrier, 80157457Sdavidxu const pthread_barrierattr_t *attr, unsigned count) 81126000Smtm{ 82144518Sdavidxu pthread_barrier_t bar; 83144518Sdavidxu 84157457Sdavidxu (void)attr; 85157457Sdavidxu 86144518Sdavidxu if (barrier == NULL || count <= 0) 87126000Smtm return (EINVAL); 88144518Sdavidxu 89278668Skib bar = calloc(1, sizeof(struct pthread_barrier)); 90144518Sdavidxu if (bar == NULL) 91126000Smtm return (ENOMEM); 92144518Sdavidxu 93162061Sdavidxu _thr_umutex_init(&bar->b_lock); 94164903Sdavidxu _thr_ucond_init(&bar->b_cv); 95144518Sdavidxu bar->b_count = count; 96144518Sdavidxu *barrier = bar; 97144518Sdavidxu 98126000Smtm return (0); 99126000Smtm} 100126000Smtm 101126000Smtmint 102126000Smtm_pthread_barrier_wait(pthread_barrier_t *barrier) 103126000Smtm{ 104144518Sdavidxu struct pthread *curthread = _get_curthread(); 105144518Sdavidxu pthread_barrier_t bar; 106164903Sdavidxu int64_t cycle; 107144518Sdavidxu int ret; 108126000Smtm 109144518Sdavidxu if (barrier == NULL || *barrier == NULL) 110126000Smtm return (EINVAL); 111126000Smtm 112144518Sdavidxu bar = *barrier; 113162061Sdavidxu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 114144518Sdavidxu if (++bar->b_waiters == bar->b_count) { 115144518Sdavidxu /* Current thread is lastest thread */ 116144518Sdavidxu bar->b_waiters = 0; 117144518Sdavidxu bar->b_cycle++; 118164903Sdavidxu _thr_ucond_broadcast(&bar->b_cv); 119162061Sdavidxu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 120144518Sdavidxu ret = PTHREAD_BARRIER_SERIAL_THREAD; 121144518Sdavidxu } else { 122144518Sdavidxu cycle = bar->b_cycle; 123233022Sdavidxu bar->b_refcount++; 124144518Sdavidxu do { 125164903Sdavidxu _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0); 126164927Sdavidxu THR_UMUTEX_LOCK(curthread, &bar->b_lock); 127144518Sdavidxu /* test cycle to avoid bogus wakeup */ 128144518Sdavidxu } while (cycle == bar->b_cycle); 129233022Sdavidxu if (--bar->b_refcount == 0 && bar->b_destroying) 130233022Sdavidxu _thr_ucond_broadcast(&bar->b_cv); 131164903Sdavidxu THR_UMUTEX_UNLOCK(curthread, &bar->b_lock); 132144518Sdavidxu ret = 0; 133126000Smtm } 134144518Sdavidxu return (ret); 135126000Smtm} 136