Home | History | Annotate | Line # | Download | only in win
      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 }
    569