From 4fa73347e4dd5638afb37625345d548f11686c11 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Tue, 19 Mar 2024 18:57:03 -0700 Subject: [PATCH] Add portable equivalent to pthread_once. Also move DllMain to H5TSwin.c. Signed-off-by: Quincey Koziol --- src/CMakeLists.txt | 1 + src/H5.c | 59 ---------------------- src/H5TSint.c | 17 ++++--- src/H5TSonce.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ src/H5TSpkg.h | 18 +++---- src/H5TSprivate.h | 15 +++--- src/H5TSwin.c | 76 ++++++++++++++++++++++++---- src/Makefile.am | 4 +- 8 files changed, 214 insertions(+), 97 deletions(-) create mode 100644 src/H5TSonce.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index df302f8074f..52895563c96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -646,6 +646,7 @@ set (H5TS_SOURCES ${HDF5_SRC_DIR}/H5TSint.c ${HDF5_SRC_DIR}/H5TSkey.c ${HDF5_SRC_DIR}/H5TSmutex.c + ${HDF5_SRC_DIR}/H5TSonce.c ${HDF5_SRC_DIR}/H5TSpthread.c ${HDF5_SRC_DIR}/H5TSrwlock.c ${HDF5_SRC_DIR}/H5TStest.c diff --git a/src/H5.c b/src/H5.c index 75a5d1d2e8a..c923316fc7c 100644 --- a/src/H5.c +++ b/src/H5.c @@ -1258,62 +1258,3 @@ H5is_library_terminating(bool *is_terminating /*out*/) FUNC_LEAVE_API_NOINIT(ret_value) } /* end H5is_library_terminating() */ -#if defined(H5_HAVE_THREADSAFE) && defined(H5_BUILT_AS_DYNAMIC_LIB) && defined(H5_HAVE_WIN32_API) && \ - defined(H5_HAVE_WIN_THREADS) -/*------------------------------------------------------------------------- - * Function: DllMain - * - * Purpose: Handles various conditions in the library on Windows. - * - * NOTE: The main purpose of this is for handling Win32 thread cleanup - * on thread/process detach. - * - * Only enabled when the shared Windows library is built with - * thread safety enabled. - * - * Return: true on success, false on failure - * - *------------------------------------------------------------------------- - */ -BOOL WINAPI -DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) -{ - /* Don't add our function enter/leave macros since this function will be - * called before the library is initialized. - * - * NOTE: Do NOT call any CRT functions in DllMain! - * This includes any functions that are called by from here! - */ - - BOOL fOkay = true; - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - break; - - case DLL_PROCESS_DETACH: - break; - - case DLL_THREAD_ATTACH: -#ifdef H5_HAVE_WIN_THREADS - if (H5TS_win32_thread_enter() < 0) - fOkay = false; -#endif /* H5_HAVE_WIN_THREADS */ - break; - - case DLL_THREAD_DETACH: -#ifdef H5_HAVE_WIN_THREADS - if (H5TS_win32_thread_exit() < 0) - fOkay = false; -#endif /* H5_HAVE_WIN_THREADS */ - break; - - default: - /* Shouldn't get here */ - fOkay = false; - break; - } - - return fOkay; -} -#endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB && H5_HAVE_WIN_THREADS && H5_HAVE_THREADSAFE*/ diff --git a/src/H5TSint.c b/src/H5TSint.c index 0575cf59f76..2218ad8dad4 100644 --- a/src/H5TSint.c +++ b/src/H5TSint.c @@ -43,6 +43,12 @@ /* Local Macros */ /****************/ +#ifdef H5_HAVE_WIN_THREADS +#define H5TS_ONCE_INIT_FUNC H5TS__win32_process_enter +#else +#define H5TS_ONCE_INIT_FUNC H5TS__pthread_first_thread_init +#endif /* H5_HAVE_WIN_THREADS */ + /******************/ /* Local Typedefs */ /******************/ @@ -170,15 +176,10 @@ H5TS_api_lock(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY -#ifdef H5_HAVE_WIN_THREADS - /* Initialize the thread-safety code */ - if (H5_UNLIKELY(!H5_INIT_GLOBAL)) - InitOnceExecuteOnce(&H5TS_first_init_s, H5TS__win32_process_enter, NULL, NULL); -#else - /* Initialize the thread-safety code */ + /* Initialize the thread-safety code, once */ if (H5_UNLIKELY(!H5_INIT_GLOBAL)) - pthread_once(&H5TS_first_init_s, H5TS__pthread_first_thread_init); -#endif /* H5_HAVE_WIN_THREADS */ + if (H5_UNLIKELY(H5TS_once(&H5TS_first_init_s, H5TS_ONCE_INIT_FUNC) < 0)) + HGOTO_DONE(FAIL); /* Acquire the "attempt" mutex, increment the attempt lock count, release the lock */ if (H5_UNLIKELY(H5TS_mutex_lock(&H5TS_api_info_p.attempt_mutex))) diff --git a/src/H5TSonce.c b/src/H5TSonce.c new file mode 100644 index 00000000000..a0ee376c105 --- /dev/null +++ b/src/H5TSonce.c @@ -0,0 +1,121 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: This file contains support for thread-local 'once' operations, + * equivalent to the pthread 'pthread_once_t' type and capabilities. + * + * Note: Because this threadsafety framework operates outside the library, + * it does not use the error stack (although it does use error macros + * that don't push errors on a stack) and only uses the "namecheck only" + * FUNC_ENTER_* / FUNC_LEAVE_* macros. + */ + +/****************/ +/* Module Setup */ +/****************/ + +#include "H5TSmodule.h" /* This source code file is part of the H5TS module */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ + +#ifdef H5_HAVE_THREADSAFE + +/****************/ +/* Local Macros */ +/****************/ + +/******************/ +/* Local Typedefs */ +/******************/ + +/********************/ +/* Local Prototypes */ +/********************/ + +/*********************/ +/* Package Variables */ +/*********************/ + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + +/*******************/ +/* Local Variables */ +/*******************/ + +#ifdef H5_HAVE_WIN_THREADS +/*------------------------------------------------------------------------- + * Function: H5TS_once + * + * Purpose: Dynamic package initialization + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_once(H5TS_once_t *once, H5TS_once_init_func_t func) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Sanity check */ + if (H5_UNLIKELY(NULL == once || NULL == func)) + HGOTO_DONE(FAIL); + + /* Invoke the function, only once per process */ + if (H5_UNLIKELY(0 == InitOnceExecuteOnce(once, func, NULL, NULL))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_once() */ +#else +/*------------------------------------------------------------------------- + * Function: H5TS_once + * + * Purpose: Dynamic package initialization + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_once(H5TS_once_t *once, H5TS_once_init_func_t func) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Sanity check */ + if (H5_UNLIKELY(NULL == once || NULL == func)) + HGOTO_DONE(FAIL); + + /* Invoke the function, only once per process */ + if (H5_UNLIKELY(pthread_once(once, func))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_once() */ +#endif + +#endif /* H5_HAVE_THREADSAFE */ + diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index 51e66639ac6..75e75261910 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -270,17 +270,6 @@ herr_t H5TS__tinfo_init(void); void H5TS__tinfo_destroy(void *tinfo_node); herr_t H5TS__tinfo_term(void); -#ifdef H5_HAVE_WIN_THREADS - -/* Functions called from DllMain */ -H5_DLL BOOL CALLBACK H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex); - -#else - -H5_DLL void H5TS__pthread_first_thread_init(void); - -#endif /* H5_HAVE_WIN_THREADS */ - /* Recursive R/W lock related function declarations */ H5_DLL herr_t H5TS__rw_lock_init(H5TS_rw_lock_t *rw_lock); H5_DLL herr_t H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock); @@ -301,6 +290,13 @@ H5_DLL herr_t H5TS__barrier_init(H5TS_barrier_t *barrier, uint64_t count); H5_DLL herr_t H5TS__barrier_wait(H5TS_barrier_t *barrier); H5_DLL herr_t H5TS__barrier_destroy(H5TS_barrier_t *barrier); +/* 'once' callbacks */ +#ifdef H5_HAVE_WIN_THREADS +H5_DLL BOOL CALLBACK H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex); +#else +H5_DLL void H5TS__pthread_first_thread_init(void); +#endif /* H5_HAVE_WIN_THREADS */ + #ifdef H5TS_TESTING #if H5TS_ENABLE_REC_RW_LOCK_STATS H5_DLL herr_t H5TS__rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats); diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index e3845d3840b..b2d26950aac 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -40,14 +40,8 @@ /* Static initialization values */ #ifdef H5_HAVE_WIN_THREADS -#define H5TS_KEY_INITIALIZER \ - { \ - NULL, 0, NULL \ - } -#define H5TS_MUTEX_INITIALIZER \ - { \ - NULL \ - } +#define H5TS_KEY_INITIALIZER { NULL, 0, NULL } +#define H5TS_MUTEX_INITIALIZER { NULL } #define H5TS_COND_INITIALIZER CONDITION_VARIABLE_INIT #define H5TS_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT #else @@ -81,6 +75,7 @@ typedef DWORD H5TS_key_t; typedef CRITICAL_SECTION H5TS_CAPABILITY("mutex") H5TS_mutex_t; typedef CONDITION_VARIABLE H5TS_cond_t; typedef PINIT_ONCE H5TS_once_t; +typedef PINIT_ONCE_FN H5TS_once_init_func_t #else typedef pthread_t H5TS_thread_t; typedef void *(*H5TS_thread_start_func_t)(void *); @@ -88,6 +83,7 @@ typedef pthread_key_t H5TS_key_t; typedef pthread_mutex_t H5TS_CAPABILITY("mutex") H5TS_mutex_t; typedef pthread_cond_t H5TS_cond_t; typedef pthread_once_t H5TS_once_t; +typedef void (*H5TS_once_init_func_t)(void); #endif /*****************************/ @@ -114,6 +110,9 @@ H5_DLL uint64_t H5TS_thread_id(void); H5_DLL struct H5CX_node_t **H5TS_get_api_ctx_ptr(void); H5_DLL struct H5E_t *H5TS_get_err_stack(void); +/* 'Once' operationss */ +H5_DLL herr_t H5TS_once(H5TS_once_t *once, H5TS_once_init_func_t func); + /* Mutex operations */ H5_DLL herr_t H5TS_mutex_init(H5TS_mutex_t *mutex); H5_DLL herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex) H5TS_ACQUIRE(*mutex); diff --git a/src/H5TSwin.c b/src/H5TSwin.c index 6a879c7fdaa..814f23746c1 100644 --- a/src/H5TSwin.c +++ b/src/H5TSwin.c @@ -104,17 +104,20 @@ H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) *-------------------------------------------------------------------------- */ herr_t -H5TS_win32_thread_enter(void){FUNC_ENTER_NOAPI_NAMECHECK_ONLY +H5TS_win32_thread_enter(void) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Currently a placeholder function. TLS setup is performed - * elsewhere in the library. - * - * WARNING: Do NOT use C standard library functions here. - * CRT functions are not allowed in DllMain, which is where this code - * is used. - */ + /* Currently a placeholder function. TLS setup is performed + * elsewhere in the library. + * + * WARNING: Do NOT use C standard library functions here. + * CRT functions are not allowed in DllMain, which is where this code + * is used. + */ - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED)} /* H5TS_win32_thread_enter() */ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* H5TS_win32_thread_enter() */ /*-------------------------------------------------------------------------- * Function: H5TS_win32_thread_exit @@ -153,6 +156,61 @@ herr_t H5TS_win32_thread_exit(void) FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS_win32_thread_exit() */ +#if defined(H5_BUILT_AS_DYNAMIC_LIB) && defined(H5_HAVE_WIN32_API) +/*------------------------------------------------------------------------- + * Function: DllMain + * + * Purpose: Handles various conditions in the library on Windows. + * + * NOTE: The main purpose of this is for handling Win32 thread cleanup + * on thread/process detach. + * + * Only enabled when the shared Windows library is built with + * thread safety enabled. + * + * Return: true on success, false on failure + * + *------------------------------------------------------------------------- + */ +BOOL WINAPI +DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) +{ + /* Don't add our function enter/leave macros since this function will be + * called before the library is initialized. + * + * NOTE: Do NOT call any CRT functions in DllMain! + * This includes any functions that are called by from here! + */ + + BOOL fOkay = true; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + break; + + case DLL_PROCESS_DETACH: + break; + + case DLL_THREAD_ATTACH: + if (H5TS_win32_thread_enter() < 0) + fOkay = false; + break; + + case DLL_THREAD_DETACH: + if (H5TS_win32_thread_exit() < 0) + fOkay = false; + break; + + default: + /* Shouldn't get here */ + fOkay = false; + break; + } + + return fOkay; +} +#endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB */ + #endif /* H5_HAVE_WIN_THREADS */ #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/Makefile.am b/src/Makefile.am index e7c7006c4ff..d695ed862f0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,8 +97,8 @@ libhdf5_la_SOURCES= H5.c H5build_settings.c H5checksum.c H5dbg.c H5system.c \ H5Torder.c H5Tref.c H5Tpad.c H5Tprecis.c H5Tstrpad.c H5Tvisit.c \ H5Tvlen.c \ H5TS.c H5TSbarrier.c H5TScond.c H5TSexlock.c H5TSint.c H5TSkey.c \ - H5TSmutex.c H5TSpthread.c H5TSrwlock.c H5TStest.c H5TSthread.c \ - H5TSwin.c \ + H5TSmutex.c H5TSonce.c H5TSpthread.c H5TSrwlock.c H5TStest.c \ + H5TSthread.c H5TSwin.c \ H5VL.c H5VLcallback.c H5VLdyn_ops.c H5VLint.c H5VLnative.c \ H5VLnative_attr.c H5VLnative_blob.c H5VLnative_dataset.c \ H5VLnative_datatype.c H5VLnative_file.c H5VLnative_group.c \