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 } 569