blob: 01b8140885298804a58bf4d29aa3eaf724e55c52 [file] [log] [blame]
Ben Noordhuis1b2d3332011-11-18 12:07:011/* Copyright Joyent, Inc. and other Node 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
Ben Noordhuis1b2d3332011-11-18 12:07:0122#include <assert.h>
23
Ben Noordhuis039fac62012-05-17 05:13:2924#include "uv.h"
25#include "internal.h"
26
27
Ben Noordhuis1b2d3332011-11-18 12:07:0128#define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL)
29
30#ifdef _MSC_VER /* msvc */
31# define inline __inline
32# define NOINLINE __declspec (noinline)
33#else /* gcc */
34# define inline inline
35# define NOINLINE __attribute__ ((noinline))
36#endif
37
38
39inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock);
40inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock);
41inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock);
42inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock);
43inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock);
44inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock);
45inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock);
46inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock);
47
48inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock);
49inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock);
50inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock);
51inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock);
52inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock);
53inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock);
54inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock);
55inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock);
56
57
58static NOINLINE void uv__once_inner(uv_once_t* guard,
59 void (*callback)(void)) {
60 DWORD result;
61 HANDLE existing_event, created_event;
62 HANDLE* event_ptr;
63
64 /* Fetch and align event_ptr */
65 event_ptr = (HANDLE*) (((uintptr_t) &guard->event + (sizeof(HANDLE) - 1)) &
66 ~(sizeof(HANDLE) - 1));
67
68 created_event = CreateEvent(NULL, 1, 0, NULL);
69 if (created_event == 0) {
70 /* Could fail in a low-memory situation? */
71 uv_fatal_error(GetLastError(), "CreateEvent");
72 }
73
74 existing_event = InterlockedCompareExchangePointer(event_ptr,
75 created_event,
76 NULL);
77
78 if (existing_event == NULL) {
79 /* We won the race */
80 callback();
81
82 result = SetEvent(created_event);
83 assert(result);
84 guard->ran = 1;
85
86 } else {
87 /* We lost the race. Destroy the event we created and wait for the */
88 /* existing one to become signaled. */
89 CloseHandle(created_event);
90 result = WaitForSingleObject(existing_event, INFINITE);
91 assert(result == WAIT_OBJECT_0);
92 }
93}
94
95
96void uv_once(uv_once_t* guard, void (*callback)(void)) {
97 /* Fast case - avoid WaitForSingleObject. */
98 if (guard->ran) {
99 return;
100 }
101
102 uv__once_inner(guard, callback);
103}
104
Igor Zinkovskyda3356b2011-12-15 23:56:42105
106int uv_thread_join(uv_thread_t *tid) {
107 if (WaitForSingleObject(*tid, INFINITE))
108 return -1;
109 else {
110 CloseHandle(*tid);
111 *tid = 0;
112 return 0;
113 }
114}
115
116
Ben Noordhuis1b2d3332011-11-18 12:07:01117int uv_mutex_init(uv_mutex_t* mutex) {
118 InitializeCriticalSection(mutex);
119 return 0;
120}
121
122
123void uv_mutex_destroy(uv_mutex_t* mutex) {
124 DeleteCriticalSection(mutex);
125}
126
127
128void uv_mutex_lock(uv_mutex_t* mutex) {
129 EnterCriticalSection(mutex);
130}
131
132
133int uv_mutex_trylock(uv_mutex_t* mutex) {
134 if (TryEnterCriticalSection(mutex))
135 return 0;
136 else
137 return -1;
138}
139
140
141void uv_mutex_unlock(uv_mutex_t* mutex) {
142 LeaveCriticalSection(mutex);
143}
144
145
146int uv_rwlock_init(uv_rwlock_t* rwlock) {
147 if (HAVE_SRWLOCK_API())
148 return uv__rwlock_srwlock_init(rwlock);
149 else
150 return uv__rwlock_fallback_init(rwlock);
151}
152
153
154void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
155 if (HAVE_SRWLOCK_API())
156 uv__rwlock_srwlock_destroy(rwlock);
157 else
158 uv__rwlock_fallback_destroy(rwlock);
159}
160
161
162void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
163 if (HAVE_SRWLOCK_API())
164 uv__rwlock_srwlock_rdlock(rwlock);
165 else
166 uv__rwlock_fallback_rdlock(rwlock);
167}
168
169
170int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
171 if (HAVE_SRWLOCK_API())
172 return uv__rwlock_srwlock_tryrdlock(rwlock);
173 else
174 return uv__rwlock_fallback_tryrdlock(rwlock);
175}
176
177
178void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
179 if (HAVE_SRWLOCK_API())
180 uv__rwlock_srwlock_rdunlock(rwlock);
181 else
182 uv__rwlock_fallback_rdunlock(rwlock);
183}
184
185
186void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
187 if (HAVE_SRWLOCK_API())
188 uv__rwlock_srwlock_wrlock(rwlock);
189 else
190 uv__rwlock_fallback_wrlock(rwlock);
191}
192
193
194int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
195 if (HAVE_SRWLOCK_API())
196 return uv__rwlock_srwlock_trywrlock(rwlock);
197 else
198 return uv__rwlock_fallback_trywrlock(rwlock);
199}
200
201
202void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
203 if (HAVE_SRWLOCK_API())
204 uv__rwlock_srwlock_wrunlock(rwlock);
205 else
206 uv__rwlock_fallback_wrunlock(rwlock);
207}
208
209
210inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) {
211 pInitializeSRWLock(&rwlock->srwlock_);
212 return 0;
213}
214
215
216inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock) {
217 (void) rwlock;
218}
219
220
221inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock) {
222 pAcquireSRWLockShared(&rwlock->srwlock_);
223}
224
225
226inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock) {
227 if (pTryAcquireSRWLockShared(&rwlock->srwlock_))
228 return 0;
229 else
230 return -1;
231}
232
233
234inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock) {
235 pReleaseSRWLockShared(&rwlock->srwlock_);
236}
237
238
239inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock) {
240 pAcquireSRWLockExclusive(&rwlock->srwlock_);
241}
242
243
244inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock) {
245 if (pTryAcquireSRWLockExclusive(&rwlock->srwlock_))
246 return 0;
247 else
248 return -1;
249}
250
251
252inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) {
253 pReleaseSRWLockExclusive(&rwlock->srwlock_);
254}
255
256
257inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) {
258 if (uv_mutex_init(&rwlock->fallback_.read_mutex_))
259 return -1;
260
261 if (uv_mutex_init(&rwlock->fallback_.write_mutex_)) {
262 uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
263 return -1;
264 }
265
266 rwlock->fallback_.num_readers_ = 0;
267
268 return 0;
269}
270
271
272inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) {
273 uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
274 uv_mutex_destroy(&rwlock->fallback_.write_mutex_);
275}
276
277
278inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) {
279 uv_mutex_lock(&rwlock->fallback_.read_mutex_);
280
281 if (++rwlock->fallback_.num_readers_ == 1)
282 uv_mutex_lock(&rwlock->fallback_.write_mutex_);
283
284 uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
285}
286
287
288inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) {
289 int ret;
290
291 ret = -1;
292
293 if (uv_mutex_trylock(&rwlock->fallback_.read_mutex_))
294 goto out;
295
296 if (rwlock->fallback_.num_readers_ == 0)
297 ret = uv_mutex_trylock(&rwlock->fallback_.write_mutex_);
298 else
299 ret = 0;
300
301 if (ret == 0)
302 rwlock->fallback_.num_readers_++;
303
304 uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
305
306out:
307 return ret;
308}
309
310
311inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) {
312 uv_mutex_lock(&rwlock->fallback_.read_mutex_);
313
314 if (--rwlock->fallback_.num_readers_ == 0)
315 uv_mutex_unlock(&rwlock->fallback_.write_mutex_);
316
317 uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
318}
319
320
321inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) {
322 uv_mutex_lock(&rwlock->fallback_.write_mutex_);
323}
324
325
326inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) {
327 return uv_mutex_trylock(&rwlock->fallback_.write_mutex_);
328}
329
330
331inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) {
332 uv_mutex_unlock(&rwlock->fallback_.write_mutex_);
333}