[PATCH v2 1/2] compat/win32/pthread: add pthread_once()
From: Matheus Tavares <hidden>
Date: 2020-06-26 21:54:18
Subsystem:
the rest · Maintainer:
Linus Torvalds
Add pthread_once() emulation for Windows. This function provides an easy way to do thread-safe one-time initializations in multithreaded code. It will be used in the next commit to make hash_to_hex_algop() thread-safe. The pthread_once() implementation added comes from libav (https://git.libav.org/?p=libav.git), commit b22693b ("w32pthreads: Add pthread_once emulation", 2015-10-07). The code is licensed under LGPLv2.1 which is compatible with GPLv2. Only the section for support on Windows Vista+ has been ported, as that's the minimum version required to build Git for Windows. Also, the code was modified to (1) check and return error codes; and (2) do not call InitOnceComplete() again after a successful initialization, as that results in an error. Signed-off-by: Matheus Tavares <redacted> --- compat/win32/pthread.c | 18 ++++++++++++++++++ compat/win32/pthread.h | 5 +++++ thread-utils.c | 11 +++++++++++ thread-utils.h | 7 +++++++ 4 files changed, 41 insertions(+)
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 2e7eead42c..cb32f8c504 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c@@ -56,3 +56,21 @@ pthread_t pthread_self(void) t.tid = GetCurrentThreadId(); return t; } + +/* Adapted from libav's compat/w32pthreads.h. */ +int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + BOOL pending = FALSE; + int ret = 0; + + if (!InitOnceBeginInitialize(once_control, 0, &pending, NULL)) { + ret = err_win_to_posix(GetLastError()); + } else if (pending) { + init_routine(); + if (!InitOnceComplete(once_control, 0, NULL)) + ret = err_win_to_posix(GetLastError()); + } + + /* POSIX doesn't allow pthread_once() to return EINTR */ + return ret == EINTR ? EIO : ret; +}
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index 737983d00b..c50f1e89c7 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h@@ -40,6 +40,11 @@ typedef int pthread_mutexattr_t; #define pthread_cond_signal WakeConditionVariable #define pthread_cond_broadcast WakeAllConditionVariable +#define pthread_once_t INIT_ONCE + +#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT +int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); + /* * Simple thread creation implementation using pthread API */
diff --git a/thread-utils.c b/thread-utils.c
index 5329845691..937deb3f2e 100644
--- a/thread-utils.c
+++ b/thread-utils.c@@ -122,4 +122,15 @@ int dummy_pthread_join(pthread_t pthread, void **retval) return ENOSYS; } +int nothreads_pthread_once(pthread_once_t *once_control, + void (*init_routine)(void)) +{ + if (*once_control == 1) + return 0; + + init_routine(); + *once_control = 1; + return 0; +} + #endif
diff --git a/thread-utils.h b/thread-utils.h
index 4961487ed9..8f9786217a 100644
--- a/thread-utils.h
+++ b/thread-utils.h@@ -19,6 +19,7 @@ #define pthread_mutex_t int #define pthread_cond_t int #define pthread_key_t int +#define pthread_once_t int #define pthread_mutex_init(mutex, attr) dummy_pthread_init(mutex) #define pthread_mutex_lock(mutex)
@@ -48,6 +49,12 @@ int dummy_pthread_join(pthread_t pthread, void **retval); int dummy_pthread_init(void *); +#define PTHREAD_ONCE_INIT 0 +#define pthread_once(once, routine) nothreads_pthread_once(once, routine) + +int nothreads_pthread_once(pthread_once_t *once_control, + void (*init_routine)(void)); + #endif int online_cpus(void);
--
2.26.2