|
160
|
1 /* 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
|
|
|
22 #include <assert.h>
|
|
|
23 #include <limits.h>
|
|
|
24 #include <stdlib.h>
|
|
|
25
|
|
|
26 #if defined(__MINGW64_VERSION_MAJOR)
|
|
|
27 /* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
|
|
|
28 * require this header in some versions of mingw64. */
|
|
|
29 #include <intrin.h>
|
|
|
30 #endif
|
|
|
31
|
|
|
32 #include "uv.h"
|
|
|
33 #include "internal.h"
|
|
|
34
|
|
|
35 typedef void (*uv__once_cb)(void);
|
|
|
36
|
|
|
37 typedef struct {
|
|
|
38 uv__once_cb callback;
|
|
|
39 } uv__once_data_t;
|
|
|
40
|
|
|
41 static BOOL WINAPI uv__once_inner(INIT_ONCE *once, void* param, void** context) {
|
|
|
42 uv__once_data_t* data = param;
|
|
|
43
|
|
|
44 data->callback();
|
|
|
45
|
|
|
46 return TRUE;
|
|
|
47 }
|
|
|
48
|
|
|
49 void uv_once(uv_once_t* guard, uv__once_cb callback) {
|
|
|
50 uv__once_data_t data = { .callback = callback };
|
|
|
51 InitOnceExecuteOnce(&guard->init_once, uv__once_inner, (void*) &data, NULL);
|
|
|
52 }
|
|
|
53
|
|
|
54
|
|
|
55 /* Verify that uv_thread_t can be stored in a TLS slot. */
|
|
|
56 STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
|
|
|
57
|
|
|
58 static uv_key_t uv__current_thread_key;
|
|
|
59 static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
|
|
|
60 static uv_once_t uv__thread_name_once = UV_ONCE_INIT;
|
|
|
61 HRESULT (WINAPI *pGetThreadDescription)(HANDLE, PWSTR*);
|
|
|
62 HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR);
|
|
|
63
|
|
|
64
|
|
|
65 static void uv__init_current_thread_key(void) {
|
|
|
66 if (uv_key_create(&uv__current_thread_key))
|
|
|
67 abort();
|
|
|
68 }
|
|
|
69
|
|
|
70
|
|
|
71 struct thread_ctx {
|
|
|
72 void (*entry)(void* arg);
|
|
|
73 void* arg;
|
|
|
74 uv_thread_t self;
|
|
|
75 };
|
|
|
76
|
|
|
77
|
|
|
78 static UINT __stdcall uv__thread_start(void* arg) {
|
|
|
79 struct thread_ctx *ctx_p;
|
|
|
80 struct thread_ctx ctx;
|
|
|
81
|
|
|
82 ctx_p = arg;
|
|
|
83 ctx = *ctx_p;
|
|
|
84 uv__free(ctx_p);
|
|
|
85
|
|
|
86 uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
|
|
|
87 uv_key_set(&uv__current_thread_key, ctx.self);
|
|
|
88
|
|
|
89 ctx.entry(ctx.arg);
|
|
|
90
|
|
|
91 return 0;
|
|
|
92 }
|
|
|
93
|
|
|
94
|
|
|
95 int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
|
|
96 uv_thread_options_t params;
|
|
|
97 params.flags = UV_THREAD_NO_FLAGS;
|
|
|
98 return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
|
|
99 }
|
|
|
100
|
|
|
101
|
|
|
102 int uv_thread_detach(uv_thread_t *tid) {
|
|
|
103 if (CloseHandle(*tid) == 0)
|
|
|
104 return uv_translate_sys_error(GetLastError());
|
|
|
105
|
|
|
106 return 0;
|
|
|
107 }
|
|
|
108
|
|
|
109
|
|
|
110 int uv_thread_create_ex(uv_thread_t* tid,
|
|
|
111 const uv_thread_options_t* params,
|
|
|
112 void (*entry)(void *arg),
|
|
|
113 void *arg) {
|
|
|
114 struct thread_ctx* ctx;
|
|
|
115 int err;
|
|
|
116 HANDLE thread;
|
|
|
117 SYSTEM_INFO sysinfo;
|
|
|
118 size_t stack_size;
|
|
|
119 size_t pagesize;
|
|
|
120
|
|
|
121 stack_size =
|
|
|
122 params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
|
|
123
|
|
|
124 if (stack_size != 0) {
|
|
|
125 GetNativeSystemInfo(&sysinfo);
|
|
|
126 pagesize = (size_t)sysinfo.dwPageSize;
|
|
|
127 /* Round up to the nearest page boundary. */
|
|
|
128 stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
|
|
129
|
|
|
130 if ((unsigned)stack_size != stack_size)
|
|
|
131 return UV_EINVAL;
|
|
|
132 }
|
|
|
133
|
|
|
134 ctx = uv__malloc(sizeof(*ctx));
|
|
|
135 if (ctx == NULL)
|
|
|
136 return UV_ENOMEM;
|
|
|
137
|
|
|
138 ctx->entry = entry;
|
|
|
139 ctx->arg = arg;
|
|
|
140
|
|
|
141 /* Create the thread in suspended state so we have a chance to pass
|
|
|
142 * its own creation handle to it */
|
|
|
143 thread = (HANDLE) _beginthreadex(NULL,
|
|
|
144 (unsigned)stack_size,
|
|
|
145 uv__thread_start,
|
|
|
146 ctx,
|
|
|
147 CREATE_SUSPENDED,
|
|
|
148 NULL);
|
|
|
149 if (thread == NULL) {
|
|
|
150 err = errno;
|
|
|
151 uv__free(ctx);
|
|
|
152 } else {
|
|
|
153 err = 0;
|
|
|
154 *tid = thread;
|
|
|
155 ctx->self = thread;
|
|
|
156 ResumeThread(thread);
|
|
|
157 }
|
|
|
158
|
|
|
159 switch (err) {
|
|
|
160 case 0:
|
|
|
161 return 0;
|
|
|
162 case EACCES:
|
|
|
163 return UV_EACCES;
|
|
|
164 case EAGAIN:
|
|
|
165 return UV_EAGAIN;
|
|
|
166 case EINVAL:
|
|
|
167 return UV_EINVAL;
|
|
|
168 }
|
|
|
169
|
|
|
170 return UV_EIO;
|
|
|
171 }
|
|
|
172
|
|
|
173 int uv_thread_setaffinity(uv_thread_t* tid,
|
|
|
174 char* cpumask,
|
|
|
175 char* oldmask,
|
|
|
176 size_t mask_size) {
|
|
|
177 int i;
|
|
|
178 HANDLE hproc;
|
|
|
179 DWORD_PTR procmask;
|
|
|
180 DWORD_PTR sysmask;
|
|
|
181 DWORD_PTR threadmask;
|
|
|
182 DWORD_PTR oldthreadmask;
|
|
|
183 int cpumasksize;
|
|
|
184
|
|
|
185 cpumasksize = uv_cpumask_size();
|
|
|
186 assert(cpumasksize > 0);
|
|
|
187 if (mask_size < (size_t)cpumasksize)
|
|
|
188 return UV_EINVAL;
|
|
|
189
|
|
|
190 hproc = GetCurrentProcess();
|
|
|
191 if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
|
|
|
192 return uv_translate_sys_error(GetLastError());
|
|
|
193
|
|
|
194 threadmask = 0;
|
|
|
195 for (i = 0; i < cpumasksize; i++) {
|
|
|
196 if (cpumask[i]) {
|
|
|
197 if (procmask & (1 << i))
|
|
|
198 threadmask |= 1 << i;
|
|
|
199 else
|
|
|
200 return UV_EINVAL;
|
|
|
201 }
|
|
|
202 }
|
|
|
203
|
|
|
204 oldthreadmask = SetThreadAffinityMask(*tid, threadmask);
|
|
|
205 if (oldthreadmask == 0)
|
|
|
206 return uv_translate_sys_error(GetLastError());
|
|
|
207
|
|
|
208 if (oldmask != NULL) {
|
|
|
209 for (i = 0; i < cpumasksize; i++)
|
|
|
210 oldmask[i] = (oldthreadmask >> i) & 1;
|
|
|
211 }
|
|
|
212
|
|
|
213 return 0;
|
|
|
214 }
|
|
|
215
|
|
|
216 int uv_thread_getaffinity(uv_thread_t* tid,
|
|
|
217 char* cpumask,
|
|
|
218 size_t mask_size) {
|
|
|
219 int i;
|
|
|
220 HANDLE hproc;
|
|
|
221 DWORD_PTR procmask;
|
|
|
222 DWORD_PTR sysmask;
|
|
|
223 DWORD_PTR threadmask;
|
|
|
224 int cpumasksize;
|
|
|
225
|
|
|
226 cpumasksize = uv_cpumask_size();
|
|
|
227 assert(cpumasksize > 0);
|
|
|
228 if (mask_size < (size_t)cpumasksize)
|
|
|
229 return UV_EINVAL;
|
|
|
230
|
|
|
231 hproc = GetCurrentProcess();
|
|
|
232 if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
|
|
|
233 return uv_translate_sys_error(GetLastError());
|
|
|
234
|
|
|
235 threadmask = SetThreadAffinityMask(*tid, procmask);
|
|
|
236 if (threadmask == 0 || SetThreadAffinityMask(*tid, threadmask) == 0)
|
|
|
237 return uv_translate_sys_error(GetLastError());
|
|
|
238
|
|
|
239 for (i = 0; i < cpumasksize; i++)
|
|
|
240 cpumask[i] = (threadmask >> i) & 1;
|
|
|
241
|
|
|
242 return 0;
|
|
|
243 }
|
|
|
244
|
|
|
245 int uv_thread_getcpu(void) {
|
|
|
246 return GetCurrentProcessorNumber();
|
|
|
247 }
|
|
|
248
|
|
|
249 uv_thread_t uv_thread_self(void) {
|
|
|
250 uv_thread_t key;
|
|
|
251 uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
|
|
|
252 key = uv_key_get(&uv__current_thread_key);
|
|
|
253 if (key == NULL) {
|
|
|
254 /* If the thread wasn't started by uv_thread_create (such as the main
|
|
|
255 * thread), we assign an id to it now. */
|
|
|
256 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
|
|
|
257 GetCurrentProcess(), &key, 0,
|
|
|
258 FALSE, DUPLICATE_SAME_ACCESS)) {
|
|
|
259 uv_fatal_error(GetLastError(), "DuplicateHandle");
|
|
|
260 }
|
|
|
261 uv_key_set(&uv__current_thread_key, key);
|
|
|
262 }
|
|
|
263 return key;
|
|
|
264 }
|
|
|
265
|
|
|
266
|
|
|
267 int uv_thread_join(uv_thread_t *tid) {
|
|
|
268 if (WaitForSingleObject(*tid, INFINITE))
|
|
|
269 return uv_translate_sys_error(GetLastError());
|
|
|
270 else {
|
|
|
271 CloseHandle(*tid);
|
|
|
272 *tid = 0;
|
|
|
273 MemoryBarrier(); /* For feature parity with pthread_join(). */
|
|
|
274 return 0;
|
|
|
275 }
|
|
|
276 }
|
|
|
277
|
|
|
278
|
|
|
279 int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
|
|
|
280 return *t1 == *t2;
|
|
|
281 }
|
|
|
282
|
|
|
283
|
|
|
284 static void uv__thread_name_init_once(void) {
|
|
|
285 HMODULE m;
|
|
|
286
|
|
|
287 m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll");
|
|
|
288 if (m != NULL) {
|
|
|
289 pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription");
|
|
|
290 pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription");
|
|
|
291 }
|
|
|
292 }
|
|
|
293
|
|
|
294
|
|
|
295 int uv_thread_setname(const char* name) {
|
|
|
296 HRESULT hr;
|
|
|
297 WCHAR* namew;
|
|
|
298 int err;
|
|
|
299 char namebuf[UV_PTHREAD_MAX_NAMELEN_NP];
|
|
|
300
|
|
|
301 uv_once(&uv__thread_name_once, uv__thread_name_init_once);
|
|
|
302
|
|
|
303 if (pSetThreadDescription == NULL)
|
|
|
304 return UV_ENOSYS;
|
|
|
305
|
|
|
306 if (name == NULL)
|
|
|
307 return UV_EINVAL;
|
|
|
308
|
|
|
309 strncpy(namebuf, name, sizeof(namebuf) - 1);
|
|
|
310 namebuf[sizeof(namebuf) - 1] = '\0';
|
|
|
311
|
|
|
312 namew = NULL;
|
|
|
313 err = uv__convert_utf8_to_utf16(namebuf, &namew);
|
|
|
314 if (err)
|
|
|
315 return err;
|
|
|
316
|
|
|
317 hr = pSetThreadDescription(GetCurrentThread(), namew);
|
|
|
318 uv__free(namew);
|
|
|
319 if (FAILED(hr))
|
|
|
320 return uv_translate_sys_error(HRESULT_CODE(hr));
|
|
|
321
|
|
|
322 return 0;
|
|
|
323 }
|
|
|
324
|
|
|
325
|
|
|
326 int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) {
|
|
|
327 HRESULT hr;
|
|
|
328 WCHAR* namew;
|
|
|
329 char* thread_name;
|
|
|
330 size_t buf_size;
|
|
|
331 int r;
|
|
|
332 DWORD exit_code;
|
|
|
333
|
|
|
334 uv_once(&uv__thread_name_once, uv__thread_name_init_once);
|
|
|
335
|
|
|
336 if (pGetThreadDescription == NULL)
|
|
|
337 return UV_ENOSYS;
|
|
|
338
|
|
|
339 if (name == NULL || size == 0)
|
|
|
340 return UV_EINVAL;
|
|
|
341
|
|
|
342 if (tid == NULL || *tid == NULL)
|
|
|
343 return UV_EINVAL;
|
|
|
344
|
|
|
345 /* Check if the thread handle is valid */
|
|
|
346 if (!GetExitCodeThread(*tid, &exit_code) || exit_code != STILL_ACTIVE)
|
|
|
347 return UV_ENOENT;
|
|
|
348
|
|
|
349 namew = NULL;
|
|
|
350 thread_name = NULL;
|
|
|
351 hr = pGetThreadDescription(*tid, &namew);
|
|
|
352 if (FAILED(hr))
|
|
|
353 return uv_translate_sys_error(HRESULT_CODE(hr));
|
|
|
354
|
|
|
355 buf_size = size;
|
|
|
356 r = uv__copy_utf16_to_utf8(namew, -1, name, &buf_size);
|
|
|
357 if (r == UV_ENOBUFS) {
|
|
|
358 r = uv__convert_utf16_to_utf8(namew, wcslen(namew), &thread_name);
|
|
|
359 if (r == 0) {
|
|
|
360 uv__strscpy(name, thread_name, size);
|
|
|
361 uv__free(thread_name);
|
|
|
362 }
|
|
|
363 }
|
|
|
364
|
|
|
365 LocalFree(namew);
|
|
|
366 return r;
|
|
|
367 }
|
|
|
368
|
|
|
369
|
|
|
370 int uv_mutex_init(uv_mutex_t* mutex) {
|
|
|
371 InitializeCriticalSection(mutex);
|
|
|
372 return 0;
|
|
|
373 }
|
|
|
374
|
|
|
375
|
|
|
376 int uv_mutex_init_recursive(uv_mutex_t* mutex) {
|
|
|
377 return uv_mutex_init(mutex);
|
|
|
378 }
|
|
|
379
|
|
|
380
|
|
|
381 void uv_mutex_destroy(uv_mutex_t* mutex) {
|
|
|
382 DeleteCriticalSection(mutex);
|
|
|
383 }
|
|
|
384
|
|
|
385
|
|
|
386 void uv_mutex_lock(uv_mutex_t* mutex) {
|
|
|
387 EnterCriticalSection(mutex);
|
|
|
388 }
|
|
|
389
|
|
|
390
|
|
|
391 int uv_mutex_trylock(uv_mutex_t* mutex) {
|
|
|
392 if (TryEnterCriticalSection(mutex))
|
|
|
393 return 0;
|
|
|
394 else
|
|
|
395 return UV_EBUSY;
|
|
|
396 }
|
|
|
397
|
|
|
398
|
|
|
399 void uv_mutex_unlock(uv_mutex_t* mutex) {
|
|
|
400 LeaveCriticalSection(mutex);
|
|
|
401 }
|
|
|
402
|
|
|
403 /* Ensure that the ABI for this type remains stable in v1.x */
|
|
|
404 #ifdef _WIN64
|
|
|
405 STATIC_ASSERT(sizeof(uv_rwlock_t) == 80);
|
|
|
406 #else
|
|
|
407 STATIC_ASSERT(sizeof(uv_rwlock_t) == 48);
|
|
|
408 #endif
|
|
|
409
|
|
|
410 int uv_rwlock_init(uv_rwlock_t* rwlock) {
|
|
|
411 memset(rwlock, 0, sizeof(*rwlock));
|
|
|
412 InitializeSRWLock(&rwlock->read_write_lock_);
|
|
|
413
|
|
|
414 return 0;
|
|
|
415 }
|
|
|
416
|
|
|
417
|
|
|
418 void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
|
|
|
419 /* SRWLock does not need explicit destruction so long as there are no waiting threads
|
|
|
420 See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */
|
|
|
421 }
|
|
|
422
|
|
|
423
|
|
|
424 void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
|
|
|
425 AcquireSRWLockShared(&rwlock->read_write_lock_);
|
|
|
426 }
|
|
|
427
|
|
|
428
|
|
|
429 int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
|
|
430 if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_))
|
|
|
431 return UV_EBUSY;
|
|
|
432
|
|
|
433 return 0;
|
|
|
434 }
|
|
|
435
|
|
|
436
|
|
|
437 void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
|
|
|
438 ReleaseSRWLockShared(&rwlock->read_write_lock_);
|
|
|
439 }
|
|
|
440
|
|
|
441
|
|
|
442 void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
|
|
|
443 AcquireSRWLockExclusive(&rwlock->read_write_lock_);
|
|
|
444 }
|
|
|
445
|
|
|
446
|
|
|
447 int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
|
|
448 if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_))
|
|
|
449 return UV_EBUSY;
|
|
|
450
|
|
|
451 return 0;
|
|
|
452 }
|
|
|
453
|
|
|
454
|
|
|
455 void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
|
|
|
456 ReleaseSRWLockExclusive(&rwlock->read_write_lock_);
|
|
|
457 }
|
|
|
458
|
|
|
459
|
|
|
460 int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
|
|
461 *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
|
|
|
462 if (*sem == NULL)
|
|
|
463 return uv_translate_sys_error(GetLastError());
|
|
|
464 else
|
|
|
465 return 0;
|
|
|
466 }
|
|
|
467
|
|
|
468
|
|
|
469 void uv_sem_destroy(uv_sem_t* sem) {
|
|
|
470 if (!CloseHandle(*sem))
|
|
|
471 abort();
|
|
|
472 }
|
|
|
473
|
|
|
474
|
|
|
475 void uv_sem_post(uv_sem_t* sem) {
|
|
|
476 if (!ReleaseSemaphore(*sem, 1, NULL))
|
|
|
477 abort();
|
|
|
478 }
|
|
|
479
|
|
|
480
|
|
|
481 void uv_sem_wait(uv_sem_t* sem) {
|
|
|
482 if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
|
|
|
483 abort();
|
|
|
484 }
|
|
|
485
|
|
|
486
|
|
|
487 int uv_sem_trywait(uv_sem_t* sem) {
|
|
|
488 DWORD r = WaitForSingleObject(*sem, 0);
|
|
|
489
|
|
|
490 if (r == WAIT_OBJECT_0)
|
|
|
491 return 0;
|
|
|
492
|
|
|
493 if (r == WAIT_TIMEOUT)
|
|
|
494 return UV_EAGAIN;
|
|
|
495
|
|
|
496 abort();
|
|
|
497 return -1; /* Satisfy the compiler. */
|
|
|
498 }
|
|
|
499
|
|
|
500
|
|
|
501 int uv_cond_init(uv_cond_t* cond) {
|
|
|
502 InitializeConditionVariable(&cond->cond_var);
|
|
|
503 return 0;
|
|
|
504 }
|
|
|
505
|
|
|
506
|
|
|
507 void uv_cond_destroy(uv_cond_t* cond) {
|
|
|
508 /* nothing to do */
|
|
|
509 (void) &cond;
|
|
|
510 }
|
|
|
511
|
|
|
512
|
|
|
513 void uv_cond_signal(uv_cond_t* cond) {
|
|
|
514 WakeConditionVariable(&cond->cond_var);
|
|
|
515 }
|
|
|
516
|
|
|
517
|
|
|
518 void uv_cond_broadcast(uv_cond_t* cond) {
|
|
|
519 WakeAllConditionVariable(&cond->cond_var);
|
|
|
520 }
|
|
|
521
|
|
|
522
|
|
|
523 void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
|
|
524 if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
|
|
|
525 abort();
|
|
|
526 }
|
|
|
527
|
|
|
528
|
|
|
529 int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
|
|
530 if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
|
|
|
531 return 0;
|
|
|
532 if (GetLastError() != ERROR_TIMEOUT)
|
|
|
533 abort();
|
|
|
534 return UV_ETIMEDOUT;
|
|
|
535 }
|
|
|
536
|
|
|
537
|
|
|
538 int uv_key_create(uv_key_t* key) {
|
|
|
539 key->tls_index = TlsAlloc();
|
|
|
540 if (key->tls_index == TLS_OUT_OF_INDEXES)
|
|
|
541 return UV_ENOMEM;
|
|
|
542 return 0;
|
|
|
543 }
|
|
|
544
|
|
|
545
|
|
|
546 void uv_key_delete(uv_key_t* key) {
|
|
|
547 if (TlsFree(key->tls_index) == FALSE)
|
|
|
548 abort();
|
|
|
549 key->tls_index = TLS_OUT_OF_INDEXES;
|
|
|
550 }
|
|
|
551
|
|
|
552
|
|
|
553 void* uv_key_get(uv_key_t* key) {
|
|
|
554 void* value;
|
|
|
555
|
|
|
556 value = TlsGetValue(key->tls_index);
|
|
|
557 if (value == NULL)
|
|
|
558 if (GetLastError() != ERROR_SUCCESS)
|
|
|
559 abort();
|
|
|
560
|
|
|
561 return value;
|
|
|
562 }
|
|
|
563
|
|
|
564
|
|
|
565 void uv_key_set(uv_key_t* key, void* value) {
|
|
|
566 if (TlsSetValue(key->tls_index, value) == FALSE)
|
|
|
567 abort();
|
|
|
568 }
|