comparison third_party/libuv/src/win/thread.c @ 160:948de3f54cea

[ThirdParty] Added libuv
author June Park <parkjune1995@gmail.com>
date Wed, 14 Jan 2026 19:39:52 -0800
parents
children
comparison
equal deleted inserted replaced
159:05cf9467a1c3 160:948de3f54cea
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, &params, 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 }