From abc9767034d7c065e6a861cc398a580d0f94e24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 25 Mar 2024 11:57:52 +0100 Subject: [PATCH] win: simplify uv_once implementation * win: simplify uv_once implementation InitOnceExecuteOnce is available in Windows >= Vista. Ref: https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initonceexecuteonce --- include/uv/win.h | 4 ++-- src/win/thread.c | 44 +++++++++++--------------------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index f4adaa21..12ac53b4 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -290,8 +290,8 @@ typedef struct { #define UV_ONCE_INIT { 0, NULL } typedef struct uv_once_s { - unsigned char ran; - HANDLE event; + unsigned char unused; + INIT_ONCE init_once; } uv_once_t; /* Platform-specific definitions for uv_spawn support. */ diff --git a/src/win/thread.c b/src/win/thread.c index 57c25e8f..bf39b886 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -32,45 +32,23 @@ #include "uv.h" #include "internal.h" -static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { - DWORD result; - HANDLE existing_event, created_event; +typedef void (*uv__once_cb)(void); - created_event = CreateEvent(NULL, 1, 0, NULL); - if (created_event == 0) { - /* Could fail in a low-memory situation? */ - uv_fatal_error(GetLastError(), "CreateEvent"); - } +typedef struct { + uv__once_cb callback; +} uv__once_data_t; - existing_event = InterlockedCompareExchangePointer(&guard->event, - created_event, - NULL); +static BOOL WINAPI uv__once_inner(INIT_ONCE *once, void* param, void** context) { + uv__once_data_t* data = param; - if (existing_event == NULL) { - /* We won the race */ - callback(); + data->callback(); - result = SetEvent(created_event); - assert(result); - guard->ran = 1; - - } else { - /* We lost the race. Destroy the event we created and wait for the existing - * one to become signaled. */ - CloseHandle(created_event); - result = WaitForSingleObject(existing_event, INFINITE); - assert(result == WAIT_OBJECT_0); - } + return TRUE; } - -void uv_once(uv_once_t* guard, void (*callback)(void)) { - /* Fast case - avoid WaitForSingleObject. */ - if (guard->ran) { - return; - } - - uv__once_inner(guard, callback); +void uv_once(uv_once_t* guard, uv__once_cb callback) { + uv__once_data_t data = { .callback = callback }; + InitOnceExecuteOnce(&guard->init_once, uv__once_inner, (void*) &data, NULL); }