1 /* Copyright libuv project contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include "uv.h" 23 #include "uv-common.h" 24 25 #include <stdlib.h> 26 #ifndef _WIN32 27 #include <pthread.h> 28 #endif 29 30 #if defined(PTHREAD_BARRIER_SERIAL_THREAD) 31 STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); 32 #endif 33 34 /* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */ 35 #if defined(_AIX) || \ 36 defined(__OpenBSD__) || \ 37 !defined(PTHREAD_BARRIER_SERIAL_THREAD) 38 int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { 39 int rc; 40 #ifdef _WIN32 41 uv_barrier_t* b; 42 b = barrier; 43 44 if (barrier == NULL || count == 0) 45 return UV_EINVAL; 46 #else 47 struct _uv_barrier* b; 48 49 if (barrier == NULL || count == 0) 50 return UV_EINVAL; 51 52 b = uv__malloc(sizeof(*b)); 53 if (b == NULL) 54 return UV_ENOMEM; 55 #endif 56 57 b->in = 0; 58 b->out = 0; 59 b->threshold = count; 60 61 rc = uv_mutex_init(&b->mutex); 62 if (rc != 0) 63 goto error2; 64 65 /* TODO(vjnash): remove these uv_cond_t casts in v2. */ 66 rc = uv_cond_init((uv_cond_t*) &b->cond); 67 if (rc != 0) 68 goto error; 69 70 #ifndef _WIN32 71 barrier->b = b; 72 #endif 73 return 0; 74 75 error: 76 uv_mutex_destroy(&b->mutex); 77 error2: 78 #ifndef _WIN32 79 uv__free(b); 80 #endif 81 return rc; 82 } 83 84 85 int uv_barrier_wait(uv_barrier_t* barrier) { 86 int last; 87 #ifdef _WIN32 88 uv_barrier_t* b; 89 b = barrier; 90 #else 91 struct _uv_barrier* b; 92 93 if (barrier == NULL || barrier->b == NULL) 94 return UV_EINVAL; 95 96 b = barrier->b; 97 #endif 98 99 uv_mutex_lock(&b->mutex); 100 101 while (b->out != 0) 102 uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex); 103 104 if (++b->in == b->threshold) { 105 b->in = 0; 106 b->out = b->threshold; 107 uv_cond_broadcast((uv_cond_t*) &b->cond); 108 } else { 109 do 110 uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex); 111 while (b->in != 0); 112 } 113 114 last = (--b->out == 0); 115 if (last) 116 uv_cond_broadcast((uv_cond_t*) &b->cond); 117 118 uv_mutex_unlock(&b->mutex); 119 return last; 120 } 121 122 123 void uv_barrier_destroy(uv_barrier_t* barrier) { 124 #ifdef _WIN32 125 uv_barrier_t* b; 126 b = barrier; 127 #else 128 struct _uv_barrier* b; 129 b = barrier->b; 130 #endif 131 132 uv_mutex_lock(&b->mutex); 133 134 assert(b->in == 0); 135 while (b->out != 0) 136 uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex); 137 138 if (b->in != 0) 139 abort(); 140 141 uv_mutex_unlock(&b->mutex); 142 uv_mutex_destroy(&b->mutex); 143 uv_cond_destroy((uv_cond_t*) &b->cond); 144 145 #ifndef _WIN32 146 uv__free(barrier->b); 147 barrier->b = NULL; 148 #endif 149 } 150 151 #else 152 153 int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { 154 return UV__ERR(pthread_barrier_init(barrier, NULL, count)); 155 } 156 157 158 int uv_barrier_wait(uv_barrier_t* barrier) { 159 int rc; 160 161 rc = pthread_barrier_wait(barrier); 162 if (rc != 0) 163 if (rc != PTHREAD_BARRIER_SERIAL_THREAD) 164 abort(); 165 166 return rc == PTHREAD_BARRIER_SERIAL_THREAD; 167 } 168 169 170 void uv_barrier_destroy(uv_barrier_t* barrier) { 171 if (pthread_barrier_destroy(barrier)) 172 abort(); 173 } 174 175 #endif 176