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