171b3fa15SDavid Xu /*- 271b3fa15SDavid Xu * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 371b3fa15SDavid Xu * All rights reserved. 471b3fa15SDavid Xu * 571b3fa15SDavid Xu * Redistribution and use in source and binary forms, with or without 671b3fa15SDavid Xu * modification, are permitted provided that the following conditions 771b3fa15SDavid Xu * are met: 871b3fa15SDavid Xu * 1. Redistributions of source code must retain the above copyright 971b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer. 1071b3fa15SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 1171b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer in the 1271b3fa15SDavid Xu * documentation and/or other materials provided with the distribution. 1371b3fa15SDavid Xu * 1471b3fa15SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1571b3fa15SDavid Xu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1671b3fa15SDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1771b3fa15SDavid Xu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1871b3fa15SDavid Xu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1971b3fa15SDavid Xu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2071b3fa15SDavid Xu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2171b3fa15SDavid Xu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2271b3fa15SDavid Xu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2371b3fa15SDavid Xu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2471b3fa15SDavid Xu * SUCH DAMAGE. 2571b3fa15SDavid Xu * 2671b3fa15SDavid Xu * $FreeBSD: src/lib/libpthread/thread/thr_barrier.c,v 1.1 2003/09/04 14:06:43 davidxu Exp $ 27*9e2ee207SJoerg Sonnenberger * $DragonFly: src/lib/libthread_xu/thread/thr_barrier.c,v 1.4 2005/03/29 19:26:20 joerg Exp $ 2871b3fa15SDavid Xu */ 2971b3fa15SDavid Xu 30*9e2ee207SJoerg Sonnenberger #include <machine/tls.h> 31*9e2ee207SJoerg Sonnenberger 3271b3fa15SDavid Xu #include <errno.h> 3371b3fa15SDavid Xu #include <stdlib.h> 3471b3fa15SDavid Xu #include <pthread.h> 3571b3fa15SDavid Xu 3671b3fa15SDavid Xu #include "thr_private.h" 3771b3fa15SDavid Xu 3871b3fa15SDavid Xu __weak_reference(_pthread_barrier_init, pthread_barrier_init); 3971b3fa15SDavid Xu __weak_reference(_pthread_barrier_wait, pthread_barrier_wait); 4071b3fa15SDavid Xu __weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy); 4171b3fa15SDavid Xu 4271b3fa15SDavid Xu int 4371b3fa15SDavid Xu _pthread_barrier_destroy(pthread_barrier_t *barrier) 4471b3fa15SDavid Xu { 4571b3fa15SDavid Xu pthread_barrier_t bar; 4671b3fa15SDavid Xu 4771b3fa15SDavid Xu if (barrier == NULL || *barrier == NULL) 4871b3fa15SDavid Xu return (EINVAL); 4971b3fa15SDavid Xu 5071b3fa15SDavid Xu bar = *barrier; 5171b3fa15SDavid Xu if (bar->b_waiters > 0) 5271b3fa15SDavid Xu return (EBUSY); 5371b3fa15SDavid Xu *barrier = NULL; 5471b3fa15SDavid Xu free(bar); 5571b3fa15SDavid Xu return (0); 5671b3fa15SDavid Xu } 5771b3fa15SDavid Xu 5871b3fa15SDavid Xu int 5971b3fa15SDavid Xu _pthread_barrier_init(pthread_barrier_t *barrier, 6071b3fa15SDavid Xu const pthread_barrierattr_t *attr, int count) 6171b3fa15SDavid Xu { 6271b3fa15SDavid Xu pthread_barrier_t bar; 6371b3fa15SDavid Xu 6471b3fa15SDavid Xu if (barrier == NULL || count <= 0) 6571b3fa15SDavid Xu return (EINVAL); 6671b3fa15SDavid Xu 6771b3fa15SDavid Xu bar = malloc(sizeof(struct pthread_barrier)); 6871b3fa15SDavid Xu if (bar == NULL) 6971b3fa15SDavid Xu return (ENOMEM); 7071b3fa15SDavid Xu 7171b3fa15SDavid Xu _thr_umtx_init(&bar->b_lock); 7271b3fa15SDavid Xu bar->b_cycle = 0; 7371b3fa15SDavid Xu bar->b_waiters = 0; 7471b3fa15SDavid Xu bar->b_count = count; 7571b3fa15SDavid Xu *barrier = bar; 7671b3fa15SDavid Xu 7771b3fa15SDavid Xu return (0); 7871b3fa15SDavid Xu } 7971b3fa15SDavid Xu 8071b3fa15SDavid Xu int 8171b3fa15SDavid Xu _pthread_barrier_wait(pthread_barrier_t *barrier) 8271b3fa15SDavid Xu { 83*9e2ee207SJoerg Sonnenberger struct pthread *curthread = tls_get_curthread(); 8471b3fa15SDavid Xu pthread_barrier_t bar; 8571b3fa15SDavid Xu long cycle; 8671b3fa15SDavid Xu int ret; 8771b3fa15SDavid Xu 8871b3fa15SDavid Xu if (barrier == NULL || *barrier == NULL) 8971b3fa15SDavid Xu return (EINVAL); 9071b3fa15SDavid Xu 9171b3fa15SDavid Xu bar = *barrier; 9271b3fa15SDavid Xu THR_UMTX_LOCK(curthread, &bar->b_lock); 9371b3fa15SDavid Xu if (++bar->b_waiters == bar->b_count) { 9471b3fa15SDavid Xu /* Current thread is lastest thread */ 9571b3fa15SDavid Xu bar->b_waiters = 0; 9671b3fa15SDavid Xu bar->b_cycle++; 973e58fd8bSDavid Xu _thr_umtx_wake(&bar->b_cycle, bar->b_count); 9871b3fa15SDavid Xu THR_UMTX_UNLOCK(curthread, &bar->b_lock); 9971b3fa15SDavid Xu ret = PTHREAD_BARRIER_SERIAL_THREAD; 10071b3fa15SDavid Xu } else { 10171b3fa15SDavid Xu cycle = bar->b_cycle; 10271b3fa15SDavid Xu THR_UMTX_UNLOCK(curthread, &bar->b_lock); 10371b3fa15SDavid Xu do { 1049219c44cSDavid Xu _thr_umtx_wait(&bar->b_cycle, cycle, NULL, 0); 10571b3fa15SDavid Xu /* test cycle to avoid bogus wakeup */ 10671b3fa15SDavid Xu } while (cycle == bar->b_cycle); 10771b3fa15SDavid Xu ret = 0; 10871b3fa15SDavid Xu } 10971b3fa15SDavid Xu return (ret); 11071b3fa15SDavid Xu } 111