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