diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index 34246a8f..99537347 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -44,6 +44,9 @@ typedef struct { typedef int uv_file; +#define UV_ONCE_INIT PTHREAD_ONCE_INIT + +typedef pthread_once_t uv_once_t; typedef pthread_t uv_thread_t; typedef pthread_mutex_t uv_mutex_t; typedef pthread_rwlock_t uv_rwlock_t; diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index a87ede73..b4b89096 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -152,6 +152,16 @@ typedef union { } fallback_; } uv_rwlock_t; +#define UV_ONCE_INIT { 0, NULL, NULL } + +typedef struct uv_once_s { + unsigned char ran; + /* The actual event handle must be aligned to sizeof(HANDLE), so in */ + /* practice it might overlap padding a little. */ + HANDLE event; + HANDLE padding; +} uv_once_t; + /* Platform-specific definitions for uv_dlopen support. */ typedef HMODULE uv_lib_t; #define UV_DYNAMIC FAR WINAPI diff --git a/include/uv.h b/include/uv.h index 4d2417c5..7e089ef7 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1339,6 +1339,12 @@ UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); +/* Runs a function once and only once. Concurrent calls to uv_once() with the + * same guard will block all callers except one (it's unspecified which one). + * The guard should be initialized statically with the UV_ONCE_INIT macro. + */ +UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void)); + UV_EXTERN int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg); UV_EXTERN int uv_thread_join(uv_thread_t *tid); diff --git a/src/unix/thread.c b/src/unix/thread.c index 3cf9ac80..9a6b3d1b 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -151,3 +151,8 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { CHECK(pthread_rwlock_unlock(rwlock)); } + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + CHECK(pthread_once(guard, callback)); +} diff --git a/src/win/internal.h b/src/win/internal.h index deb8972c..e7d6c974 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -343,22 +343,4 @@ extern int uv_allow_ipv6; extern struct sockaddr_in uv_addr_ip4_any_; extern struct sockaddr_in6 uv_addr_ip6_any_; - -/* - * Threads and synchronization - */ -typedef struct uv_once_s { - unsigned char ran; - /* The actual event handle must be aligned to sizeof(HANDLE), so in */ - /* practice it might overlap padding a little. */ - HANDLE event; - HANDLE padding; -} uv_once_t; - -#define UV_ONCE_INIT \ - { 0, NULL, NULL } - -void uv_once(uv_once_t* guard, void (*callback)(void)); - - #endif /* UV_WIN_INTERNAL_H_ */