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)
uv_barrier_init(uv_barrier_t * barrier,unsigned int count)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
uv_barrier_wait(uv_barrier_t * barrier)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
uv_barrier_destroy(uv_barrier_t * barrier)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
uv_barrier_init(uv_barrier_t * barrier,unsigned int count)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
uv_barrier_wait(uv_barrier_t * barrier)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
uv_barrier_destroy(uv_barrier_t * barrier)170 void uv_barrier_destroy(uv_barrier_t* barrier) {
171 if (pthread_barrier_destroy(barrier))
172 abort();
173 }
174
175 #endif
176