1 1.23 riastrad /* $NetBSD: pthread_barrier.c,v 1.23 2022/02/12 14:59:32 riastradh Exp $ */ 2 1.2 thorpej 3 1.2 thorpej /*- 4 1.22 ad * Copyright (c) 2001, 2003, 2006, 2007, 2009, 2020 The NetBSD Foundation, Inc. 5 1.2 thorpej * All rights reserved. 6 1.2 thorpej * 7 1.2 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.11 ad * by Nathan J. Williams, by Jason R. Thorpe, and by Andrew Doran. 9 1.2 thorpej * 10 1.2 thorpej * Redistribution and use in source and binary forms, with or without 11 1.2 thorpej * modification, are permitted provided that the following conditions 12 1.2 thorpej * are met: 13 1.2 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.2 thorpej * notice, this list of conditions and the following disclaimer. 15 1.2 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.2 thorpej * documentation and/or other materials provided with the distribution. 18 1.2 thorpej * 19 1.2 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.2 thorpej */ 31 1.6 lukem 32 1.6 lukem #include <sys/cdefs.h> 33 1.23 riastrad __RCSID("$NetBSD: pthread_barrier.c,v 1.23 2022/02/12 14:59:32 riastradh Exp $"); 34 1.23 riastrad 35 1.23 riastrad /* Need to use libc-private names for atomic operations. */ 36 1.23 riastrad #include "../../common/lib/libc/atomic/atomic_op_namespace.h" 37 1.2 thorpej 38 1.2 thorpej #include <errno.h> 39 1.2 thorpej 40 1.2 thorpej #include "pthread.h" 41 1.2 thorpej #include "pthread_int.h" 42 1.2 thorpej 43 1.2 thorpej int 44 1.2 thorpej pthread_barrier_init(pthread_barrier_t *barrier, 45 1.18 ad const pthread_barrierattr_t *attr, unsigned int count) 46 1.2 thorpej { 47 1.21 kamil 48 1.21 kamil pthread__error(EINVAL, "Invalid barrier attribute", 49 1.21 kamil attr == NULL || attr->ptba_magic == _PT_BARRIERATTR_MAGIC); 50 1.2 thorpej if (count == 0) 51 1.2 thorpej return EINVAL; 52 1.2 thorpej 53 1.2 thorpej barrier->ptb_magic = _PT_BARRIER_MAGIC; 54 1.2 thorpej PTQ_INIT(&barrier->ptb_waiters); 55 1.2 thorpej barrier->ptb_initcount = count; 56 1.2 thorpej barrier->ptb_curcount = 0; 57 1.3 nathanw barrier->ptb_generation = 0; 58 1.2 thorpej return 0; 59 1.2 thorpej } 60 1.2 thorpej 61 1.2 thorpej int 62 1.2 thorpej pthread_barrier_destroy(pthread_barrier_t *barrier) 63 1.2 thorpej { 64 1.2 thorpej 65 1.21 kamil pthread__error(EINVAL, "Invalid barrier", 66 1.21 kamil barrier->ptb_magic == _PT_BARRIER_MAGIC); 67 1.19 ad if (barrier->ptb_curcount != 0) 68 1.2 thorpej return EBUSY; 69 1.21 kamil 70 1.21 kamil barrier->ptb_magic = _PT_BARRIER_DEAD; 71 1.21 kamil 72 1.2 thorpej return 0; 73 1.2 thorpej } 74 1.2 thorpej 75 1.2 thorpej int 76 1.2 thorpej pthread_barrier_wait(pthread_barrier_t *barrier) 77 1.2 thorpej { 78 1.18 ad pthread_mutex_t *interlock; 79 1.2 thorpej pthread_t self; 80 1.3 nathanw unsigned int gen; 81 1.2 thorpej 82 1.21 kamil pthread__error(EINVAL, "Invalid barrier", 83 1.21 kamil barrier->ptb_magic == _PT_BARRIER_MAGIC); 84 1.2 thorpej 85 1.2 thorpej /* 86 1.2 thorpej * A single arbitrary thread is supposed to return 87 1.2 thorpej * PTHREAD_BARRIER_SERIAL_THREAD, and everone else 88 1.2 thorpej * is supposed to return 0. Since pthread_barrier_wait() 89 1.2 thorpej * is not a cancellation point, this is trivial; we 90 1.2 thorpej * simply elect that the thread that causes the barrier 91 1.2 thorpej * to be satisfied gets the special return value. Note 92 1.2 thorpej * that this final thread does not actually need to block, 93 1.2 thorpej * but instead is responsible for waking everyone else up. 94 1.2 thorpej */ 95 1.19 ad self = pthread__self(); 96 1.19 ad interlock = pthread__hashlock(barrier); 97 1.19 ad pthread_mutex_lock(interlock); 98 1.2 thorpej if (barrier->ptb_curcount + 1 == barrier->ptb_initcount) { 99 1.8 ad barrier->ptb_generation++; 100 1.19 ad barrier->ptb_curcount = 0; 101 1.18 ad pthread__unpark_all(&barrier->ptb_waiters, self, 102 1.18 ad interlock); 103 1.18 ad pthread_mutex_unlock(interlock); 104 1.2 thorpej return PTHREAD_BARRIER_SERIAL_THREAD; 105 1.2 thorpej } 106 1.3 nathanw barrier->ptb_curcount++; 107 1.3 nathanw gen = barrier->ptb_generation; 108 1.19 ad for (;;) { 109 1.11 ad PTQ_INSERT_TAIL(&barrier->ptb_waiters, self, pt_sleep); 110 1.11 ad self->pt_sleepobj = &barrier->ptb_waiters; 111 1.18 ad (void)pthread__park(self, interlock, &barrier->ptb_waiters, 112 1.22 ad NULL, 0); 113 1.19 ad if (__predict_true(gen != barrier->ptb_generation)) { 114 1.19 ad break; 115 1.19 ad } 116 1.18 ad pthread_mutex_lock(interlock); 117 1.19 ad if (gen != barrier->ptb_generation) { 118 1.19 ad pthread_mutex_unlock(interlock); 119 1.19 ad break; 120 1.19 ad } 121 1.3 nathanw } 122 1.2 thorpej 123 1.2 thorpej return 0; 124 1.2 thorpej } 125 1.2 thorpej 126 1.20 christos #ifdef _PTHREAD_PSHARED 127 1.20 christos int 128 1.20 christos pthread_barrierattr_getpshared(const pthread_barrierattr_t * __restrict attr, 129 1.20 christos int * __restrict pshared) 130 1.20 christos { 131 1.20 christos 132 1.21 kamil pthread__error(EINVAL, "Invalid barrier attribute", 133 1.21 kamil attr->ptba_magic == _PT_BARRIERATTR_MAGIC); 134 1.21 kamil 135 1.20 christos *pshared = PTHREAD_PROCESS_PRIVATE; 136 1.20 christos return 0; 137 1.20 christos } 138 1.20 christos 139 1.20 christos int 140 1.20 christos pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) 141 1.20 christos { 142 1.20 christos 143 1.21 kamil pthread__error(EINVAL, "Invalid barrier attribute", 144 1.21 kamil attr->ptba_magic == _PT_BARRIERATTR_MAGIC); 145 1.21 kamil 146 1.20 christos switch(pshared) { 147 1.20 christos case PTHREAD_PROCESS_PRIVATE: 148 1.20 christos return 0; 149 1.20 christos case PTHREAD_PROCESS_SHARED: 150 1.20 christos return ENOSYS; 151 1.20 christos } 152 1.20 christos return EINVAL; 153 1.20 christos } 154 1.20 christos #endif 155 1.2 thorpej 156 1.2 thorpej int 157 1.2 thorpej pthread_barrierattr_init(pthread_barrierattr_t *attr) 158 1.2 thorpej { 159 1.2 thorpej 160 1.2 thorpej attr->ptba_magic = _PT_BARRIERATTR_MAGIC; 161 1.2 thorpej return 0; 162 1.2 thorpej } 163 1.2 thorpej 164 1.2 thorpej int 165 1.2 thorpej pthread_barrierattr_destroy(pthread_barrierattr_t *attr) 166 1.2 thorpej { 167 1.2 thorpej 168 1.21 kamil pthread__error(EINVAL, "Invalid barrier attribute", 169 1.21 kamil attr->ptba_magic == _PT_BARRIERATTR_MAGIC); 170 1.2 thorpej attr->ptba_magic = _PT_BARRIERATTR_DEAD; 171 1.2 thorpej return 0; 172 1.2 thorpej } 173