|
160
|
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
|