Skip to content

Commit

Permalink
Add portable equivalent to pthread_once. Also move DllMain to H5TSwin.c.
Browse files Browse the repository at this point in the history
Signed-off-by: Quincey Koziol <[email protected]>
  • Loading branch information
qkoziol committed Mar 20, 2024
1 parent 2a5a831 commit 4fa7334
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 97 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 0 additions & 59 deletions src/H5.c
Original file line number Diff line number Diff line change
Expand Up @@ -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*/
17 changes: 9 additions & 8 deletions src/H5TSint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
/******************/
Expand Down Expand Up @@ -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)))
Expand Down
121 changes: 121 additions & 0 deletions src/H5TSonce.c
Original file line number Diff line number Diff line change
@@ -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 *
* [email protected]. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
* 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 */

18 changes: 7 additions & 11 deletions src/H5TSpkg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
15 changes: 7 additions & 8 deletions src/H5TSprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -81,13 +75,15 @@ 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 *);
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

/*****************************/
Expand All @@ -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);
Expand Down
76 changes: 67 additions & 9 deletions src/H5TSwin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Loading

0 comments on commit 4fa7334

Please sign in to comment.