From 4b321c3a495a398ec91b3826843b7b554acbefe3 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Thu, 14 Mar 2024 17:17:54 -0500 Subject: [PATCH 001/522] WIP on updating thread-related code in the library. Includes, but not limited to: - Bring the recursive readers/writer lock (RRWL) from the 1.12 branch to develop - Pulls together all the thread-related code into the H5TS package, removing sprawl and providing private API calls for other packages to use for e.g. acquiring thread-local variables, etc. - Breaks H5TS package into several source files, instead of a single one, with large ifdef's. - Added FUNC_ENTER_API_REENTER / FUNC_LEAVE_API_REENTER macros around all "developer" callback routines (e.g., the routines in H5VLdevelop.h, H5FDdevelop.h, etc.) that can be used for pass-through VOL connectors, stackable VFDs, etc., so they can have different thread-reentry behavior, like not re-acquiring the global lock. - Moved all the thread-related tests into one test binary (test/ttsafe), with a "typical" use of test testhdf5.h macros. This now includes the previously standalone thread_id test, and the tests for the RRWL. - Added API context push/pop to tests that directly called routines that use FUNC_ENTER_API_REENTER / FUNC_LEAVE_API_REENTER. Planned: - Remove Mercury threading package, moving all usage back to single, HDF5-based thread-related wrappers, etc. - Remove requirement for PTHREAD_MUTEX_ADAPTIVE_NP, pthread_condattr_setclock(), and CLOCK_MONOTONIC_COARSE, as they are built into the Mercury thread- related wrappers, but we don't need them. Not related to threading, but also in this branch currently: - Adds support for detecting and using the __builtin_expect() compiler hint, to let the compiler know branches that are likely/unlikely to be taken. Wrapped inside new H5_LIKELY/H5_UNLIKELY macros. Signed-off-by: Quincey Koziol --- CMakeLists.txt | 8 - bin/trace | 2 +- config/clang-warnings/error-general | 2 - config/cmake/ConfigureChecks.cmake | 8 +- config/cmake/H5pubconf.h.in | 13 +- config/cmake/HDF5DeveloperBuild.cmake | 6 + config/cmake/HDFTests.c | 31 + config/gnu-warnings/error-general | 2 - configure.ac | 48 +- release_docs/RELEASE.txt | 7 - src/CMakeLists.txt | 13 + src/H5.c | 33 +- src/H5CS.c | 95 +- src/H5CSprivate.h | 37 +- src/H5CX.c | 85 +- src/H5CXprivate.h | 6 + src/H5E.c | 126 +- src/H5Epkg.h | 8 +- src/H5FD.c | 107 +- src/H5FDsubfiling/H5FDioc.h | 12 - src/H5FDsubfiling/H5FDioc_priv.h | 3 +- src/H5FDsubfiling/H5FDioc_threads.c | 60 +- src/H5FDsubfiling/H5subfiling_common.c | 11 +- .../src/util/mercury_compiler_attributes.h | 48 - .../mercury/src/util/mercury_queue.h | 38 - .../mercury/src/util/mercury_thread.c | 50 - .../mercury/src/util/mercury_thread.h | 70 +- .../src/util/mercury_thread_condition.c | 11 +- .../src/util/mercury_thread_condition.h | 73 +- .../mercury/src/util/mercury_thread_mutex.c | 50 +- .../mercury/src/util/mercury_thread_mutex.h | 25 +- .../mercury/src/util/mercury_thread_pool.h | 8 +- .../mercury/src/util/mercury_util_config.h | 25 - .../mercury/src/util/mercury_util_error.h | 24 +- src/H5TS.c | 916 +------------- src/H5TSbarrier.c | 228 ++++ src/H5TScond.c | 288 +++++ src/H5TSdevelop.h | 6 +- src/H5TSexlock.c | 372 ++++++ src/H5TSint.c | 534 ++++++++ src/H5TSkey.c | 344 +++++ src/H5TSmodule.h | 28 + src/H5TSmutex.c | 292 +++++ src/H5TSpkg.h | 370 ++++++ src/H5TSprivate.h | 186 ++- src/H5TSpthread.c | 791 ++++++++++++ src/H5TSrwlock.c | 71 ++ src/H5TStest.c | 107 ++ src/H5TSthread.c | 69 + src/H5TSwin.c | 164 +++ src/H5Tnative.c | 2 + src/H5VLcallback.c | 300 ++--- src/H5err.txt | 1 + src/H5private.h | 160 ++- src/Makefile.am | 4 +- test/CMakeLists.txt | 27 +- test/Makefile.am | 8 +- test/onion.c | 137 ++ test/thread_id.c | 324 ----- test/ttsafe.c | 11 + test/ttsafe.h | 14 + test/ttsafe_acreate.c | 4 +- test/ttsafe_attr_vlen.c | 4 +- test/ttsafe_dcreate.c | 10 +- test/ttsafe_develop.c | 160 +++ test/ttsafe_error.c | 17 +- test/ttsafe_rec_rw_lock.c | 1113 +++++++++++++++++ test/ttsafe_thread_id.c | 137 ++ test/vfd.c | 195 ++- testpar/t_vfd.c | 428 ++++++- utils/mirror_vfd/mirror_writer.c | 84 ++ 71 files changed, 6667 insertions(+), 2384 deletions(-) delete mode 100644 src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h create mode 100644 src/H5TSbarrier.c create mode 100644 src/H5TScond.c create mode 100644 src/H5TSexlock.c create mode 100644 src/H5TSint.c create mode 100644 src/H5TSkey.c create mode 100644 src/H5TSmodule.h create mode 100644 src/H5TSmutex.c create mode 100644 src/H5TSpkg.h create mode 100644 src/H5TSpthread.c create mode 100644 src/H5TSrwlock.c create mode 100644 src/H5TStest.c create mode 100644 src/H5TSthread.c create mode 100644 src/H5TSwin.c delete mode 100644 test/thread_id.c create mode 100644 test/ttsafe_develop.c create mode 100644 test/ttsafe_rec_rw_lock.c create mode 100644 test/ttsafe_thread_id.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a2ebfcbec19..c64ebe2c06e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -796,14 +796,6 @@ if (HDF5_ENABLE_SUBFILING_VFD) set (CMAKE_EXTRA_INCLUDE_FILES pthread.h) set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) - check_type_size(PTHREAD_MUTEX_ADAPTIVE_NP PTHREAD_MUTEX_ADAPTIVE_NP_SIZE) - if (HAVE_PTHREAD_MUTEX_ADAPTIVE_NP_SIZE) - set (${HDF_PREFIX}_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1) - endif () - - check_symbol_exists(pthread_condattr_setclock pthread.h - ${HDF_PREFIX}_HAVE_PTHREAD_CONDATTR_SETCLOCK) - unset (CMAKE_EXTRA_INCLUDE_FILES) unset (CMAKE_REQUIRED_LIBRARIES) endif() diff --git a/bin/trace b/bin/trace index 5941f3a89a8..b70d2168cd6 100755 --- a/bin/trace +++ b/bin/trace @@ -509,7 +509,7 @@ for $file (@ARGV) { $file_args = 0; # Ignore some files that do not need tracing macros - unless ($file eq "H5FDmulti.c" or $file eq "src/H5FDmulti.c" or $file eq "H5FDstdio.c" or $file eq "src/H5FDstdio.c" or $file eq "src/H5TS.c" or $file eq "src/H5FDperform.c") { + unless ($file eq "H5FDmulti.c" or $file eq "src/H5FDmulti.c" or $file eq "H5FDstdio.c" or $file eq "src/H5FDstdio.c" or $file eq "src/H5TS.c" or $file eq "src/H5TSmutex.c" or $file eq "src/H5FDperform.c") { # Snarf up the entire file open SOURCE, $file or die "$file: $!\n"; diff --git a/config/clang-warnings/error-general b/config/clang-warnings/error-general index 883dff76f7a..52f8ac865e3 100644 --- a/config/clang-warnings/error-general +++ b/config/clang-warnings/error-general @@ -57,8 +57,6 @@ # Here is a list of tests and examples that have issues with the stricter warnings as error # # NOTE: Test files are not compatible with these warnings as errors -# thread_id.c, -# -Werror=unused-function # dsets.c # -Werror=unused-parameter # diff --git a/config/cmake/ConfigureChecks.cmake b/config/cmake/ConfigureChecks.cmake index 668739e7074..928f22ec825 100644 --- a/config/cmake/ConfigureChecks.cmake +++ b/config/cmake/ConfigureChecks.cmake @@ -433,6 +433,8 @@ endif () if (MINGW OR NOT WINDOWS) foreach (other_test HAVE_ATTRIBUTE + HAVE_BUILTIN_EXPECT + PTHREAD_BARRIER SYSTEM_SCOPE_THREADS HAVE_SOCKLEN_T ) @@ -642,12 +644,6 @@ if (MINGW OR NOT WINDOWS) endif () endif () -# Check for clock_gettime() CLOCK_MONOTONIC_COARSE -set (CMAKE_EXTRA_INCLUDE_FILES time.h) -check_type_size(CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_COARSE_SIZE) -if (HAVE_CLOCK_MONOTONIC_COARSE_SIZE) - set (${HDF_PREFIX}_HAVE_CLOCK_MONOTONIC_COARSE 1) -endif () unset (CMAKE_EXTRA_INCLUDE_FILES) #----------------------------------------------------------------------------- diff --git a/config/cmake/H5pubconf.h.in b/config/cmake/H5pubconf.h.in index f835da103f8..267781a6d85 100644 --- a/config/cmake/H5pubconf.h.in +++ b/config/cmake/H5pubconf.h.in @@ -107,9 +107,6 @@ /* Define to 1 if you have the `clock_gettime' function. */ #cmakedefine H5_HAVE_CLOCK_GETTIME @H5_HAVE_CLOCK_GETTIME@ -/* Define to 1 if CLOCK_MONOTONIC_COARSE is available */ -#cmakedefine H5_HAVE_CLOCK_MONOTONIC_COARSE @H5_HAVE_CLOCK_MONOTONIC_COARSE@ - /* Define if the function stack tracing code is to be compiled in */ #cmakedefine H5_HAVE_CODESTACK @H5_HAVE_CODESTACK@ @@ -261,11 +258,8 @@ /* Define to 1 if you have the header file. */ #cmakedefine H5_HAVE_PTHREAD_H @H5_HAVE_PTHREAD_H@ -/* Define to 1 if 'pthread_condattr_setclock()' is available */ -#cmakedefine H5_HAVE_PTHREAD_CONDATTR_SETCLOCK @H5_HAVE_PTHREAD_CONDATTR_SETCLOCK@ - -/* Define to 1 if PTHREAD_MUTEX_ADAPTIVE_NP is available */ -#cmakedefine H5_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP @H5_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP@ +/* Define to 1 if the compiler supports the pthread_barrier_*() routines */ +#cmakedefine H5_HAVE_PTHREAD_BARRIER @H5_HAVE_PTHREAD_BARRIER@ /* Define to 1 if you have the header file. */ #cmakedefine H5_HAVE_PWD_H @H5_HAVE_PWD_H@ @@ -334,6 +328,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine H5_HAVE_SZLIB_H @H5_HAVE_SZLIB_H@ +/* Define to 1 if the compiler supports the __builtin_expect() extension */ +#cmakedefine H5_HAVE_BUILTIN_EXPECT @H5_HAVE_BUILTIN_EXPECT@ + #if defined(_WIN32) && !defined(H5_BUILT_AS_DYNAMIC_LIB) /* Not supported on WIN32 platforms with static linking */ /* #undef H5_HAVE_THREADSAFE */ diff --git a/config/cmake/HDF5DeveloperBuild.cmake b/config/cmake/HDF5DeveloperBuild.cmake index f8ccc2f7bef..e71990445bb 100644 --- a/config/cmake/HDF5DeveloperBuild.cmake +++ b/config/cmake/HDF5DeveloperBuild.cmake @@ -174,6 +174,12 @@ if (HDF5_ENABLE_DEBUG_H5FS_ASSERT) list (APPEND HDF5_DEBUG_APIS H5FS_DEBUG_ASSERT) endif () +option (HDF5_ENABLE_DEBUG_H5TS "Enable debugging of H5TS module" OFF) +mark_as_advanced (HDF5_ENABLE_DEBUG_H5TS) +if (HDF5_ENABLE_DEBUG_H5TS) + list (APPEND HDF5_DEBUG_APIS H5TS_DEBUG) +endif () + # If HDF5 free list debugging wasn't specifically enabled, disable # free lists entirely for developer build modes, as they can # make certain types of issues (like references to stale pointers) diff --git a/config/cmake/HDFTests.c b/config/cmake/HDFTests.c index 3d16721346c..90c03a3992d 100644 --- a/config/cmake/HDFTests.c +++ b/config/cmake/HDFTests.c @@ -15,6 +15,21 @@ #define SIMPLE_TEST(x) int main(void){ x; return 0; } +#ifdef HAVE_BUILTIN_EXPECT + +int +main () +{ + void *ptr = (void*) 0; + + if (__builtin_expect (ptr != (void*) 0, 1)) + return 0; + + return 0; +} + +#endif /* HAVE_BUILTIN_EXPECT */ + #ifdef HAVE_ATTRIBUTE int @@ -37,6 +52,22 @@ SIMPLE_TEST(timezone = 0); #endif /* HAVE_TIMEZONE */ +#ifdef PTHREAD_BARRIER +#include + +int main(void) +{ + pthread_barrier_t barr; + int ret; + + ret = pthread_barrier_init(&barr, NULL, 1); + if (ret == 0) + return 0; + return 1; +} + +#endif /* PTHREAD_BARRIER */ + #ifdef SYSTEM_SCOPE_THREADS #include #include diff --git a/config/gnu-warnings/error-general b/config/gnu-warnings/error-general index 73d1dd564cb..406bfd6e6c1 100644 --- a/config/gnu-warnings/error-general +++ b/config/gnu-warnings/error-general @@ -38,8 +38,6 @@ # Here is a list of tests and examples that have issues with the stricter warnings as error # # NOTE: Test files are not compatible with these warnings as errors -# thread_id.c, -# -Werror=unused-function # dsets.c # -Werror=unused-parameter # external.c,perform/sio_engine.c diff --git a/configure.ac b/configure.ac index dff0c4a0afc..2063a221c5d 100644 --- a/configure.ac +++ b/configure.ac @@ -1830,8 +1830,13 @@ AM_CONDITIONAL([BUILD_SHARED_SZIP_CONDITIONAL], [test "X$USE_FILTER_SZIP" = "Xye AC_CACHE_SAVE ## ---------------------------------------------------------------------- -## Enable thread-safe version of library. It requires Pthreads support -## on POSIX systems. +## Enable thread-safe version of library (requires Pthreads on POSIX +## systems). We usually pick up the system Pthreads library, so --with-pthread +## is only necessary if you are using a custom Pthreads library or if +## your OS hides its implementation in an unusual location. +## +## On Windows, we use Win32 threads and no special configuration should be +## required to use them. ## AC_SUBST([THREADSAFE]) @@ -1969,6 +1974,15 @@ if test "X$THREADSAFE" = "Xyes"; then ;; esac + ## If using Pthreads, check for barrier routines + if test "x$HAVE_PTHREAD" = "xyes"; then + AC_CHECK_DECL([pthread_barrier_init], + [AC_DEFINE([HAVE_PTHREAD_BARRIER], [1], + [Define if has pthread_barrier_*() routines])], + [], + [[#include ]]) + fi + ## ---------------------------------------------------------------------- ## Check if pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM) ## is supported on this system @@ -2126,6 +2140,14 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[int __attribute__((unused)) x]])], AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) +AC_MSG_CHECKING([if compiler supports the __builtin_expect() extension]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[void *ptr = (void*) 0; + if (__builtin_expect (ptr != (void*) 0, 1)) return 0;]])], + [AC_DEFINE([HAVE_BUILTIN_EXPECT], [1], + [Define if supports __builtin_expect() extension]) + AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + ## ---------------------------------------------------------------------- ## Remove old ways of determining debug/production build. ## These were used in 1.8.x and earlier. We should probably keep these checks @@ -2559,8 +2581,8 @@ AC_SUBST([INTERNAL_DEBUG_OUTPUT]) ## too specialized or have huge performance hits. These ## are not listed in the "all" packages list. ## -## all_packages="AC,B2,CX,D,F,FA,FL,FS,MM,O,T,Z" -all_packages="AC,B2,CX,D,F,MM,O,T,Z" +## all_packages="AC,B2,CX,D,F,FA,FL,FS,MM,O,T,TS,Z" +all_packages="AC,B2,CX,D,F,MM,O,T,TS,Z" case "X-$INTERNAL_DEBUG_OUTPUT" in X-yes|X-all) @@ -3190,26 +3212,8 @@ if test "X$SUBFILING_VFD" = "Xyes"; then fi # Checks for libraries. - AC_SEARCH_LIBS([shm_open], [rt]) AC_CHECK_LIB([pthread], [pthread_self],[], [echo "Error: Required library pthread not found." && exit 1]) - # Perform various checks for Mercury util code - AC_CHECK_DECL([PTHREAD_MUTEX_ADAPTIVE_NP], - [AC_DEFINE([HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], [1], - [Define if has PTHREAD_MUTEX_ADAPTIVE_NP])], - [], - [[#include ]]) - AC_CHECK_DECL([pthread_condattr_setclock], - [AC_DEFINE([HAVE_PTHREAD_CONDATTR_SETCLOCK], [1], - [Define if has pthread_condattr_setclock()])], - [], - [[#include ]]) - AC_CHECK_DECL([CLOCK_MONOTONIC_COARSE], - [AC_DEFINE([HAVE_CLOCK_MONOTONIC_COARSE], [1], - [Define if has CLOCK_MONOTONIC_COARSE])], - [], - [[#include ]]) - else AC_MSG_RESULT([no]) fi diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 4c6367e9611..f51d3933f9b 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -1118,13 +1118,6 @@ Bug Fixes since HDF5-1.14.0 release of HDF5. The CMake configuration code already avoids installing the executable on the system. - - Fixed a configuration issue that prevented building of the Subfiling VFD on macOS - - Checks were added to the CMake and Autotools code to verify that CLOCK_MONOTONIC_COARSE, - PTHREAD_MUTEX_ADAPTIVE_NP and pthread_condattr_setclock() are available before attempting - to use them in Subfiling VFD-related utility code. Without these checks, attempting - to build the Subfiling VFD on macOS would fail. - - Fixes the ordering of INCLUDES when building with CMake Include directories in the source or build tree should come before other diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a19126c8291..df302f8074f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -640,6 +640,17 @@ IDE_GENERATED_PROPERTIES ("H5T" "${H5T_HDRS}" "${H5T_SOURCES}" ) set (H5TS_SOURCES ${HDF5_SRC_DIR}/H5TS.c + ${HDF5_SRC_DIR}/H5TSbarrier.c + ${HDF5_SRC_DIR}/H5TScond.c + ${HDF5_SRC_DIR}/H5TSexlock.c + ${HDF5_SRC_DIR}/H5TSint.c + ${HDF5_SRC_DIR}/H5TSkey.c + ${HDF5_SRC_DIR}/H5TSmutex.c + ${HDF5_SRC_DIR}/H5TSpthread.c + ${HDF5_SRC_DIR}/H5TSrwlock.c + ${HDF5_SRC_DIR}/H5TStest.c + ${HDF5_SRC_DIR}/H5TSthread.c + ${HDF5_SRC_DIR}/H5TSwin.c ) set (H5TS_HDRS ${HDF5_SRC_DIR}/H5TSdevelop.h @@ -757,6 +768,7 @@ set (H5_MODULE_HEADERS ${HDF5_SRC_DIR}/H5SLmodule.h ${HDF5_SRC_DIR}/H5SMmodule.h ${HDF5_SRC_DIR}/H5Tmodule.h + ${HDF5_SRC_DIR}/H5TSmodule.h ${HDF5_SRC_DIR}/H5VLmodule.h ${HDF5_SRC_DIR}/H5Zmodule.h ) @@ -958,6 +970,7 @@ set (H5_PRIVATE_HEADERS ${HDF5_SRC_DIR}/H5Tpkg.h ${HDF5_SRC_DIR}/H5Tprivate.h + ${HDF5_SRC_DIR}/H5TSpkg.h ${HDF5_SRC_DIR}/H5TSprivate.h ${HDF5_SRC_DIR}/H5UCprivate.h diff --git a/src/H5.c b/src/H5.c index 4b0a4a2f6e9..75a5d1d2e8a 100644 --- a/src/H5.c +++ b/src/H5.c @@ -73,14 +73,9 @@ static int H5__mpi_delete_cb(MPI_Comm comm, int keyval, void *attr_val, int *fla static const unsigned VERS_RELEASE_EXCEPTIONS[] = {0}; static const unsigned VERS_RELEASE_EXCEPTIONS_SIZE = 1; -/* statically initialize block for pthread_once call used in initializing */ -/* the first global mutex */ -#ifdef H5_HAVE_THREADSAFE -H5_api_t H5_g; -#else +/* Library init / term status (global) */ bool H5_libinit_g = false; /* Library hasn't been initialized */ bool H5_libterm_g = false; /* Library isn't being shutdown */ -#endif char H5_lib_vers_info_g[] = H5_VERS_INFO; static bool H5_dont_atexit_g = false; @@ -213,12 +208,13 @@ H5_init_library(void) */ if (!H5_dont_atexit_g) { -#if defined(H5_HAVE_THREADSAFE) && defined(H5_HAVE_WIN_THREADS) - /* Clean up Win32 thread resources. Pthreads automatically cleans up. - * This must be entered before the library cleanup code so it's +#if defined(H5_HAVE_THREADSAFE) + /* Clean up thread resources. + * + * This must be pushed before the library cleanup code so it's * executed in LIFO order (i.e., last). */ - (void)atexit(H5TS_win32_process_exit); + (void)atexit(H5TS_term_package); #endif /* H5_HAVE_THREADSAFE && H5_HAVE_WIN_THREADS */ /* Normal library termination code */ @@ -303,13 +299,12 @@ H5_term_library(void) H5E_auto2_t func; #ifdef H5_HAVE_THREADSAFE - /* explicit locking of the API */ - H5_FIRST_THREAD_INIT + /* explicitly lock the API */ H5_API_LOCK #endif /* Don't do anything if the library is already closed */ - if (!(H5_INIT_GLOBAL)) + if (!H5_INIT_GLOBAL) goto done; /* Indicate that the library is being shut down */ @@ -1125,7 +1120,7 @@ H5allocate_memory(size_t size, bool clear) { void *ret_value = NULL; - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("*x", "zb", size, clear); if (0 == size) @@ -1136,7 +1131,7 @@ H5allocate_memory(size_t size, bool clear) else ret_value = H5MM_malloc(size); - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5allocate_memory() */ /*------------------------------------------------------------------------- @@ -1168,12 +1163,12 @@ H5resize_memory(void *mem, size_t size) { void *ret_value = NULL; - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("*x", "*xz", mem, size); ret_value = H5MM_realloc(mem, size); - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5resize_memory() */ /*------------------------------------------------------------------------- @@ -1191,13 +1186,13 @@ H5resize_memory(void *mem, size_t size) herr_t H5free_memory(void *mem) { - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE1("e", "*x", mem); /* At this time, it is impossible for this to fail. */ H5MM_xfree(mem); - FUNC_LEAVE_API_NOINIT(SUCCEED) + FUNC_LEAVE_API_REENTER(SUCCEED) } /* end H5free_memory() */ /*------------------------------------------------------------------------- diff --git a/src/H5CS.c b/src/H5CS.c index 3728273ea2a..246ca3c0c4d 100644 --- a/src/H5CS.c +++ b/src/H5CS.c @@ -26,87 +26,13 @@ #include "H5private.h" /* Generic Functions */ #include "H5CSprivate.h" /* Function stack */ +#include "H5CXprivate.h" /* API Contexts */ #include "H5Eprivate.h" /* Error handling */ #ifdef H5_HAVE_CODESTACK #define H5CS_MIN_NSLOTS 16 /* Minimum number of records in an function stack */ -/* A function stack */ -typedef struct H5CS_t { - unsigned nused; /* Number of records currently used in stack */ - unsigned nalloc; /* Number of records current allocated for stack */ - const char **rec; /* Array of function records */ -} H5CS_t; - -#ifdef H5_HAVE_THREADSAFE -/* - * The per-thread function stack. pthread_once() initializes a special - * key that will be used by all threads to create a stack specific to - * each thread individually. The association of stacks to threads will - * be handled by the pthread library. - * - * In order for this macro to work, H5CS_get_my_stack() must be preceded - * by "H5CS_t *fstack =". - */ -static H5CS_t *H5CS__get_stack(void); -#define H5CS_get_my_stack() H5CS__get_stack() -#else /* H5_HAVE_THREADSAFE */ -/* - * The function stack. Eventually we'll have some sort of global table so each - * thread has it's own stack. The stacks will be created on demand when the - * thread first calls H5CS_push(). */ -H5CS_t H5CS_stack_g[1]; -#define H5CS_get_my_stack() (H5CS_stack_g + 0) -#endif /* H5_HAVE_THREADSAFE */ - -#ifdef H5_HAVE_THREADSAFE -/*------------------------------------------------------------------------- - * Function: H5CS__get_stack - * - * Purpose: Support function for H5CS_get_my_stack() to initialize and - * acquire per-thread function stack. - * - * Return: Success: function stack (H5CS_t *) - * - * Failure: NULL - * - *------------------------------------------------------------------------- - */ -static H5CS_t * -H5CS__get_stack(void) -{ - H5CS_t *fstack; - - FUNC_ENTER_PACKAGE_NOERR_NOFS - - fstack = H5TS_get_thread_local_value(H5TS_funcstk_key_g); - if (!fstack) { - /* No associated value with current thread - create one */ -#ifdef H5_HAVE_WIN_THREADS - fstack = (H5CS_t *)LocalAlloc( - LPTR, sizeof(H5CS_t)); /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */ -#else - fstack = - (H5CS_t *)malloc(sizeof(H5CS_t)); /* Don't use H5MM_malloc() here, it causes infinite recursion */ -#endif /* H5_HAVE_WIN_THREADS */ - assert(fstack); - - /* Set the thread-specific info */ - fstack->nused = 0; - fstack->nalloc = 0; - fstack->rec = NULL; - - /* (It's not necessary to release this in this API, it is - * released by the "key destructor" set up in the H5TS - * routines. See calls to pthread_key_create() in H5TS.c -QAK) - */ - H5TS_set_thread_local_value(H5TS_funcstk_key_g, (void *)fstack); - } /* end if */ - - FUNC_LEAVE_NOAPI_NOFS(fstack) -} /* end H5CS__get_stack() */ -#endif /* H5_HAVE_THREADSAFE */ /*------------------------------------------------------------------------- * Function: H5CS_print_stack @@ -159,7 +85,7 @@ H5CS_print_stack(const H5CS_t *fstack, FILE *stream) herr_t H5CS_push(const char *func_name) { - H5CS_t *fstack = H5CS_get_my_stack(); /* Current function stack for library */ + H5CS_t *fstack = H5CX_get_fstack(); /* Get function stack from API context */ /* Don't push this function on the function stack... :-) */ FUNC_ENTER_NOAPI_NOERR_NOFS @@ -201,7 +127,7 @@ H5CS_push(const char *func_name) herr_t H5CS_pop(void) { - H5CS_t *fstack = H5CS_get_my_stack(); + H5CS_t *fstack = H5CX_get_fstack(); /* Get function stack from API context */ /* Don't push this function on the function stack... :-) */ FUNC_ENTER_NOAPI_NOERR_NOFS @@ -213,6 +139,15 @@ H5CS_pop(void) /* Pop the function. */ fstack->nused--; + if (0 == fstack->nused) { + /* The function name strings are statically allocated (by the compiler) + * and are not allocated, so there's no need to free them. + */ + free(fstack->rec); + fstack->rec = NULL; + fstack->nalloc = 0; + } /* end if */ + FUNC_LEAVE_NOAPI_NOFS(SUCCEED) } /* end H5CS_pop() */ @@ -228,9 +163,9 @@ H5CS_pop(void) H5CS_t * H5CS_copy_stack(void) { - H5CS_t *old_stack = H5CS_get_my_stack(); /* Existing function stack for library */ - H5CS_t *new_stack; /* New function stack, for copy */ - H5CS_t *ret_value = NULL; /* Return value */ + H5CS_t *old_stack = H5CX_get_fstack(); /* Get function stack from API context */ + H5CS_t *new_stack; /* New function stack, for copy */ + H5CS_t *ret_value = NULL; /* Return value */ /* Don't push this function on the function stack... :-) */ FUNC_ENTER_NOAPI_NOFS diff --git a/src/H5CSprivate.h b/src/H5CSprivate.h index 5cdf2d5fdd3..e8bb65b8889 100644 --- a/src/H5CSprivate.h +++ b/src/H5CSprivate.h @@ -19,12 +19,35 @@ /* Private headers needed by this file */ #include "H5private.h" -/* Forward declarations for structure fields */ -struct H5CS_t; -H5_DLL herr_t H5CS_push(const char *func_name); -H5_DLL herr_t H5CS_pop(void); -H5_DLL herr_t H5CS_print_stack(const struct H5CS_t *stack, FILE *stream); -H5_DLL struct H5CS_t *H5CS_copy_stack(void); -H5_DLL herr_t H5CS_close_stack(struct H5CS_t *stack); +/**************************/ +/* Library Private Macros */ +/**************************/ + + +/****************************/ +/* Library Private Typedefs */ +/****************************/ + +/* A function stack */ +typedef struct H5CS_t { + unsigned nused; /* Number of records currently used in stack */ + unsigned nalloc; /* Number of records current allocated for stack */ + const char **rec; /* Array of function records */ +} H5CS_t; + + +/*****************************/ +/* Library-private Variables */ +/*****************************/ + + +/***************************************/ +/* Library-private Function Prototypes */ +/***************************************/ +H5_DLL herr_t H5CS_push(const char *func_name); +H5_DLL herr_t H5CS_pop(void); +H5_DLL herr_t H5CS_print_stack(const H5CS_t *stack, FILE *stream); +H5_DLL H5CS_t *H5CS_copy_stack(void); +H5_DLL herr_t H5CS_close_stack(H5CS_t *stack); #endif /* H5CSprivate_H */ diff --git a/src/H5CX.c b/src/H5CX.c index 0c6c8733703..a9a50b50340 100644 --- a/src/H5CX.c +++ b/src/H5CX.c @@ -50,7 +50,7 @@ * In order for this macro to work, H5CX_get_my_context() must be preceded * by "H5CX_node_t *ctx =". */ -#define H5CX_get_my_context() H5CX__get_context() +#define H5CX_get_my_context() H5TS_get_api_ctx_ptr() #else /* H5_HAVE_THREADSAFE */ /* * The current API context. @@ -199,6 +199,11 @@ typedef struct H5CX_t { /* Internal: Metadata cache info */ H5AC_ring_t ring; /* Current metadata cache ring for entries */ +#ifdef H5_HAVE_CODESTACK + /* Internal: Function stack info */ + H5CS_t fstack; /* Current function stack for an API operation */ +#endif + #ifdef H5_HAVE_PARALLEL /* Internal: Parallel I/O settings */ bool coll_metadata_read; /* Whether to use collective I/O for metadata read */ @@ -427,9 +432,6 @@ typedef struct H5CX_fapl_cache_t { /********************/ /* Local Prototypes */ /********************/ -#ifdef H5_HAVE_THREADSAFE -static H5CX_node_t **H5CX__get_context(void); -#endif /* H5_HAVE_THREADSAFE */ static void H5CX__push_common(H5CX_node_t *cnode); static H5CX_node_t *H5CX__pop_common(bool update_dxpl_props); @@ -710,55 +712,6 @@ H5CX_term_package(void) FUNC_LEAVE_NOAPI(0) } /* end H5CX_term_package() */ -#ifdef H5_HAVE_THREADSAFE -/*------------------------------------------------------------------------- - * Function: H5CX__get_context - * - * Purpose: Support function for H5CX_get_my_context() to initialize and - * acquire per-thread API context stack. - * - * Return: Success: Non-NULL pointer to head pointer of API context stack for thread - * Failure: NULL - * - *------------------------------------------------------------------------- - */ -static H5CX_node_t ** -H5CX__get_context(void) -{ - H5CX_node_t **ctx = NULL; - - FUNC_ENTER_PACKAGE_NOERR - - ctx = (H5CX_node_t **)H5TS_get_thread_local_value(H5TS_apictx_key_g); - - if (!ctx) { - /* No associated value with current thread - create one */ -#ifdef H5_HAVE_WIN_THREADS - /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */ - ctx = (H5CX_node_t **)LocalAlloc(LPTR, sizeof(H5CX_node_t *)); -#else - /* Use malloc here since this has to match the free in the - * destructor and we want to avoid the codestack there. - */ - ctx = (H5CX_node_t **)malloc(sizeof(H5CX_node_t *)); -#endif /* H5_HAVE_WIN_THREADS */ - assert(ctx); - - /* Reset the thread-specific info */ - *ctx = NULL; - - /* (It's not necessary to release this in this API, it is - * released by the "key destructor" set up in the H5TS - * routines. See calls to pthread_key_create() in H5TS.c -QAK) - */ - H5TS_set_thread_local_value(H5TS_apictx_key_g, (void *)ctx); - } /* end if */ - - /* Set return value */ - FUNC_LEAVE_NOAPI(ctx) -} /* end H5CX__get_context() */ -#endif /* H5_HAVE_THREADSAFE */ - /*------------------------------------------------------------------------- * Function: H5CX_pushed * @@ -1726,6 +1679,32 @@ H5CX_get_ring(void) FUNC_LEAVE_NOAPI(ring) } /* end H5CX_get_ring() */ +#ifdef H5_HAVE_CODESTACK +/*------------------------------------------------------------------------- + * Function: H5CX_get_fstack + * + * Purpose: Retrieves the function stack for the current API call context. + * + * Return: Non-NULL on success / NULL on failure + * + *------------------------------------------------------------------------- + */ +H5CS_t * +H5CX_get_fstack(void) +{ + H5CX_node_t **head = NULL; /* Pointer to head of API context list */ + + FUNC_ENTER_NOAPI_NOERR_NOFS + + /* Sanity check */ + head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + assert(head && *head); + + /* Return value */ + FUNC_LEAVE_NOAPI_NOFS(&(*head)->ctx.fstack) +} /* end H5CX_get_fstack() */ +#endif + #ifdef H5_HAVE_PARALLEL /*------------------------------------------------------------------------- diff --git a/src/H5CXprivate.h b/src/H5CXprivate.h index 2a49d9ef031..450929d472e 100644 --- a/src/H5CXprivate.h +++ b/src/H5CXprivate.h @@ -19,6 +19,9 @@ /* Private headers needed by this file */ #include "H5private.h" /* Generic Functions */ #include "H5ACprivate.h" /* Metadata cache */ +#ifdef H5_HAVE_CODESTACK +#include "H5CSprivate.h" /* Function stack */ +#endif #ifdef H5_HAVE_PARALLEL #include "H5FDprivate.h" /* File drivers */ #endif /* H5_HAVE_PARALLEL */ @@ -87,6 +90,9 @@ H5_DLL herr_t H5CX_get_vol_wrap_ctx(void **wrap_ctx); H5_DLL herr_t H5CX_get_vol_connector_prop(H5VL_connector_prop_t *vol_connector_prop); H5_DLL haddr_t H5CX_get_tag(void); H5_DLL H5AC_ring_t H5CX_get_ring(void); +#ifdef H5_HAVE_CODESTACK +H5_DLL H5CS_t *H5CX_get_fstack(void); +#endif #ifdef H5_HAVE_PARALLEL H5_DLL bool H5CX_get_coll_metadata_read(void); H5_DLL herr_t H5CX_get_mpi_coll_datatypes(MPI_Datatype *btype, MPI_Datatype *ftype); diff --git a/src/H5E.c b/src/H5E.c index 36f07048e94..c31a16b741a 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -73,7 +73,6 @@ /* Local Prototypes */ /********************/ /* Static function declarations */ -static herr_t H5E__set_default_auto(H5E_t *stk); static H5E_cls_t *H5E__register_class(const char *cls_name, const char *lib_name, const char *version); static herr_t H5E__unregister_class(H5E_cls_t *cls, void **request); static ssize_t H5E__get_class_name(const H5E_cls_t *cls, char *name, size_t size); @@ -91,6 +90,59 @@ static herr_t H5E__append_stack(H5E_t *dst_estack, const H5E_t *src_stack); /* Package Variables */ /*********************/ +/* Default value to initialize R/W locks */ +static const H5E_t H5E_err_stack_def = { + 0, /* nused */ + { /*slot[] */ + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL} + }, + + /* H5E_auto_op_t */ +#ifndef H5_NO_DEPRECATED_SYMBOLS +#ifdef H5_USE_16_API_DEFAULT + {1, TRUE, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2}, +#else /* H5_USE_16_API */ + {2, TRUE, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2}, +#endif /* H5_USE_16_API_DEFAULT */ +#else /* H5_NO_DEPRECATED_SYMBOLS */ + {(H5E_auto2_t)H5E__print2}, +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + + NULL /* auto_data */ +}; + + /*****************************/ /* Library Private Variables */ /*****************************/ @@ -272,81 +324,17 @@ H5E_term_package(void) * *-------------------------------------------------------------------------- */ -static herr_t +void H5E__set_default_auto(H5E_t *stk) { FUNC_ENTER_PACKAGE_NOERR -#ifndef H5_NO_DEPRECATED_SYMBOLS -#ifdef H5_USE_16_API_DEFAULT - stk->auto_op.vers = 1; -#else /* H5_USE_16_API */ - stk->auto_op.vers = 2; -#endif /* H5_USE_16_API_DEFAULT */ - - stk->auto_op.func1 = stk->auto_op.func1_default = (H5E_auto1_t)H5Eprint1; - stk->auto_op.func2 = stk->auto_op.func2_default = (H5E_auto2_t)H5E__print2; - stk->auto_op.is_default = true; -#else /* H5_NO_DEPRECATED_SYMBOLS */ - stk->auto_op.func2 = (H5E_auto2_t)H5E__print2; -#endif /* H5_NO_DEPRECATED_SYMBOLS */ - - stk->auto_data = NULL; + /* Initialize with default error stack */ + memcpy(stk, &H5E_err_stack_def, sizeof(H5E_err_stack_def)); - FUNC_LEAVE_NOAPI(SUCCEED) + FUNC_LEAVE_NOAPI_VOID } /* end H5E__set_default_auto() */ -#ifdef H5_HAVE_THREADSAFE -/*------------------------------------------------------------------------- - * Function: H5E__get_stack - * - * Purpose: Support function for H5E__get_my_stack() to initialize and - * acquire per-thread error stack. - * - * Return: Success: Pointer to an error stack struct (H5E_t *) - * - * Failure: NULL - * - *------------------------------------------------------------------------- - */ -H5E_t * -H5E__get_stack(void) -{ - H5E_t *estack = NULL; - - FUNC_ENTER_PACKAGE_NOERR - - estack = (H5E_t *)H5TS_get_thread_local_value(H5TS_errstk_key_g); - - if (!estack) { - /* No associated value with current thread - create one */ -#ifdef H5_HAVE_WIN_THREADS - /* Win32 has to use LocalAlloc to match the LocalFree in DllMain */ - estack = (H5E_t *)LocalAlloc(LPTR, sizeof(H5E_t)); -#else - /* Use malloc here since this has to match the free in the - * destructor and we want to avoid the codestack there. - */ - estack = (H5E_t *)malloc(sizeof(H5E_t)); -#endif /* H5_HAVE_WIN_THREADS */ - assert(estack); - - /* Set the thread-specific info */ - estack->nused = 0; - H5E__set_default_auto(estack); - - /* (It's not necessary to release this in this API, it is - * released by the "key destructor" set up in the H5TS - * routines. See calls to pthread_key_create() in H5TS.c -QAK) - */ - H5TS_set_thread_local_value(H5TS_errstk_key_g, (void *)estack); - } /* end if */ - - /* Set return value */ - FUNC_LEAVE_NOAPI(estack) -} /* end H5E__get_stack() */ -#endif /* H5_HAVE_THREADSAFE */ - /*------------------------------------------------------------------------- * Function: H5E__free_class * diff --git a/src/H5Epkg.h b/src/H5Epkg.h index 546e389c971..0cdbeb0249e 100644 --- a/src/H5Epkg.h +++ b/src/H5Epkg.h @@ -47,7 +47,7 @@ * In order for this macro to work, H5E__get_my_stack() must be preceded * by "H5E_t *estack =". */ -#define H5E__get_my_stack() H5E__get_stack() +#define H5E__get_my_stack() H5TS_get_err_stack() #else /* H5_HAVE_THREADSAFE */ /* * The current error stack. @@ -117,15 +117,13 @@ struct H5E_t { * The current error stack. */ H5_DLLVAR H5E_t H5E_stack_g[1]; -#endif /* H5_HAVE_THREADSAFE */ +#endif /******************************/ /* Package Private Prototypes */ /******************************/ H5_DLL herr_t H5E__term_deprec_interface(void); -#ifdef H5_HAVE_THREADSAFE -H5_DLL H5E_t *H5E__get_stack(void); -#endif /* H5_HAVE_THREADSAFE */ +H5_DLL void H5E__set_default_auto(H5E_t *stk); H5_DLL herr_t H5E__push_stack(H5E_t *estack, const char *file, const char *func, unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc); H5_DLL ssize_t H5E__get_msg(const H5E_msg_t *msg_ptr, H5E_type_t *type, char *msg, size_t size); diff --git a/src/H5FD.c b/src/H5FD.c index f89fdd93b81..cdefd15431a 100644 --- a/src/H5FD.c +++ b/src/H5FD.c @@ -689,7 +689,7 @@ H5FDopen(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) { H5FD_t *ret_value = NULL; - FUNC_ENTER_API(NULL) + FUNC_ENTER_API_REENTER H5TRACE4("*#", "*sIuia", name, flags, fapl_id, maxaddr); /* Check arguments */ @@ -703,7 +703,7 @@ H5FDopen(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "unable to open file"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /*------------------------------------------------------------------------- @@ -825,7 +825,7 @@ H5FDclose(H5FD_t *file) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE1("e", "*#", file); /* Check arguments */ @@ -839,7 +839,7 @@ H5FDclose(H5FD_t *file) HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "unable to close file"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDclose() */ /*------------------------------------------------------------------------- @@ -903,14 +903,13 @@ H5FDcmp(const H5FD_t *f1, const H5FD_t *f2) { int ret_value = -1; - FUNC_ENTER_API(-1) /* return value is arbitrary */ + FUNC_ENTER_API_REENTER H5TRACE2("Is", "*#*#", f1, f2); /* Call private function */ ret_value = H5FD_cmp(f1, f2); -done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDcmp() */ /*------------------------------------------------------------------------- @@ -973,7 +972,7 @@ H5FDquery(const H5FD_t *file, unsigned long *flags /*out*/) { int ret_value = 0; - FUNC_ENTER_API((-1)) + FUNC_ENTER_API_REENTER H5TRACE2("Is", "*#*Ul", file, flags); /* Check arguments */ @@ -989,7 +988,7 @@ H5FDquery(const H5FD_t *file, unsigned long *flags /*out*/) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, (-1), "unable to query feature flags"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /*------------------------------------------------------------------------- @@ -1066,7 +1065,7 @@ H5FDalloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) { haddr_t ret_value = HADDR_UNDEF; - FUNC_ENTER_API(HADDR_UNDEF) + FUNC_ENTER_API_REENTER H5TRACE4("a", "*#Mtih", file, type, dxpl_id, size); /* Check arguments */ @@ -1094,7 +1093,7 @@ H5FDalloc(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size) ret_value += file->base_addr; done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDalloc() */ /*------------------------------------------------------------------------- @@ -1116,7 +1115,7 @@ H5FDfree(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t siz { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE5("e", "*#Mtiah", file, type, dxpl_id, addr, size); /* Check arguments */ @@ -1140,7 +1139,7 @@ H5FDfree(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t siz HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "file deallocation request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDfree() */ /*------------------------------------------------------------------------- @@ -1159,7 +1158,7 @@ H5FDget_eoa(H5FD_t *file, H5FD_mem_t type) { haddr_t ret_value; - FUNC_ENTER_API(HADDR_UNDEF) + FUNC_ENTER_API_REENTER H5TRACE2("a", "*#Mt", file, type); /* Check arguments */ @@ -1178,7 +1177,7 @@ H5FDget_eoa(H5FD_t *file, H5FD_mem_t type) ret_value += file->base_addr; done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDget_eoa() */ /*------------------------------------------------------------------------- @@ -1207,7 +1206,7 @@ H5FDset_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t addr) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE3("e", "*#Mta", file, type, addr); /* Check arguments */ @@ -1226,7 +1225,7 @@ H5FDset_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t addr) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "file set eoa request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDset_eoa() */ /*------------------------------------------------------------------------- @@ -1255,7 +1254,7 @@ H5FDget_eof(H5FD_t *file, H5FD_mem_t type) { haddr_t ret_value; - FUNC_ENTER_API(HADDR_UNDEF) + FUNC_ENTER_API_REENTER H5TRACE2("a", "*#Mt", file, type); /* Check arguments */ @@ -1272,7 +1271,7 @@ H5FDget_eof(H5FD_t *file, H5FD_mem_t type) ret_value += file->base_addr; done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDget_eof() */ /*------------------------------------------------------------------------- @@ -1405,7 +1404,7 @@ H5FDread(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE6("e", "*#Mtiaz*x", file, type, dxpl_id, addr, size, buf); /* Check arguments */ @@ -1431,7 +1430,7 @@ H5FDread(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t size HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file read request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDread() */ /*------------------------------------------------------------------------- @@ -1451,7 +1450,7 @@ H5FDwrite(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t siz { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE6("e", "*#Mtiaz*x", file, type, dxpl_id, addr, size, buf); /* Check arguments */ @@ -1477,7 +1476,7 @@ H5FDwrite(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, size_t siz HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file write request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDwrite() */ /*------------------------------------------------------------------------- @@ -1507,7 +1506,7 @@ H5FDread_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[], { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE7("e", "*#iIu*Mt*a*z**x", file, dxpl_id, count, types, addrs, sizes, bufs); /* Check arguments */ @@ -1555,7 +1554,7 @@ H5FDread_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[], HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file vector read request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDread_vector() */ /*------------------------------------------------------------------------- @@ -1583,7 +1582,7 @@ H5FDwrite_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[] { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE7("e", "*#iIu*Mt*a*z**x", file, dxpl_id, count, types, addrs, sizes, bufs); /* Check arguments */ @@ -1629,7 +1628,7 @@ H5FDwrite_vector(H5FD_t *file, hid_t dxpl_id, uint32_t count, H5FD_mem_t types[] HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file vector write request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDwrite_vector() */ /*------------------------------------------------------------------------- @@ -1676,7 +1675,7 @@ H5FDread_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, element_sizes, bufs); @@ -1728,7 +1727,7 @@ H5FDread_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count, HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file selection read request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDread_selection() */ /*------------------------------------------------------------------------- @@ -1773,7 +1772,7 @@ H5FDwrite_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, element_sizes, bufs); @@ -1826,7 +1825,7 @@ H5FDwrite_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t count HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file selection write request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDwrite_selection() */ /*------------------------------------------------------------------------- @@ -1877,7 +1876,7 @@ H5FDread_vector_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uin { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, element_sizes, bufs); @@ -1926,7 +1925,7 @@ H5FDread_vector_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uin HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file selection read request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDread_vector_from_selection() */ /*------------------------------------------------------------------------- @@ -1975,7 +1974,7 @@ H5FDwrite_vector_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, ui { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, element_sizes, bufs); @@ -2024,7 +2023,7 @@ H5FDwrite_vector_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, ui HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file selection write request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDwrite_vector_from_selection() */ /*------------------------------------------------------------------------- @@ -2073,7 +2072,7 @@ H5FDread_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t c { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, element_sizes, bufs); @@ -2122,7 +2121,7 @@ H5FDread_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t c HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "file selection read request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDread_from_selection() */ /*------------------------------------------------------------------------- @@ -2170,7 +2169,7 @@ H5FDwrite_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE9("e", "*#MtiIu*i*i*a*z**x", file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, element_sizes, bufs); @@ -2219,7 +2218,7 @@ H5FDwrite_from_selection(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, uint32_t HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "file selection write request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDwrite_from_selection() */ /*------------------------------------------------------------------------- @@ -2237,7 +2236,7 @@ H5FDflush(H5FD_t *file, hid_t dxpl_id, hbool_t closing) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE3("e", "*#ib", file, dxpl_id, closing); /* Check arguments */ @@ -2259,7 +2258,7 @@ H5FDflush(H5FD_t *file, hid_t dxpl_id, hbool_t closing) HGOTO_ERROR(H5E_VFL, H5E_CANTFLUSH, FAIL, "file flush request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDflush() */ /*------------------------------------------------------------------------- @@ -2304,7 +2303,7 @@ H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE3("e", "*#ib", file, dxpl_id, closing); /* Check arguments */ @@ -2325,7 +2324,7 @@ H5FDtruncate(H5FD_t *file, hid_t dxpl_id, hbool_t closing) HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "file flush request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDtruncate() */ /*------------------------------------------------------------------------- @@ -2370,7 +2369,7 @@ H5FDlock(H5FD_t *file, hbool_t rw) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE2("e", "*#b", file, rw); /* Check arguments */ @@ -2384,7 +2383,7 @@ H5FDlock(H5FD_t *file, hbool_t rw) HGOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "file lock request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDlock() */ /*------------------------------------------------------------------------- @@ -2429,7 +2428,7 @@ H5FDunlock(H5FD_t *file) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE1("e", "*#", file); /* Check arguments */ @@ -2443,7 +2442,7 @@ H5FDunlock(H5FD_t *file) HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "file unlock request failed"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDunlock() */ /*------------------------------------------------------------------------- @@ -2497,7 +2496,7 @@ H5FDctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE5("e", "*#ULUL*x**x", file, op_code, flags, input, output); /* Check arguments */ @@ -2517,9 +2516,7 @@ H5FDctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed"); done: - - FUNC_LEAVE_API(ret_value) - + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDctl() */ /*------------------------------------------------------------------------- @@ -2616,7 +2613,7 @@ H5FDget_vfd_handle(H5FD_t *file, hid_t fapl_id, void **file_handle /*out*/) { herr_t ret_value = SUCCEED; - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE3("e", "*#i**x", file, fapl_id, file_handle); /* Check arguments */ @@ -2639,7 +2636,7 @@ H5FDget_vfd_handle(H5FD_t *file, hid_t fapl_id, void **file_handle /*out*/) *file_handle = NULL; } - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDget_vfd_handle() */ /*-------------------------------------------------------------------------- @@ -2791,7 +2788,7 @@ H5FDdelete(const char *filename, hid_t fapl_id) { herr_t ret_value = SUCCEED; - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API_REENTER H5TRACE2("e", "*si", filename, fapl_id); /* Check arguments */ @@ -2808,5 +2805,5 @@ H5FDdelete(const char *filename, hid_t fapl_id) HGOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL, "unable to delete file"); done: - FUNC_LEAVE_API(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5FDdelete() */ diff --git a/src/H5FDsubfiling/H5FDioc.h b/src/H5FDsubfiling/H5FDioc.h index bcacd52252d..8f0255c5583 100644 --- a/src/H5FDsubfiling/H5FDioc.h +++ b/src/H5FDsubfiling/H5FDioc.h @@ -174,18 +174,6 @@ H5_DLL herr_t H5Pset_fapl_ioc(hid_t fapl_id, H5FD_ioc_config_t *vfd_config); * */ H5_DLL herr_t H5Pget_fapl_ioc(hid_t fapl_id, H5FD_ioc_config_t *config_out); -/** - * \brief Internal routine for managing exclusive access to critical sections - * by the #H5FD_IOC driver's worker threads. Not meant to be called - * directly by an HDF5 application - */ -H5_DLL void H5FD_ioc_begin_thread_exclusive(void); -/** - * \brief Internal routine for managing exclusive access to critical sections - * by the #H5FD_IOC driver's worker threads. Not meant to be called - * directly by an HDF5 application - */ -H5_DLL void H5FD_ioc_end_thread_exclusive(void); #ifdef __cplusplus } diff --git a/src/H5FDsubfiling/H5FDioc_priv.h b/src/H5FDsubfiling/H5FDioc_priv.h index fbce1a0d0f6..d141111e421 100644 --- a/src/H5FDsubfiling/H5FDioc_priv.h +++ b/src/H5FDsubfiling/H5FDioc_priv.h @@ -35,6 +35,7 @@ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Pprivate.h" /* Property lists */ +#include "H5TSprivate.h" /* Threadsafety */ #include "H5subfiling_common.h" #include "H5subfiling_err.h" @@ -370,7 +371,7 @@ typedef struct ioc_io_queue { int32_t num_failed; int32_t q_len; uint32_t req_counter; - hg_thread_mutex_t q_mutex; + H5TS_mutex_t q_mutex; /* statistics */ #ifdef H5FD_IOC_COLLECT_STATS diff --git a/src/H5FDsubfiling/H5FDioc_threads.c b/src/H5FDsubfiling/H5FDioc_threads.c index 85c2561549d..65147f97438 100644 --- a/src/H5FDsubfiling/H5FDioc_threads.c +++ b/src/H5FDsubfiling/H5FDioc_threads.c @@ -56,7 +56,7 @@ typedef struct ioc_data_t { * use mercury for that purpose... */ -static hg_thread_mutex_t ioc_thread_mutex = PTHREAD_MUTEX_INITIALIZER; +static H5TS_mutex_t ioc_thread_mutex = H5TS_MUTEX_INITIALIZER; #ifdef H5FD_IOC_COLLECT_STATS static int sf_write_ops = 0; @@ -163,7 +163,7 @@ initialize_ioc_threads(void *_sf_context) t_start = MPI_Wtime(); #endif - if (hg_thread_mutex_init(&ioc_data->io_queue.q_mutex) < 0) + if (H5TS_mutex_init(&ioc_data->io_queue.q_mutex) < 0) H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, (-1), "can't initialize IOC thread queue mutex"); /* Allow experimentation with the number of helper threads */ @@ -229,7 +229,7 @@ finalize_ioc_threads(void *_sf_context) assert(0 == atomic_load(&ioc_data->sf_io_ops_pending)); hg_thread_pool_destroy(ioc_data->io_thread_pool); - hg_thread_mutex_destroy(&ioc_data->io_queue.q_mutex); + H5TS_mutex_destroy(&ioc_data->io_queue.q_mutex); /* Wait for IOC main thread to exit */ hg_thread_join(ioc_data->ioc_main_thread); @@ -563,37 +563,6 @@ handle_work_request(void *arg) H5_SUBFILING_FUNC_LEAVE; } -/*------------------------------------------------------------------------- - * Function: H5FD_ioc_begin_thread_exclusive - * - * Purpose: Mutex lock to restrict access to code or variables. - * - * Return: integer result of mutex_lock request. - * - *------------------------------------------------------------------------- - */ -void -H5FD_ioc_begin_thread_exclusive(void) -{ - hg_thread_mutex_lock(&ioc_thread_mutex); -} - -/*------------------------------------------------------------------------- - * Function: H5FD_ioc_end_thread_exclusive - * - * Purpose: Mutex unlock. Should only be called by the current holder - * of the locked mutex. - * - * Return: result of mutex_unlock operation. - * - *------------------------------------------------------------------------- - */ -void -H5FD_ioc_end_thread_exclusive(void) -{ - hg_thread_mutex_unlock(&ioc_thread_mutex); -} - static herr_t send_ack_to_client(int ack_val, int dest_rank, int source_rank, int msg_tag, MPI_Comm comm) { @@ -794,13 +763,13 @@ ioc_file_queue_write_indep(sf_work_request_t *msg, int ioc_idx, int source, MPI_ sf_queue_delay_time += t_queue_delay; #endif - H5FD_ioc_begin_thread_exclusive(); + H5TS_mutex_lock(&ioc_thread_mutex); /* Adjust EOF if necessary */ if (sf_eof > sf_context->sf_eof) sf_context->sf_eof = sf_eof; - H5FD_ioc_end_thread_exclusive(); + H5TS_mutex_unlock(&ioc_thread_mutex); /* * Send a message back to the client that the I/O call has @@ -1313,7 +1282,7 @@ ioc_io_queue_add_entry(ioc_data_t *ioc_data, sf_work_request_t *wk_req_ptr) H5MM_memcpy((void *)(&(entry_ptr->wk_req)), (const void *)wk_req_ptr, sizeof(sf_work_request_t)); /* must obtain io_queue mutex before appending */ - hg_thread_mutex_lock(&ioc_data->io_queue.q_mutex); + H5TS_mutex_lock(&ioc_data->io_queue.q_mutex); assert(ioc_data->io_queue.q_len == atomic_load(&ioc_data->sf_io_ops_pending)); @@ -1375,7 +1344,7 @@ ioc_io_queue_add_entry(ioc_data_t *ioc_data, sf_work_request_t *wk_req_ptr) assert(ioc_data->io_queue.q_len == atomic_load(&ioc_data->sf_io_ops_pending)); - hg_thread_mutex_unlock(&ioc_data->io_queue.q_mutex); + H5TS_mutex_unlock(&ioc_data->io_queue.q_mutex); return; } /* ioc_io_queue_add_entry() */ @@ -1434,11 +1403,16 @@ ioc_io_queue_dispatch_eligible_entries(ioc_data_t *ioc_data, bool try_lock) assert(ioc_data->io_queue.magic == H5FD_IOC__IO_Q_MAGIC); if (try_lock) { - if (hg_thread_mutex_try_lock(&ioc_data->io_queue.q_mutex) < 0) + bool acquired; + herr_t ret; + + ret = H5TS_mutex_try_lock(&ioc_data->io_queue.q_mutex, &acquired); + assert(SUCCEED == ret); + if (!acquired) return; } else - hg_thread_mutex_lock(&ioc_data->io_queue.q_mutex); + H5TS_mutex_lock(&ioc_data->io_queue.q_mutex); entry_ptr = ioc_data->io_queue.q_head; @@ -1558,7 +1532,7 @@ ioc_io_queue_dispatch_eligible_entries(ioc_data_t *ioc_data, bool try_lock) assert(ioc_data->io_queue.q_len == atomic_load(&ioc_data->sf_io_ops_pending)); - hg_thread_mutex_unlock(&ioc_data->io_queue.q_mutex); + H5TS_mutex_unlock(&ioc_data->io_queue.q_mutex); } /* ioc_io_queue_dispatch_eligible_entries() */ /*------------------------------------------------------------------------- @@ -1593,7 +1567,7 @@ ioc_io_queue_complete_entry(ioc_data_t *ioc_data, ioc_io_queue_entry_t *entry_pt assert(entry_ptr->magic == H5FD_IOC__IO_Q_ENTRY_MAGIC); /* must obtain io_queue mutex before deleting and updating stats */ - hg_thread_mutex_lock(&ioc_data->io_queue.q_mutex); + H5TS_mutex_lock(&ioc_data->io_queue.q_mutex); assert(ioc_data->io_queue.num_pending + ioc_data->io_queue.num_in_progress == ioc_data->io_queue.q_len); assert(ioc_data->io_queue.num_in_progress > 0); @@ -1639,7 +1613,7 @@ ioc_io_queue_complete_entry(ioc_data_t *ioc_data, ioc_io_queue_entry_t *entry_pt #endif - hg_thread_mutex_unlock(&ioc_data->io_queue.q_mutex); + H5TS_mutex_unlock(&ioc_data->io_queue.q_mutex); ioc_io_queue_free_entry(entry_ptr); diff --git a/src/H5FDsubfiling/H5subfiling_common.c b/src/H5FDsubfiling/H5subfiling_common.c index 1127ae0a386..01426e40abe 100644 --- a/src/H5FDsubfiling/H5subfiling_common.c +++ b/src/H5FDsubfiling/H5subfiling_common.c @@ -18,6 +18,7 @@ #include "H5subfiling_err.h" #include "H5MMprivate.h" +#include "H5TSprivate.h" /* Threadsafety */ typedef struct { /* Format of a context map entry */ uint64_t file_id; /* key value (linear search of the cache) */ @@ -44,6 +45,8 @@ static size_t sf_topology_cache_num_entries = 0; static file_map_to_context_t *sf_open_file_map = NULL; static int sf_file_map_size = 0; +static H5TS_mutex_t subfiling_log_mutex = H5TS_MUTEX_INITIALIZER; + #define DEFAULT_CONTEXT_CACHE_SIZE 16 #define DEFAULT_TOPOLOGY_CACHE_SIZE 4 #define DEFAULT_FILE_MAP_ENTRIES 8 @@ -3136,7 +3139,7 @@ H5_subfiling_log(int64_t sf_context_id, const char *fmt, ...) goto done; } - H5FD_ioc_begin_thread_exclusive(); + H5TS_mutex_lock(&subfiling_log_mutex); if (sf_context->sf_logfile) { vfprintf(sf_context->sf_logfile, fmt, log_args); @@ -3149,7 +3152,7 @@ H5_subfiling_log(int64_t sf_context_id, const char *fmt, ...) fflush(stdout); } - H5FD_ioc_end_thread_exclusive(); + H5TS_mutex_unlock(&subfiling_log_mutex); done: va_end(log_args); @@ -3171,7 +3174,7 @@ H5_subfiling_log_nonewline(int64_t sf_context_id, const char *fmt, ...) goto done; } - H5FD_ioc_begin_thread_exclusive(); + H5TS_mutex_lock(&subfiling_log_mutex); if (sf_context->sf_logfile) { vfprintf(sf_context->sf_logfile, fmt, log_args); @@ -3182,7 +3185,7 @@ H5_subfiling_log_nonewline(int64_t sf_context_id, const char *fmt, ...) fflush(stdout); } - H5FD_ioc_end_thread_exclusive(); + H5TS_mutex_unlock(&subfiling_log_mutex); done: va_end(log_args); diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h b/src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h deleted file mode 100644 index d2b8ed12137..00000000000 --- a/src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2013-2022 UChicago Argonne, LLC and The HDF Group. - * Copyright (c) 2022-2023 Intel Corporation. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef MERCURY_COMPILER_ATTRIBUTES_H -#define MERCURY_COMPILER_ATTRIBUTES_H - -/*************************************/ -/* Public Type and Struct Definition */ -/*************************************/ - -/*****************/ -/* Public Macros */ -/*****************/ - -/* - * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17. - * In the meantime, to support gcc < 5, we implement __has_attribute - * by hand. - */ -#if !defined(__has_attribute) && defined(__GNUC__) && (__GNUC__ >= 4) -#define __has_attribute(x) __GCC4_has_attribute_##x -#define __GCC4_has_attribute___visibility__ 1 -#define __GCC4_has_attribute___warn_unused_result__ 1 -#define __GCC4_has_attribute___unused__ 1 -#define __GCC4_has_attribute___format__ 1 -#define __GCC4_has_attribute___fallthrough__ 0 -#endif - -/* Visibility of symbols */ -#if defined(_WIN32) -#define HG_ATTR_ABI_IMPORT __declspec(dllimport) -#define HG_ATTR_ABI_EXPORT __declspec(dllexport) -#define HG_ATTR_ABI_HIDDEN -#elif __has_attribute(__visibility__) -#define HG_ATTR_ABI_IMPORT __attribute__((__visibility__("default"))) -#define HG_ATTR_ABI_EXPORT __attribute__((__visibility__("default"))) -#define HG_ATTR_ABI_HIDDEN __attribute__((__visibility__("hidden"))) -#else -#define HG_ATTR_ABI_IMPORT -#define HG_ATTR_ABI_EXPORT -#define HG_ATTR_ABI_HIDDEN -#endif - -#endif /* MERCURY_COMPILER_ATTRIBUTES_H */ diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_queue.h b/src/H5FDsubfiling/mercury/src/util/mercury_queue.h index 946adec75df..6f8dfef3d18 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_queue.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_queue.h @@ -40,20 +40,6 @@ #ifndef MERCURY_QUEUE_H #define MERCURY_QUEUE_H -#define HG_QUEUE_HEAD_INITIALIZER(name) \ - { \ - NULL, &(name).head \ - } - -#define HG_QUEUE_HEAD_INIT(struct_head_name, var_name) \ - struct struct_head_name var_name = HG_QUEUE_HEAD_INITIALIZER(var_name) - -#define HG_QUEUE_HEAD_DECL(struct_head_name, struct_entry_name) \ - struct struct_head_name { \ - struct struct_entry_name *head; \ - struct struct_entry_name **tail; \ - } - #define HG_QUEUE_HEAD(struct_entry_name) \ struct { \ struct struct_entry_name *head; \ @@ -75,8 +61,6 @@ #define HG_QUEUE_FIRST(head_ptr) ((head_ptr)->head) -#define HG_QUEUE_NEXT(entry_ptr, entry_field_name) ((entry_ptr)->entry_field_name.next) - #define HG_QUEUE_PUSH_TAIL(head_ptr, entry_ptr, entry_field_name) \ do { \ (entry_ptr)->entry_field_name.next = NULL; \ @@ -91,26 +75,4 @@ (head_ptr)->tail = &(head_ptr)->head; \ } while (/*CONSTCOND*/ 0) -#define HG_QUEUE_FOREACH(var, head_ptr, entry_field_name) \ - for ((var) = ((head_ptr)->head); (var); (var) = ((var)->entry_field_name.next)) - -/** - * Avoid using those for performance reasons or use mercury_list.h instead - */ - -#define HG_QUEUE_REMOVE(head_ptr, entry_ptr, type, entry_field_name) \ - do { \ - if ((head_ptr)->head == (entry_ptr)) { \ - HG_QUEUE_POP_HEAD((head_ptr), entry_field_name); \ - } \ - else { \ - struct type *curelm = (head_ptr)->head; \ - while (curelm->entry_field_name.next != (entry_ptr)) \ - curelm = curelm->entry_field_name.next; \ - if ((curelm->entry_field_name.next = curelm->entry_field_name.next->entry_field_name.next) == \ - NULL) \ - (head_ptr)->tail = &(curelm)->entry_field_name.next; \ - } \ - } while (/*CONSTCOND*/ 0) - #endif /* MERCURY_QUEUE_H */ diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c index effae48f346..34d0db7c917 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c @@ -79,21 +79,6 @@ hg_thread_cancel(hg_thread_t thread) return HG_UTIL_SUCCESS; } -/*---------------------------------------------------------------------------*/ -int -hg_thread_yield(void) -{ -#ifdef _WIN32 - SwitchToThread(); -#elif defined(__APPLE__) - pthread_yield_np(); -#else - sched_yield(); -#endif - - return HG_UTIL_SUCCESS; -} - /*---------------------------------------------------------------------------*/ int hg_thread_key_create(hg_thread_key_t *key) @@ -127,38 +112,3 @@ hg_thread_key_delete(hg_thread_key_t key) return HG_UTIL_SUCCESS; } -/*---------------------------------------------------------------------------*/ -int -hg_thread_getaffinity(hg_thread_t thread, hg_cpu_set_t *cpu_mask) -{ -#if defined(_WIN32) - return HG_UTIL_FAIL; -#elif defined(__APPLE__) - (void)thread; - (void)cpu_mask; - return HG_UTIL_FAIL; -#else - if (pthread_getaffinity_np(thread, sizeof(hg_cpu_set_t), cpu_mask)) - return HG_UTIL_FAIL; - return HG_UTIL_SUCCESS; -#endif -} - -/*---------------------------------------------------------------------------*/ -int -hg_thread_setaffinity(hg_thread_t thread, const hg_cpu_set_t *cpu_mask) -{ -#if defined(_WIN32) - if (!SetThreadAffinityMask(thread, *cpu_mask)) - return HG_UTIL_FAIL; - return HG_UTIL_SUCCESS; -#elif defined(__APPLE__) - (void)thread; - (void)cpu_mask; - return HG_UTIL_FAIL; -#else - if (pthread_setaffinity_np(thread, sizeof(hg_cpu_set_t), cpu_mask)) - return HG_UTIL_FAIL; - return HG_UTIL_SUCCESS; -#endif -} diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h index f338226da3f..a9ea1cb27c9 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h @@ -21,7 +21,6 @@ typedef LPTHREAD_START_ROUTINE hg_thread_func_t; typedef DWORD hg_thread_ret_t; #define HG_THREAD_RETURN_TYPE hg_thread_ret_t WINAPI typedef DWORD hg_thread_key_t; -typedef DWORD_PTR hg_cpu_set_t; #else #include typedef pthread_t hg_thread_t; @@ -29,18 +28,6 @@ typedef void *(*hg_thread_func_t)(void *); typedef void *hg_thread_ret_t; #define HG_THREAD_RETURN_TYPE hg_thread_ret_t typedef pthread_key_t hg_thread_key_t; -#ifdef __APPLE__ -/* Size definition for CPU sets. */ -#define HG_CPU_SETSIZE 1024 -#define HG_NCPUBITS (8 * sizeof(hg_cpu_mask_t)) -/* Type for array elements in 'cpu_set_t'. */ -typedef uint64_t hg_cpu_mask_t; -typedef struct { - hg_cpu_mask_t bits[HG_CPU_SETSIZE / HG_NCPUBITS]; -} hg_cpu_set_t; -#else -typedef cpu_set_t hg_cpu_set_t; -#endif #endif #ifdef __cplusplus @@ -52,7 +39,7 @@ extern "C" { * * \param thread [IN/OUT] pointer to thread object */ -HG_UTIL_PUBLIC void hg_thread_init(hg_thread_t *thread); +void hg_thread_init(hg_thread_t *thread); /** * Create a new thread for the given function. @@ -63,7 +50,7 @@ HG_UTIL_PUBLIC void hg_thread_init(hg_thread_t *thread); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_create(hg_thread_t *thread, hg_thread_func_t f, void *data); +int hg_thread_create(hg_thread_t *thread, hg_thread_func_t f, void *data); /** * Ends the calling thread. @@ -72,7 +59,7 @@ HG_UTIL_PUBLIC int hg_thread_create(hg_thread_t *thread, hg_thread_func_t f, voi * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC void hg_thread_exit(hg_thread_ret_t ret); +void hg_thread_exit(hg_thread_ret_t ret); /** * Wait for thread completion. @@ -81,7 +68,7 @@ HG_UTIL_PUBLIC void hg_thread_exit(hg_thread_ret_t ret); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_join(hg_thread_t thread); +int hg_thread_join(hg_thread_t thread); /** * Terminate the thread. @@ -90,28 +77,21 @@ HG_UTIL_PUBLIC int hg_thread_join(hg_thread_t thread); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_cancel(hg_thread_t thread); - -/** - * Yield the processor. - * - * \return Non-negative on success or negative on failure - */ -HG_UTIL_PUBLIC int hg_thread_yield(void); +int hg_thread_cancel(hg_thread_t thread); /** * Obtain handle of the calling thread. * * \return */ -static HG_UTIL_INLINE hg_thread_t hg_thread_self(void); +static inline hg_thread_t hg_thread_self(void); /** * Compare thread IDs. * * \return Non-zero if equal, zero if not equal */ -static HG_UTIL_INLINE int hg_thread_equal(hg_thread_t t1, hg_thread_t t2); +static inline int hg_thread_equal(hg_thread_t t1, hg_thread_t t2); /** * Create a thread-specific data key visible to all threads in the process. @@ -120,7 +100,7 @@ static HG_UTIL_INLINE int hg_thread_equal(hg_thread_t t1, hg_thread_t t2); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_key_create(hg_thread_key_t *key); +int hg_thread_key_create(hg_thread_key_t *key); /** * Delete a thread-specific data key previously returned by @@ -130,7 +110,7 @@ HG_UTIL_PUBLIC int hg_thread_key_create(hg_thread_key_t *key); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_key_delete(hg_thread_key_t key); +int hg_thread_key_delete(hg_thread_key_t key); /** * Get value from specified key. @@ -139,7 +119,7 @@ HG_UTIL_PUBLIC int hg_thread_key_delete(hg_thread_key_t key); * * \return Pointer to data associated to the key */ -static HG_UTIL_INLINE void *hg_thread_getspecific(hg_thread_key_t key); +static inline void *hg_thread_getspecific(hg_thread_key_t key); /** * Set value to specified key. @@ -149,30 +129,10 @@ static HG_UTIL_INLINE void *hg_thread_getspecific(hg_thread_key_t key); * * \return Non-negative on success or negative on failure */ -static HG_UTIL_INLINE int hg_thread_setspecific(hg_thread_key_t key, const void *value); - -/** - * Get affinity mask. - * - * \param thread [IN] thread object - * \param cpu_mask [IN/OUT] cpu mask - * - * \return Non-negative on success or negative on failure - */ -HG_UTIL_PUBLIC int hg_thread_getaffinity(hg_thread_t thread, hg_cpu_set_t *cpu_mask); - -/** - * Set affinity mask. - * - * \param thread [IN] thread object - * \param cpu_mask [IN] cpu mask - * - * \return Non-negative on success or negative on failure - */ -HG_UTIL_PUBLIC int hg_thread_setaffinity(hg_thread_t thread, const hg_cpu_set_t *cpu_mask); +static inline int hg_thread_setspecific(hg_thread_key_t key, const void *value); /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE hg_thread_t +static inline hg_thread_t hg_thread_self(void) { #ifdef _WIN32 @@ -183,7 +143,7 @@ hg_thread_self(void) } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_equal(hg_thread_t t1, hg_thread_t t2) { #ifdef _WIN32 @@ -194,7 +154,7 @@ hg_thread_equal(hg_thread_t t1, hg_thread_t t2) } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE void * +static inline void * hg_thread_getspecific(hg_thread_key_t key) { #ifdef _WIN32 @@ -205,7 +165,7 @@ hg_thread_getspecific(hg_thread_key_t key) } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_setspecific(hg_thread_key_t key, const void *value) { #ifdef _WIN32 diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c index 6b70978eb15..8534ddfad0f 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c @@ -14,17 +14,8 @@ hg_thread_cond_init(hg_thread_cond_t *cond) #ifdef _WIN32 InitializeConditionVariable(cond); #else - pthread_condattr_t attr; - - pthread_condattr_init(&attr); -#if defined(H5_HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(H5_HAVE_CLOCK_MONOTONIC_COARSE) - /* Must set clock ID if using different clock - * (CLOCK_MONOTONIC_COARSE not supported here) */ - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); -#endif - if (pthread_cond_init(cond, &attr)) + if (pthread_cond_init(cond, NULL)) return HG_UTIL_FAIL; - pthread_condattr_destroy(&attr); #endif return HG_UTIL_SUCCESS; diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h index dcead57eff8..6d9252d7eb5 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h @@ -13,12 +13,6 @@ #ifdef _WIN32 typedef CONDITION_VARIABLE hg_thread_cond_t; #else -#if defined(H5_HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(H5_HAVE_CLOCK_MONOTONIC_COARSE) -#include -#elif defined(H5_HAVE_SYS_TIME_H) -#include -#endif -#include typedef pthread_cond_t hg_thread_cond_t; #endif @@ -33,7 +27,7 @@ extern "C" { * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_cond_init(hg_thread_cond_t *cond); +int hg_thread_cond_init(hg_thread_cond_t *cond); /** * Destroy the condition. @@ -42,7 +36,7 @@ HG_UTIL_PUBLIC int hg_thread_cond_init(hg_thread_cond_t *cond); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_cond_destroy(hg_thread_cond_t *cond); +int hg_thread_cond_destroy(hg_thread_cond_t *cond); /** * Wake one thread waiting for the condition to change. @@ -51,7 +45,7 @@ HG_UTIL_PUBLIC int hg_thread_cond_destroy(hg_thread_cond_t *cond); * * \return Non-negative on success or negative on failure */ -static HG_UTIL_INLINE int hg_thread_cond_signal(hg_thread_cond_t *cond); +static inline int hg_thread_cond_signal(hg_thread_cond_t *cond); /** * Wake all the threads waiting for the condition to change. @@ -60,7 +54,7 @@ static HG_UTIL_INLINE int hg_thread_cond_signal(hg_thread_cond_t *cond); * * \return Non-negative on success or negative on failure */ -static HG_UTIL_INLINE int hg_thread_cond_broadcast(hg_thread_cond_t *cond); +static inline int hg_thread_cond_broadcast(hg_thread_cond_t *cond); /** * Wait for the condition to change. @@ -70,22 +64,10 @@ static HG_UTIL_INLINE int hg_thread_cond_broadcast(hg_thread_cond_t *cond); * * \return Non-negative on success or negative on failure */ -static HG_UTIL_INLINE int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex); - -/** - * Wait timeout ms for the condition to change. - * - * \param cond [IN/OUT] pointer to condition object - * \param mutex [IN/OUT] pointer to mutex object - * \param timeout [IN] timeout (in milliseconds) - * - * \return Non-negative on success or negative on failure - */ -static HG_UTIL_INLINE int hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex, - unsigned int timeout); +static inline int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex); /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_cond_signal(hg_thread_cond_t *cond) { #ifdef _WIN32 @@ -99,7 +81,7 @@ hg_thread_cond_signal(hg_thread_cond_t *cond) } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_cond_broadcast(hg_thread_cond_t *cond) { #ifdef _WIN32 @@ -113,7 +95,7 @@ hg_thread_cond_broadcast(hg_thread_cond_t *cond) } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex) { #ifdef _WIN32 @@ -127,45 +109,6 @@ hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex) return HG_UTIL_SUCCESS; } -/*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int -hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex, unsigned int timeout) -{ -#ifdef _WIN32 - if (!SleepConditionVariableCS(cond, mutex, timeout)) - return HG_UTIL_FAIL; -#else -#if defined(H5_HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(H5_HAVE_CLOCK_MONOTONIC_COARSE) - struct timespec now; -#else - struct timeval now; -#endif - struct timespec abs_timeout; - ldiv_t ld; - - /* Need to convert timeout (ms) to absolute time */ -#if defined(H5_HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(H5_HAVE_CLOCK_MONOTONIC_COARSE) - clock_gettime(CLOCK_MONOTONIC_COARSE, &now); - - /* Get sec / nsec */ - ld = ldiv(now.tv_nsec + timeout * 1000000L, 1000000000L); - abs_timeout.tv_nsec = ld.rem; -#elif defined(H5_HAVE_SYS_TIME_H) - gettimeofday(&now, NULL); - - /* Get sec / usec */ - ld = ldiv(now.tv_usec + timeout * 1000L, 1000000L); - abs_timeout.tv_nsec = ld.rem * 1000L; -#endif - abs_timeout.tv_sec = now.tv_sec + ld.quot; - - if (pthread_cond_timedwait(cond, mutex, &abs_timeout)) - return HG_UTIL_FAIL; -#endif - - return HG_UTIL_SUCCESS; -} - #ifdef __cplusplus } #endif diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c index 8fc804f6141..d4a927bfecd 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c @@ -11,33 +11,6 @@ #include -#ifndef _WIN32 -static int -hg_thread_mutex_init_posix(hg_thread_mutex_t *mutex, int kind) -{ - pthread_mutexattr_t mutex_attr; - int ret = HG_UTIL_SUCCESS; - int rc; - - rc = pthread_mutexattr_init(&mutex_attr); - HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutexattr_init() failed (%s)", - strerror(rc)); - - /* Keep mutex mode as normal and do not expect error checking */ - rc = pthread_mutexattr_settype(&mutex_attr, kind); - HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutexattr_settype() failed (%s)", - strerror(rc)); - - rc = pthread_mutex_init(mutex, &mutex_attr); - HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutex_init() failed (%s)", strerror(rc)); - -done: - rc = pthread_mutexattr_destroy(&mutex_attr); - - return ret; -} -#endif - /*---------------------------------------------------------------------------*/ int hg_thread_mutex_init(hg_thread_mutex_t *mutex) @@ -47,27 +20,14 @@ hg_thread_mutex_init(hg_thread_mutex_t *mutex) #ifdef _WIN32 InitializeCriticalSection(mutex); #else - ret = hg_thread_mutex_init_posix(mutex, PTHREAD_MUTEX_NORMAL); -#endif - - return ret; -} + int rc; -/*---------------------------------------------------------------------------*/ -int -hg_thread_mutex_init_fast(hg_thread_mutex_t *mutex) -{ - int ret = HG_UTIL_SUCCESS; + rc = pthread_mutex_init(mutex, NULL); + HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutex_init() failed (%s)", + strerror(rc)); -#if defined(_WIN32) - ret = hg_thread_mutex_init(mutex); -#elif defined(H5_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) - /* Set type to PTHREAD_MUTEX_ADAPTIVE_NP to improve performance */ - ret = hg_thread_mutex_init_posix(mutex, PTHREAD_MUTEX_ADAPTIVE_NP); -#else - ret = hg_thread_mutex_init_posix(mutex, PTHREAD_MUTEX_NORMAL); +done: #endif - return ret; } diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h index 73ceafb8850..be2e5110c70 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h @@ -36,16 +36,7 @@ extern "C" { * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_mutex_init(hg_thread_mutex_t *mutex); - -/** - * Initialize the mutex, asking for "fast" mutex. - * - * \param mutex [IN/OUT] pointer to mutex object - * - * \return Non-negative on success or negative on failure - */ -HG_UTIL_PUBLIC int hg_thread_mutex_init_fast(hg_thread_mutex_t *mutex); +int hg_thread_mutex_init(hg_thread_mutex_t *mutex); /** * Destroy the mutex. @@ -54,14 +45,14 @@ HG_UTIL_PUBLIC int hg_thread_mutex_init_fast(hg_thread_mutex_t *mutex); * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_mutex_destroy(hg_thread_mutex_t *mutex); +int hg_thread_mutex_destroy(hg_thread_mutex_t *mutex); /** * Lock the mutex. * * \param mutex [IN/OUT] pointer to mutex object */ -static HG_UTIL_INLINE void hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_ACQUIRE(*mutex); +static inline void hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_ACQUIRE(*mutex); /** * Try locking the mutex. @@ -70,7 +61,7 @@ static HG_UTIL_INLINE void hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOC * * \return Non-negative on success or negative on failure */ -static HG_UTIL_INLINE int hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) +static inline int hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *mutex); /** @@ -78,10 +69,10 @@ static HG_UTIL_INLINE int hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) * * \param mutex [IN/OUT] pointer to mutex object */ -static HG_UTIL_INLINE void hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_RELEASE(*mutex); +static inline void hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_RELEASE(*mutex); /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE void +static inline void hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS { #ifdef _WIN32 @@ -92,7 +83,7 @@ hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS { #ifdef _WIN32 @@ -107,7 +98,7 @@ hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANAL } /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE void +static inline void hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS { #ifdef _WIN32 diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h index 6744eac9693..5141d584765 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h @@ -53,7 +53,7 @@ extern "C" { * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_pool_init(unsigned int thread_count, hg_thread_pool_t **pool); +int hg_thread_pool_init(unsigned int thread_count, hg_thread_pool_t **pool); /** * Destroy the thread pool. @@ -62,7 +62,7 @@ HG_UTIL_PUBLIC int hg_thread_pool_init(unsigned int thread_count, hg_thread_pool * * \return Non-negative on success or negative on failure */ -HG_UTIL_PUBLIC int hg_thread_pool_destroy(hg_thread_pool_t *pool); +int hg_thread_pool_destroy(hg_thread_pool_t *pool); /** * Post work to the pool. Note that the operation may be queued depending on @@ -73,10 +73,10 @@ HG_UTIL_PUBLIC int hg_thread_pool_destroy(hg_thread_pool_t *pool); * * \return Non-negative on success or negative on failure */ -static HG_UTIL_INLINE int hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work); +static inline int hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work); /*---------------------------------------------------------------------------*/ -static HG_UTIL_INLINE int +static inline int hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work) { int ret = HG_UTIL_SUCCESS; diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h b/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h index 53189fb59a5..1f3a9ade317 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h @@ -14,37 +14,12 @@ #include "H5private.h" -/* Type definitions */ -#include -#include -#include - /*****************/ /* Public Macros */ /*****************/ -/* Reflects any major or incompatible public API changes */ -#define HG_UTIL_VERSION_MAJOR 4 -/* Reflects any minor backwards compatible API or functionality addition */ -#define HG_UTIL_VERSION_MINOR 0 -/* Reflects any backwards compatible bug fixes */ -#define HG_UTIL_VERSION_PATCH 0 - /* Return codes */ #define HG_UTIL_SUCCESS 0 #define HG_UTIL_FAIL -1 -#include - -/* Inline macro */ -#ifdef _WIN32 -#define HG_UTIL_INLINE __inline -#else -#define HG_UTIL_INLINE __inline__ -#endif - -#define HG_UTIL_PUBLIC -#define HG_UTIL_PRIVATE -#define HG_UTIL_PLUGIN - #endif /* MERCURY_UTIL_CONFIG_H */ diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h b/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h index b5cb5cca2a4..edf0485d4f9 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h @@ -10,32 +10,12 @@ #include "mercury_util_config.h" -/* Branch predictor hints */ -#ifndef _WIN32 -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else -#define likely(x) (x) -#define unlikely(x) (x) -#endif - /* Error macros */ -#define HG_UTIL_GOTO_DONE(label, ret, ret_val) \ - do { \ - ret = ret_val; \ - goto label; \ - } while (0) - -#define HG_UTIL_GOTO_ERROR(label, ret, err_val, ...) \ - do { \ - ret = err_val; \ - goto label; \ - } while (0) /* Check for cond, set ret to err_val and goto label */ #define HG_UTIL_CHECK_ERROR(cond, label, ret, err_val, ...) \ do { \ - if (unlikely(cond)) { \ + if (H5_UNLIKELY(cond)) { \ ret = err_val; \ goto label; \ } \ @@ -43,7 +23,7 @@ #define HG_UTIL_CHECK_ERROR_NORET(cond, label, ...) \ do { \ - if (unlikely(cond)) { \ + if (H5_UNLIKELY(cond)) { \ goto label; \ } \ } while (0) diff --git a/src/H5TS.c b/src/H5TS.c index 8aadd904c34..d4cec185992 100644 --- a/src/H5TS.c +++ b/src/H5TS.c @@ -12,25 +12,28 @@ /* * Purpose: This file contains the framework for ensuring that the global - * library lock is held when an API routine is called. This - * framework works in concert with the FUNC_ENTER_API / FUNC_LEAVE_API - * macros defined in H5private.h. + * library lock is held when an API routine is called. This framework + * works in concert with the FUNC_ENTER_API / FUNC_LEAVE_API macros + * defined in H5private.h. * - * Note: Because this threadsafety framework operates outside the library, - * it does not use the error stack and only uses the "namecheck only" - * FUNC_ENTER_* / FUNC_LEAVE_* macros. + * 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 "H5MMprivate.h" /* Memory management */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -38,369 +41,33 @@ /* Local Macros */ /****************/ + /******************/ /* Local Typedefs */ /******************/ -/* Cancellability structure */ -typedef struct H5TS_cancel_struct { - int previous_state; - unsigned int cancel_count; -} H5TS_cancel_t; - -/* Function pointer typedef for thread callback function */ -typedef void *(*H5TS_thread_cb_t)(void *); /********************/ /* Local Prototypes */ /********************/ -static void H5TS__key_destructor(void *key_val); -static herr_t H5TS__mutex_acquire(H5TS_mutex_t *mutex, unsigned int lock_count, bool *acquired); -static herr_t H5TS__mutex_unlock(H5TS_mutex_t *mutex, unsigned int *lock_count); + /*********************/ /* Package Variables */ /*********************/ +/* API threadsafety info */ +H5TS_api_info_t H5TS_api_info_p; + /*****************************/ /* Library Private Variables */ /*****************************/ -/* Global variable definitions */ -#ifdef H5_HAVE_WIN_THREADS -H5TS_once_t H5TS_first_init_g; -#else -H5TS_once_t H5TS_first_init_g = PTHREAD_ONCE_INIT; -#endif - -/* Thread-local keys, used by other interfaces */ -/* Error stack */ -#ifdef H5_HAVE_WIN_THREADS -H5TS_key_t H5TS_errstk_key_g = TLS_OUT_OF_INDEXES; -#else -H5TS_key_t H5TS_errstk_key_g; -#endif - -#ifdef H5_HAVE_CODESTACK -/* Function stack */ -#ifdef H5_HAVE_WIN_THREADS -H5TS_key_t H5TS_funcstk_key_g = TLS_OUT_OF_INDEXES; -#else -H5TS_key_t H5TS_funcstk_key_g; -#endif -#endif /* H5_HAVE_CODESTACK */ - -/* API context */ -#ifdef H5_HAVE_WIN_THREADS -H5TS_key_t H5TS_apictx_key_g = TLS_OUT_OF_INDEXES; -#else -H5TS_key_t H5TS_apictx_key_g; -#endif /*******************/ /* Local Variables */ /*******************/ -/* Thread-local keys, used in this module */ -/* Thread cancellation state */ -#ifdef H5_HAVE_WIN_THREADS -static H5TS_key_t H5TS_cancel_key_s = TLS_OUT_OF_INDEXES; -#else -static H5TS_key_t H5TS_cancel_key_s; -#endif - -#ifndef H5_HAVE_WIN_THREADS - -/* An H5TS_tid_t is a record of a thread identifier that is - * available for reuse. - */ -struct _tid; -typedef struct _tid H5TS_tid_t; - -struct _tid { - H5TS_tid_t *next; - uint64_t id; -}; - -/* Pointer to first free thread ID record or NULL. */ -static H5TS_tid_t *H5TS_tid_next_free = NULL; -static uint64_t H5TS_tid_next_id = 0; - -/* Mutual exclusion for access to H5TS_tid_next_free and H5TS_tid_next_id. */ -static pthread_mutex_t H5TS_tid_mtx; - -/* Key for thread-local storage of the thread ID. */ -static H5TS_key_t H5TS_tid_key; - -#endif /* H5_HAVE_WIN_THREADS */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS__key_destructor - * - * USAGE - * H5TS__key_destructor() - * - * RETURNS - * None - * - * DESCRIPTION - * Frees the memory for a key. Called by each thread as it exits. - * Currently all the thread-specific information for all keys are simple - * structures allocated with malloc, so we can free them all uniformly. - *-------------------------------------------------------------------------- - */ -static void -H5TS__key_destructor(void *key_val) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - /* Use free() here instead of H5MM_xfree(), to avoid calling the H5CS routines */ - if (key_val != NULL) - free(key_val); - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__key_destructor() */ - -#ifndef H5_HAVE_WIN_THREADS - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_tid_destructor - * - * USAGE - * H5TS_tid_destructor() - * - * RETURNS - * - * DESCRIPTION - * When a thread shuts down, put its ID record on the free list. - * - *-------------------------------------------------------------------------- - */ -static void -H5TS_tid_destructor(void *_v) -{ - H5TS_tid_t *tid = _v; - - if (tid == NULL) - return; - - /* TBD use an atomic CAS */ - pthread_mutex_lock(&H5TS_tid_mtx); - tid->next = H5TS_tid_next_free; - H5TS_tid_next_free = tid; - pthread_mutex_unlock(&H5TS_tid_mtx); -} - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_tid_init - * - * USAGE - * H5TS_tid_init() - * - * RETURNS - * - * DESCRIPTION - * Initialize for integer thread identifiers. - * - *-------------------------------------------------------------------------- - */ -static void -H5TS_tid_init(void) -{ - pthread_mutex_init(&H5TS_tid_mtx, NULL); - pthread_key_create(&H5TS_tid_key, H5TS_tid_destructor); -} - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_thread_id - * - * USAGE - * uint64_t id = H5TS_thread_id() - * - * RETURNS - * Return an integer identifier, ID, for the current thread. - * - * DESCRIPTION - * The ID satisfies the following properties: - * - * 1 1 <= ID <= UINT64_MAX - * 2 ID is constant over the thread's lifetime. - * 3 No two threads share an ID during their lifetimes. - * 4 A thread's ID is available for reuse as soon as it is joined. - * - * ID 0 is reserved. H5TS_thread_id() returns 0 if the library was not - * built with thread safety or if an error prevents it from assigning an - * ID. - * - *-------------------------------------------------------------------------- - */ -uint64_t -H5TS_thread_id(void) -{ - H5TS_tid_t *tid = pthread_getspecific(H5TS_tid_key); - H5TS_tid_t proto_tid; - - /* An ID is already assigned. */ - if (tid != NULL) - return tid->id; - - /* An ID is *not* already assigned: reuse an ID that's on the - * free list, or else generate a new ID. - * - * Allocating memory while holding a mutex is bad form, so - * point `tid` at `proto_tid` if we need to allocate some - * memory. - */ - pthread_mutex_lock(&H5TS_tid_mtx); - if ((tid = H5TS_tid_next_free) != NULL) - H5TS_tid_next_free = tid->next; - else if (H5TS_tid_next_id != UINT64_MAX) { - tid = &proto_tid; - tid->id = ++H5TS_tid_next_id; - } - pthread_mutex_unlock(&H5TS_tid_mtx); - - /* If a prototype ID record was established, copy it to the heap. */ - if (tid == &proto_tid) - if ((tid = malloc(sizeof(*tid))) != NULL) - *tid = proto_tid; - - if (tid == NULL) - return 0; - - /* Finish initializing the ID record and set a thread-local pointer - * to it. - */ - tid->next = NULL; - if (pthread_setspecific(H5TS_tid_key, tid) != 0) { - H5TS_tid_destructor(tid); - return 0; - } - - return tid->id; -} - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_pthread_first_thread_init - * - * USAGE - * H5TS_pthread_first_thread_init() - * - * RETURNS - * - * DESCRIPTION - * Initialization of global API lock, keys for per-thread error stacks and - * cancallability information. Called by the first thread that enters the - * library. - * - * PROGRAMMER: Chee Wai LEE - * May 2, 2000 - * - *-------------------------------------------------------------------------- - */ -void -H5TS_pthread_first_thread_init(void) -{ - H5_g.H5_libinit_g = false; /* Library hasn't been initialized */ - H5_g.H5_libterm_g = false; /* Library isn't being shutdown */ - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN32_API -#ifdef PTW32_STATIC_LIB - pthread_win32_process_attach_np(); -#endif -#endif - - /* initialize global API mutex lock */ - pthread_mutex_init(&H5_g.init_lock.atomic_lock, NULL); - pthread_cond_init(&H5_g.init_lock.cond_var, NULL); - H5_g.init_lock.lock_count = 0; - - pthread_mutex_init(&H5_g.init_lock.atomic_lock2, NULL); - H5_g.init_lock.attempt_lock_count = 0; - - /* Initialize integer thread identifiers. */ - H5TS_tid_init(); - - /* initialize key for thread-specific error stacks */ - pthread_key_create(&H5TS_errstk_key_g, H5TS__key_destructor); - -#ifdef H5_HAVE_CODESTACK - /* initialize key for thread-specific function stacks */ - pthread_key_create(&H5TS_funcstk_key_g, H5TS__key_destructor); -#endif /* H5_HAVE_CODESTACK */ - - /* initialize key for thread-specific API contexts */ - pthread_key_create(&H5TS_apictx_key_g, H5TS__key_destructor); - - /* initialize key for thread cancellability mechanism */ - pthread_key_create(&H5TS_cancel_key_s, H5TS__key_destructor); - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS_pthread_first_thread_init() */ -#endif /* H5_HAVE_WIN_THREADS */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__mutex_acquire - * - * Purpose: Attempts to acquire a mutex lock, without blocking - * - * Note: On success, the 'acquired' flag indicates if the HDF5 library - * global lock was acquired. - * - * Note: The Windows threads code is very likely bogus. - * - * Return: Non-negative on success / Negative on failure - *-------------------------------------------------------------------------- - */ -static herr_t -H5TS__mutex_acquire(H5TS_mutex_t *mutex, unsigned int lock_count, bool *acquired) -{ - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - EnterCriticalSection(&mutex->CriticalSection); - *acquired = true; -#else /* H5_HAVE_WIN_THREADS */ - /* Attempt to acquire the mutex lock */ - if (0 == pthread_mutex_lock(&mutex->atomic_lock)) { - pthread_t my_thread_id = pthread_self(); - - /* Check if locked already */ - if (mutex->lock_count) { - /* Check for this thread already owning the lock */ - if (pthread_equal(my_thread_id, mutex->owner_thread)) { - /* Already owned by self - increment count */ - mutex->lock_count += lock_count; - *acquired = true; - } - else - *acquired = false; - } - else { - /* Take ownership of the mutex */ - mutex->owner_thread = my_thread_id; - mutex->lock_count = lock_count; - *acquired = true; - } - - if (0 != pthread_mutex_unlock(&mutex->atomic_lock)) - ret_value = -1; - } - else - ret_value = -1; -#endif /* H5_HAVE_WIN_THREADS */ - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__mutex_acquire() */ /*-------------------------------------------------------------------------- * Function: H5TSmutex_acquire @@ -411,189 +78,16 @@ H5TS__mutex_acquire(H5TS_mutex_t *mutex, unsigned int lock_count, bool *acquired * global lock was acquired. * * Return: Non-negative on success / Negative on failure - *-------------------------------------------------------------------------- - */ -herr_t -H5TSmutex_acquire(unsigned int lock_count, bool *acquired){ - FUNC_ENTER_API_NAMECHECK_ONLY - - FUNC_LEAVE_API_NAMECHECK_ONLY(H5TS__mutex_acquire(&H5_g.init_lock, lock_count, acquired))} -/* end H5TSmutex_acquire() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_mutex_lock - * - * USAGE - * H5TS_mutex_lock(&mutex_var) - * - * RETURNS - * Non-negative on success / Negative on failure - * - * DESCRIPTION - * Recursive lock semantics for HDF5 (locking) - - * Multiple acquisition of a lock by a thread is permitted with a - * corresponding unlock operation required. - * - * PROGRAMMER: Chee Wai LEE - * May 2, 2000 - * - *-------------------------------------------------------------------------- - */ -herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex) -{ - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - EnterCriticalSection(&mutex->CriticalSection); -#else /* H5_HAVE_WIN_THREADS */ - /* Acquire the "attempt" lock, increment the attempt lock count, release the lock */ - ret_value = pthread_mutex_lock(&mutex->atomic_lock2); - if (ret_value) - HGOTO_DONE(ret_value); - mutex->attempt_lock_count++; - ret_value = pthread_mutex_unlock(&mutex->atomic_lock2); - if (ret_value) - HGOTO_DONE(ret_value); - - /* Acquire the library lock */ - ret_value = pthread_mutex_lock(&mutex->atomic_lock); - if (ret_value) - HGOTO_DONE(ret_value); - - /* Check if this thread already owns the lock */ - if (mutex->lock_count && pthread_equal(pthread_self(), mutex->owner_thread)) - /* already owned by self - increment count */ - mutex->lock_count++; - else { - /* Wait until the lock is released by current owner thread */ - while (mutex->lock_count) - pthread_cond_wait(&mutex->cond_var, &mutex->atomic_lock); - - /* After we've received the signal, take ownership of the mutex */ - mutex->owner_thread = pthread_self(); - mutex->lock_count = 1; - } - - /* Release the library lock */ - ret_value = pthread_mutex_unlock(&mutex->atomic_lock); - -done: -#endif /* H5_HAVE_WIN_THREADS */ - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS_mutex_lock() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS__mutex_unlock - * - * USAGE - * H5TS__mutex_unlock(&mutex_var, &lock_count) - * - * RETURNS - * Non-negative on success / Negative on failure - * - * DESCRIPTION - * Recursive lock semantics for HDF5 (unlocking) - - * Reset the lock and return the current lock count - * - * PROGRAMMER: Houjun Tang - * Nov 3, 2020 - * - *-------------------------------------------------------------------------- - */ -static herr_t -H5TS__mutex_unlock(H5TS_mutex_t *mutex, unsigned int *lock_count) -{ - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - /* Releases ownership of the specified critical section object. */ - LeaveCriticalSection(&mutex->CriticalSection); -#else /* H5_HAVE_WIN_THREADS */ - - /* Reset the lock count for this thread */ - ret_value = pthread_mutex_lock(&mutex->atomic_lock); - if (ret_value) - HGOTO_DONE(ret_value); - *lock_count = mutex->lock_count; - mutex->lock_count = 0; - ret_value = pthread_mutex_unlock(&mutex->atomic_lock); - - /* If the lock count drops to zero, signal the condition variable, to - * wake another thread. - */ - if (mutex->lock_count == 0) { - int err; - - err = pthread_cond_signal(&mutex->cond_var); - if (err != 0) - ret_value = err; - } - -done: -#endif /* H5_HAVE_WIN_THREADS */ - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS__mutex_unlock */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_mutex_unlock - * - * USAGE - * H5TS_mutex_unlock(&mutex_var) - * - * RETURNS - * Non-negative on success / Negative on failure - * - * DESCRIPTION - * Recursive lock semantics for HDF5 (unlocking) - - * Multiple acquisition of a lock by a thread is permitted with a - * corresponding unlock operation required. - * - * PROGRAMMER: Chee Wai LEE - * May 2, 2000 * *-------------------------------------------------------------------------- */ herr_t -H5TS_mutex_unlock(H5TS_mutex_t *mutex) +H5TSmutex_acquire(unsigned lock_count, bool *acquired) { - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - /* Releases ownership of the specified critical section object. */ - LeaveCriticalSection(&mutex->CriticalSection); -#else /* H5_HAVE_WIN_THREADS */ - - /* Decrement the lock count for this thread */ - ret_value = pthread_mutex_lock(&mutex->atomic_lock); - if (ret_value) - HGOTO_DONE(ret_value); - mutex->lock_count--; - ret_value = pthread_mutex_unlock(&mutex->atomic_lock); - - /* If the lock count drops to zero, signal the condition variable, to - * wake another thread. - */ - if (mutex->lock_count == 0) { - int err; + FUNC_ENTER_API_NAMECHECK_ONLY - err = pthread_cond_signal(&mutex->cond_var); - if (err != 0) - ret_value = err; - } - -done: -#endif /* H5_HAVE_WIN_THREADS */ - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS_mutex_unlock */ + FUNC_LEAVE_API_NAMECHECK_ONLY(H5TS__mutex_acquire(lock_count, acquired)) +} /* end H5TSmutex_acquire() */ /*-------------------------------------------------------------------------- * Function: H5TSmutex_get_attempt_count @@ -601,30 +95,33 @@ H5TS_mutex_unlock(H5TS_mutex_t *mutex) * Purpose: Get the current count of the global lock attempt * * Return: Non-negative on success / Negative on failure + * + * Programmer: Houjun Tang + * June 24, 2019 + * *-------------------------------------------------------------------------- */ herr_t -H5TSmutex_get_attempt_count(unsigned int *count) +H5TSmutex_get_attempt_count(unsigned *count) { + bool have_mutex = false; herr_t ret_value = SUCCEED; FUNC_ENTER_API_NAMECHECK_ONLY -#ifdef H5_HAVE_WIN_THREADS - /* Add Win32 equivalent here when async is supported */ -#else /* H5_HAVE_WIN_THREADS */ - ret_value = pthread_mutex_lock(&H5_g.init_lock.atomic_lock2); - if (ret_value) - HGOTO_DONE(ret_value); - - *count = H5_g.init_lock.attempt_lock_count; + /* Acquire the "attempt" lock, retrieve the attempt lock count, release the lock */ + if (H5_UNLIKELY(H5TS_mutex_lock(&H5TS_api_info_p.attempt_mutex) < 0)) + HGOTO_DONE(FAIL); + have_mutex = true; - ret_value = pthread_mutex_unlock(&H5_g.init_lock.atomic_lock2); - if (ret_value) - HGOTO_DONE(ret_value); + *count = H5TS_api_info_p.attempt_lock_count; done: -#endif /* H5_HAVE_WIN_THREADS */ + /* Release the lock */ + if(have_mutex) + if(H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.attempt_mutex) < 0)) + ret_value = FAIL; + FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value) } /* end H5TSmutex_get_attempt_count() */ @@ -634,351 +131,20 @@ H5TSmutex_get_attempt_count(unsigned int *count) * Purpose: Releases the HDF5 library global lock * * Return: Non-negative on success / Negative on failure + * *-------------------------------------------------------------------------- */ herr_t -H5TSmutex_release(unsigned int *lock_count) +H5TSmutex_release(unsigned *lock_count) { herr_t ret_value = SUCCEED; FUNC_ENTER_API_NAMECHECK_ONLY *lock_count = 0; - if (0 != H5TS__mutex_unlock(&H5_g.init_lock, lock_count)) - ret_value = -1; + if (H5_UNLIKELY(H5TS__mutex_release(lock_count) < 0)) + ret_value = FAIL; FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value) } /* end H5TSmutex_release() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_cancel_count_inc - * - * USAGE - * H5TS_cancel_count_inc() - * - * RETURNS - * Non-negative on success / Negative on failure - * - * DESCRIPTION - * Creates a cancellation counter for a thread if it is the first time - * the thread is entering the library. - * - * if counter value is zero, then set cancellability type of the thread - * to PTHREAD_CANCEL_DISABLE as thread is entering the library and store - * the previous cancellability type into cancellation counter. - * Increase the counter value by 1. - * - * PROGRAMMER: Chee Wai LEE - * May 2, 2000 - * - *-------------------------------------------------------------------------- - */ -herr_t -H5TS_cancel_count_inc(void) -{ -#ifndef H5_HAVE_WIN_THREADS - H5TS_cancel_t *cancel_counter; -#endif /* H5_HAVE_WIN_THREADS */ - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - /* unsupported */ -#else /* H5_HAVE_WIN_THREADS */ - /* Acquire the thread's cancellation counter */ - cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_s); - - /* Check if it's created yet */ - if (!cancel_counter) { - /* - * First time thread calls library - create new counter and associate - * with key. - * - * Don't use H5MM calls here since the destructor has to use free in - * order to avoid codestack calls. - */ - cancel_counter = (H5TS_cancel_t *)calloc(1, sizeof(H5TS_cancel_t)); - if (NULL == cancel_counter) - HGOTO_DONE(FAIL); - - /* Set the thread's cancellation counter with the new object */ - ret_value = pthread_setspecific(H5TS_cancel_key_s, (void *)cancel_counter); - if (ret_value) { - free(cancel_counter); - HGOTO_DONE(FAIL); - } - } - - /* Check if thread entering library */ - if (cancel_counter->cancel_count == 0) - /* Set cancellation state to 'disable', and remember previous state */ - ret_value = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_counter->previous_state); - - /* Increment # of times the library API was re-entered, to avoid resetting - * previous cancellation state until the final API routine is returning. - */ - ++cancel_counter->cancel_count; - -done: -#endif /* H5_HAVE_WIN_THREADS */ - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS_cancel_count_inc() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_cancel_count_dec - * - * USAGE - * H5TS_cancel_count_dec() - * - * RETURNS - * 0 on success and a non-zero error code on error. - * - * DESCRIPTION - * If counter value is one, then set cancellability type of the thread - * to the previous cancellability type stored in the cancellation counter. - * (the thread is leaving the library). - * - * Decrement the counter value by 1. - * - * PROGRAMMER: Chee Wai LEE - * May 2, 2000 - * - *-------------------------------------------------------------------------- - */ -herr_t -H5TS_cancel_count_dec(void) -{ -#ifndef H5_HAVE_WIN_THREADS - H5TS_cancel_t *cancel_counter; -#endif /* H5_HAVE_WIN_THREADS */ - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - /* unsupported */ -#else /* H5_HAVE_WIN_THREADS */ - /* Acquire the thread's cancellation counter */ - cancel_counter = (H5TS_cancel_t *)H5TS_get_thread_local_value(H5TS_cancel_key_s); - - /* Check for leaving last API routine */ - if (cancel_counter->cancel_count == 1) - /* Reset to previous thread cancellation state, if last API */ - ret_value = pthread_setcancelstate(cancel_counter->previous_state, NULL); - - /* Decrement cancellation counter */ - --cancel_counter->cancel_count; -#endif /* H5_HAVE_WIN_THREADS */ - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS_cancel_count_dec() */ - -#ifdef H5_HAVE_WIN_THREADS -/*-------------------------------------------------------------------------- - * NAME - * H5TS_win32_process_enter - * - * RETURNS - * SUCCEED/FAIL - * - * DESCRIPTION - * Per-process setup on Windows when using Win32 threads. - * - *-------------------------------------------------------------------------- - */ -H5_DLL BOOL CALLBACK -H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) -{ - BOOL ret_value = true; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - - /* Initialize the critical section (can't fail) */ - InitializeCriticalSection(&H5_g.init_lock.CriticalSection); - - /* Set up thread local storage */ - if (TLS_OUT_OF_INDEXES == (H5TS_errstk_key_g = TlsAlloc())) - ret_value = false; - -#ifdef H5_HAVE_CODESTACK - if (TLS_OUT_OF_INDEXES == (H5TS_funcstk_key_g = TlsAlloc())) - ret_value = false; -#endif /* H5_HAVE_CODESTACK */ - - if (TLS_OUT_OF_INDEXES == (H5TS_apictx_key_g = TlsAlloc())) - ret_value = false; - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS_win32_process_enter() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_win32_thread_enter - * - * RETURNS - * SUCCEED/FAIL - * - * DESCRIPTION - * Per-thread setup on Windows when using Win32 threads. - * - *-------------------------------------------------------------------------- - */ -herr_t -H5TS_win32_thread_enter(void) -{ - herr_t ret_value = SUCCEED; - - 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. - */ - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS_win32_thread_enter() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_win32_process_exit - * - * RETURNS - * SUCCEED/FAIL - * - * DESCRIPTION - * Per-process cleanup on Windows when using Win32 threads. - * - *-------------------------------------------------------------------------- - */ -void -H5TS_win32_process_exit(void) -{ - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - - /* Windows uses a different thread local storage mechanism which does - * not support auto-freeing like pthreads' keys. - * - * This function is currently registered via atexit() and is called - * AFTER H5_term_library(). - */ - - /* Clean up critical section resources (can't fail) */ - DeleteCriticalSection(&H5_g.init_lock.CriticalSection); - - /* Clean up per-process thread local storage */ - if (H5TS_errstk_key_g != TLS_OUT_OF_INDEXES) - TlsFree(H5TS_errstk_key_g); -#ifdef H5_HAVE_CODESTACK - if (H5TS_funcstk_key_g != TLS_OUT_OF_INDEXES) - TlsFree(H5TS_funcstk_key_g); -#endif /* H5_HAVE_CODESTACK */ - if (H5TS_apictx_key_g != TLS_OUT_OF_INDEXES) - TlsFree(H5TS_apictx_key_g); - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* H5TS_win32_process_exit() */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_win32_thread_exit - * - * RETURNS - * SUCCEED/FAIL - * - * DESCRIPTION - * Per-thread cleanup on Windows when using Win32 threads. - * - *-------------------------------------------------------------------------- - */ -herr_t -H5TS_win32_thread_exit(void) -{ - LPVOID lpvData; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - - /* Windows uses a different thread local storage mechanism which does - * not support auto-freeing like pthreads' keys. - * - * WARNING: Do NOT use C standard library functions here. - * CRT functions are not allowed in DllMain, which is where this code - * is used. - */ - - /* Clean up per-thread thread local storage */ - if (H5TS_errstk_key_g != TLS_OUT_OF_INDEXES) { - lpvData = TlsGetValue(H5TS_errstk_key_g); - if (lpvData) - LocalFree((HLOCAL)lpvData); - } - -#ifdef H5_HAVE_CODESTACK - if (H5TS_funcstk_key_g != TLS_OUT_OF_INDEXES) { - lpvData = TlsGetValue(H5TS_funcstk_key_g); - if (lpvData) - LocalFree((HLOCAL)lpvData); - } -#endif /* H5_HAVE_CODESTACK */ - - if (H5TS_apictx_key_g != TLS_OUT_OF_INDEXES) { - lpvData = TlsGetValue(H5TS_apictx_key_g); - if (lpvData) - LocalFree((HLOCAL)lpvData); - } - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS_win32_thread_exit() */ -#endif /* H5_HAVE_WIN_THREADS */ - -/*-------------------------------------------------------------------------- - * NAME - * H5TS_create_thread - * - * RETURNS - * Thread identifier. - * - * DESCRIPTION - * Spawn off a new thread calling function 'func' with input 'udata'. - * - * PROGRAMMER: Mike McGreevy - * August 31, 2010 - * - *-------------------------------------------------------------------------- - */ -H5TS_thread_t -H5TS_create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata) -{ - H5TS_thread_t ret_value; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - -#ifdef H5_HAVE_WIN_THREADS - /* When calling C runtime functions, you should use _beginthread or - * _beginthreadex instead of CreateThread. Threads created with - * CreateThread risk being killed in low-memory situations. Since we - * only create threads in our test code, this is unlikely to be an issue - * and we'll use the easier-to-deal-with CreateThread for now. - * - * NOTE: _beginthread() auto-recycles its handle when execution completes - * so you can't wait on it, making it unsuitable for the existing - * test code. - */ - ret_value = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, udata, 0, NULL); - -#else /* H5_HAVE_WIN_THREADS */ - - pthread_create(&ret_value, attr, (void *(*)(void *))func, udata); - -#endif /* H5_HAVE_WIN_THREADS */ - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS_create_thread */ - #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSbarrier.c b/src/H5TSbarrier.c new file mode 100644 index 00000000000..b2f0226ec49 --- /dev/null +++ b/src/H5TSbarrier.c @@ -0,0 +1,228 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 barrier operations, equivalent + * to the pthread 'pthread_barrier_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 */ +/****************/ + +#ifndef H5_HAVE_PTHREAD_BARRIER +/* Barrier initialization macro */ +#define H5TS_BARRIER_INIT { \ + PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ + PTHREAD_COND_INITIALIZER, /* cv */ \ + 0, /* count */ \ + 0, /* entered */ \ + 0 /* threshold */ \ + } +#endif + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Default value to initialize barriers */ +#ifndef H5_HAVE_PTHREAD_BARRIER +static const H5TS_barrier_t H5TS_barrier_def = H5TS_BARRIER_INIT; +#endif + +/*-------------------------------------------------------------------------- + * Function: H5TS__barrier_init + * + * Purpose: Initialize a thread barrier + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__barrier_init(H5TS_barrier_t *barrier, uint64_t count) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == barrier || 0 == count)) + HGOTO_DONE(FAIL); + + /* Initialize the barrier */ +#ifdef H5_HAVE_PTHREAD_BARRIER + if (pthread_barrier_init(barrier, NULL, count)) + HGOTO_DONE(FAIL); +#else + memcpy(barrier, &H5TS_barrier_def, sizeof(H5TS_barrier_def)); + + /* Set non-default fields */ + barrier->count = barrier->threshold = count; +#endif + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__barrier_init() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__barrier_wait + * + * Purpose: Wait at a barrier. + * + * Note: Similar to pthread_barrier_wait, a barrier may be re-used + * multiple times without intervening calls to H5TS_barrier_init. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__barrier_wait(H5TS_barrier_t *barrier) +{ +#ifndef H5_HAVE_PTHREAD_BARRIER + bool have_mutex = false; +#endif + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == barrier)) + HGOTO_DONE(FAIL); + +#ifdef H5_HAVE_PTHREAD_BARRIER + if (0 != pthread_barrier_wait(barrier)) + HGOTO_DONE(FAIL); +#else + /* Acquire the mutex for the barrier */ + if (H5_UNLIKELY(H5TS_mutex_lock(&barrier->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + barrier->entered++; + if (barrier->entered < barrier->threshold) { + if (H5_UNLIKELY(H5TS_cond_wait(&barrier->cv, &barrier->mutex))) + HGOTO_DONE(FAIL); + } + else { + if (H5_UNLIKELY(H5TS_cond_broadcast(&barrier->cv))) + HGOTO_DONE(FAIL); + + /* Increment threshold count of threads for next barrier */ + barrier->threshold += barrier->count; + } +#endif + +done: +#ifndef H5_HAVE_PTHREAD_BARRIER + if(have_mutex) + if(H5_UNLIKELY(H5TS_mutex_unlock(&barrier->mutex))) + ret_value = FAIL; +#endif + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__barrier_wait() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__barrier_destroy + * + * Purpose: Destroy an H5TS_barrier_t. All internal components are + * destroyed, but the instance of H5TS_barrier_t is not freed. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__barrier_destroy(H5TS_barrier_t *barrier) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == barrier)) + HGOTO_DONE(FAIL); + +#ifdef H5_HAVE_PTHREAD_BARRIER + if (0 != pthread_barrier_destroy(barrier)) + HGOTO_DONE(FAIL); +#else + + /* Acquire the mutex for the barrier */ + if (H5_UNLIKELY(H5TS_mutex_lock(&barrier->mutex))) + HGOTO_DONE(FAIL); + + /* Check for barrier still in use */ + if (H5_UNLIKELY((barrier->threshold - barrier->entered) != barrier->count)) { + (void)H5TS_mutex_unlock(&barrier->mutex); + HGOTO_DONE(FAIL); + } + + /* Release the barrier's mutex */ + if(H5_UNLIKELY(H5TS_mutex_unlock(&barrier->mutex))) + HGOTO_DONE(FAIL); + + /* Call the appropriate pthread destroy routines. We are committed + * to the destroy at this point, so call them all, even if one fails + * along the way. + */ + if (H5_UNLIKELY(H5TS_mutex_destroy(&barrier->mutex))) + ret_value = FAIL; + if (H5_UNLIKELY(H5TS_cond_destroy(&barrier->cv))) + ret_value = FAIL; +#endif + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__barrier_destroy() */ + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TScond.c b/src/H5TScond.c new file mode 100644 index 00000000000..b0ed28be47f --- /dev/null +++ b/src/H5TScond.c @@ -0,0 +1,288 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 condition variables, equivalent to + * the pthread 'pthread_cond_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_cond_init + * + * Purpose: Initialize a H5TS_cond_t (does not allocate it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_init(H5TS_cond_t *cond) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + InitializeConditionVariable(cond); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_cond_init() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_wait + * + * Purpose: Wait on a condition variable + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_wait(H5TS_cond_t *cond, H5TS_mutex_t *mutex) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(!SleepConditionVariableCS(cond, mutex, INFINITE))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_cond_wait() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_signal + * + * Purpose: Unblock a thread waiting for a condition variable + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_signal(H5TS_cond_t *cond) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + WakeConditionVariable(cond); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_cond_signal() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_broadcast + * + * Purpose: Unblock all threads waiting for a condition variable + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_broadcast(H5TS_cond_t *cond) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + WakeAllConditionVariable(cond); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_cond_broadcast() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_destroy + * + * Purpose: Destroy a H5TS_cond_t (does not free it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_destroy(H5TS_cond_t *cond) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Condition variables in Windows are not destroyed */ + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_cond_destroy() */ + +#else + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_init + * + * Purpose: Initialize a H5TS_cond_t (does not allocate it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_init(H5TS_cond_t *cond) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_cond_init(cond, NULL))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_cond_init() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_wait + * + * Purpose: Wait on a condition variable + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_wait(H5TS_cond_t *cond, H5TS_mutex_t *mutex) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_cond_wait(cond, mutex))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_cond_wait() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_signal + * + * Purpose: Unblock a thread waiting for a condition variable + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_signal(H5TS_cond_t *cond) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_cond_signal(cond))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_cond_signal() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_broadcast + * + * Purpose: Unblock all threads waiting for a condition variable + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_broadcast(H5TS_cond_t *cond) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_cond_broadcast(cond))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_cond_broadcast() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_cond_destroy + * + * Purpose: Destroy a H5TS_cond_t (does not free it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_cond_destroy(H5TS_cond_t *cond) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_cond_destroy(cond))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_cond_destroy() */ + +#endif + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSdevelop.h b/src/H5TSdevelop.h index c3e1a6a65bf..6700d1047d8 100644 --- a/src/H5TSdevelop.h +++ b/src/H5TSdevelop.h @@ -39,9 +39,9 @@ extern "C" { #endif /* HDF5 global library lock routines */ -H5_DLL herr_t H5TSmutex_acquire(unsigned int lock_count, bool *acquired); -H5_DLL herr_t H5TSmutex_release(unsigned int *lock_count); -H5_DLL herr_t H5TSmutex_get_attempt_count(unsigned int *count); +H5_DLL herr_t H5TSmutex_acquire(unsigned lock_count, bool *acquired); +H5_DLL herr_t H5TSmutex_release(unsigned *lock_count); +H5_DLL herr_t H5TSmutex_get_attempt_count(unsigned *count); #ifdef __cplusplus } diff --git a/src/H5TSexlock.c b/src/H5TSexlock.c new file mode 100644 index 00000000000..bac81136529 --- /dev/null +++ b/src/H5TSexlock.c @@ -0,0 +1,372 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 recursive exclusive locks, equivalent to + * the pthread 'pthread_mutex_t' type and capabilities, except that + * threads that hold the lock are allowed to acquire access again + * (and must match each lock with an unlock operation). + * + * 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 */ +/****************/ + +/* Excl lock initialization macro */ +#ifdef H5_HAVE_PTHREAD_H +#define H5TS_EX_LOCK_INIT { \ + H5TS_MUTEX_INITIALIZER, /* mutex */ \ + H5TS_COND_INITIALIZER, /* cond_var */ \ + 0, /* owner_thread */ \ + 0, /* lock_count */ \ + false, /* disable_cancel */ \ + 0 /* previous_state */ \ + } +#else +#define H5TS_EXL_LOCK_INIT { \ + H5TS_MUTEX_INITIALIZER, /* mutex */ \ + H5TS_COND_INITIALIZER, /* cond_var */ \ + 0, /* owner_thread */ \ + 0 /* lock_count */ \ + } +#endif + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Default value to initialize exclusive locks */ +static const H5TS_ex_lock_t H5TS_ex_lock_def = H5TS_EX_LOCK_INIT; + + +/*-------------------------------------------------------------------------- + * Function: H5TS__ex_lock_init + * + * Purpose: Initialize the supplied instance of H5TS_ex_lock_t. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__ex_lock_init(H5TS_ex_lock_t *lock, bool disable_cancel) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Initialize the lock */ + memcpy(lock, &H5TS_ex_lock_def, sizeof(H5TS_ex_lock_def)); + +#ifdef H5_HAVE_PTHREAD_H + /* Set non-default fields */ + lock->disable_cancel = disable_cancel; +#else + (void)disable_cancel; +#endif + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__ex_lock_init() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__ex_lock + * + * Purpose: Acquire a lock on the associated recursive exclusive lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__ex_lock(H5TS_ex_lock_t *lock) +{ + H5TS_thread_t my_thread_id = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Acquire the mutex for the lock */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Check if this thread already owns the lock */ + if (lock->lock_count && H5TS_thread_equal(my_thread_id, lock->owner_thread)) + /* Already owned by self - increment count */ + lock->lock_count++; + else { + /* Wait until the mutex is released by current owner thread */ + while (lock->lock_count) + H5TS_cond_wait(&lock->cond_var, &lock->mutex); + + /* After we've received the signal, take ownership of the lock */ + lock->owner_thread = my_thread_id; + lock->lock_count = 1; + +#ifdef H5_HAVE_PTHREAD_H + /* Disable cancellation, if requested for this lock */ + if (lock->disable_cancel) + /* Set cancellation state to 'disable', and remember previous state */ + if (H5_UNLIKELY(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &lock->previous_state))) + HGOTO_DONE(FAIL); +#endif + } + +done: + if(have_mutex) + if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__ex_lock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__ex_acquire + * + * Purpose: Attempts to acquire an exclusive lock, without blocking + * + * Note: On success, the 'acquired' flag indicates if lock was acquired. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__ex_acquire(H5TS_ex_lock_t *lock, unsigned lock_count, bool *acquired) +{ + bool have_mutex = false; + H5TS_thread_t my_thread_id = H5TS_thread_self(); + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Attempt to acquire the lock's mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Check if locked already */ + if (lock->lock_count) { + /* Check for this thread already owning the lock */ + if (H5TS_thread_equal(my_thread_id, lock->owner_thread)) { + /* Already owned by self - increment count */ + lock->lock_count += lock_count; + *acquired = true; + } + else + *acquired = false; + } + else { + /* Take ownership of the lock */ + lock->owner_thread = my_thread_id; + lock->lock_count = lock_count; + *acquired = true; + } + +done: + /* Release the mutex, if acquired */ + if(have_mutex) + if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__ex_acquire() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__ex_release + * + * Purpose: Release an exclusive lock. Passes back the previous lock count + * to the caller in a parameter. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__ex_release(H5TS_ex_lock_t *lock, unsigned int *lock_count) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Attempt to acquire the lock's mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Reset the lock count for this thread */ + *lock_count = lock->lock_count; + lock->lock_count = 0; + + /* Signal the condition variable, to wake any thread waiting on the lock */ + if (H5_UNLIKELY(H5TS_cond_signal(&lock->cond_var))) + HGOTO_DONE(FAIL); + +done: + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__ex_release */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__ex_unlock + * + * Purpose: Decrements the lock counter, releasing the lock when the counter + * reaches 0. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__ex_unlock(H5TS_ex_lock_t *lock) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Acquire the mutex for the lock */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Decrement the lock count for this thread */ + lock->lock_count--; + + if (lock->lock_count == 0) { +#ifdef H5_HAVE_PTHREAD_H + /* Restore previous cancellation state, if requested for this lock */ + if (lock->disable_cancel) + if (H5_UNLIKELY(pthread_setcancelstate(lock->previous_state, NULL))) + HGOTO_DONE(FAIL); +#endif + + /* If the lock count drops to zero, signal the condition variable, to + * wake any thread waiting on the lock. + */ + if (H5_UNLIKELY(H5TS_cond_signal(&lock->cond_var))) + HGOTO_DONE(FAIL); + } + +done: + if(have_mutex) + if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__ex_unlock */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__ex_lock_destroy + * + * Purpose: Destroy an exlusive lock. All mutex, condition variables, + * etc. are destroyed. However, the instance of H5TS_ex_lock_t + * is not freed. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__ex_lock_destroy(H5TS_ex_lock_t *lock) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex for the lock */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Fail if this thread owns the lock */ + if (lock->lock_count && H5TS_thread_equal(H5TS_thread_self(), lock->owner_thread)) + HGOTO_DONE(FAIL); + + /* Release the mutex for the lock */ + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = false; + + /* Call the appropriate destroy routines. We are committed + * to the destroy at this point, so call them all, even if one fails + * along the way. + */ + if (H5_UNLIKELY(H5TS_mutex_destroy(&lock->mutex))) + ret_value = FAIL; + if (H5_UNLIKELY(H5TS_cond_destroy(&lock->cond_var))) + ret_value = FAIL; + +done: + if(have_mutex) + if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__ex_lock_destroy() */ + +#endif /* H5_HAVE_THREADSAFE */ + diff --git a/src/H5TSint.c b/src/H5TSint.c new file mode 100644 index 00000000000..7d39fdab027 --- /dev/null +++ b/src/H5TSint.c @@ -0,0 +1,534 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 the framework for ensuring that the global + * library lock is held when an API routine is called. This framework + * works in concert with the FUNC_ENTER_API / FUNC_LEAVE_API macros + * defined in H5private.h. + * + * 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 */ +/****************/ + +#define H5E_FRIEND /* Suppress error about including H5Epkg */ +#include "H5TSmodule.h" /* This source code file is part of the H5TS module */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5CXprivate.h" /* API Contexts */ +#include "H5Epkg.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ + +#ifdef H5_HAVE_THREADSAFE + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + +/* Per-thread info */ +typedef struct H5TS_thread_info_t { + uint64_t id; /* Unique ID for each thread */ + struct H5CX_node_t *api_ctx_node_ptr; /* Pointer to an API context node */ + H5E_t err_stack; /* Error stack */ +} H5TS_thread_info_t; + +/* An H5TS_tinfo_node_t is a thread info that is available for reuse */ +typedef struct H5TS_tinfo_node_t { + struct H5TS_tinfo_node_t *next; + H5TS_thread_info_t info; +} H5TS_tinfo_node_t; + + +/********************/ +/* Local Prototypes */ +/********************/ +static H5TS_tinfo_node_t *H5TS__tinfo_create(void); + + +/*********************/ +/* Package Variables */ +/*********************/ + +/* Per-thread info */ +H5TS_key_t H5TS_thrd_info_key_g; + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Has threadsafety code been initialized? */ +#ifdef H5_HAVE_WIN_THREADS +static H5TS_once_t H5TS_first_init_s; +#else +static H5TS_once_t H5TS_first_init_s = PTHREAD_ONCE_INIT; +#endif + + +/* Pointer to first free thread info record or NULL. */ +static H5TS_tinfo_node_t *H5TS_tinfo_next_free_s = NULL; +static uint64_t H5TS_next_thrd_id_s = 0; + +/* Mutex for access to H5TS_tinfo_next_free_s and H5TS_next_thrd_id_s */ +#ifdef H5_HAVE_WIN_THREADS +static H5TS_mutex_t H5TS_tinfo_mtx_s; +#else +static H5TS_mutex_t H5TS_tinfo_mtx_s = PTHREAD_MUTEX_INITIALIZER; +#endif + +/*------------------------------------------------------------------------- + * Function: H5TS_term_package + * + * Purpose: Terminate this interface. + * + * Note: This function is currently registered via atexit() and is called + * AFTER H5_term_library(). + * + * Return: void + * + *------------------------------------------------------------------------- + */ +void +H5TS_term_package(void) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Destroy global API lock */ + H5TS__ex_lock_destroy(&H5TS_api_info_p.api_lock); + + /* Destroy the "lock acquisition attempt" mutex */ + H5TS_mutex_destroy(&H5TS_api_info_p.attempt_mutex); + + /* Clean up per-process thread local storage */ + H5TS__tinfo_term(); + + FUNC_LEAVE_NOAPI_VOID +} /* end H5TS_term_package() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__mutex_acquire + * + * Purpose: Attempts to acquire the API lock, without blocking + * + * Note: On success, the 'acquired' flag indicates if the HDF5 library + * global lock was acquired. + * + * Note: The Windows threads code is very likely bogus. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__mutex_acquire(unsigned int lock_count, bool *acquired) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Attempt to acquire the lock */ + if (H5_UNLIKELY(H5TS__ex_acquire(&H5TS_api_info_p.api_lock, lock_count, acquired) < 0)) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__mutex_acquire() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_api_lock + * + * Purpose: Increment the global "API" lock counter for accessing the HDF5 + * library, acquiring the lock for the thread if the counter is + * initially 0. + * + * Note: Multiple (usually recursive) acquisitions of the "API" lock by + * the same thread is permitted with corresponding unlock + * operation(s). + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS_api_lock(void) +{ + herr_t ret_value = SUCCEED; + + 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 */ + if (H5_UNLIKELY(!H5_INIT_GLOBAL)) + pthread_once(&H5TS_first_init_s, H5TS__pthread_first_thread_init); +#endif /* H5_HAVE_WIN_THREADS */ + + /* Acquire the "attempt" mutex, increment the attempt lock count, release the lock */ + if (H5_UNLIKELY(H5TS_mutex_lock(&H5TS_api_info_p.attempt_mutex))) + HGOTO_DONE(FAIL); + H5TS_api_info_p.attempt_lock_count++; + if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.attempt_mutex))) + HGOTO_DONE(FAIL); + + /* Acquire the library's exclusive API lock */ + if (H5_UNLIKELY(H5TS__ex_lock(&H5TS_api_info_p.api_lock) < 0)) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_api_lock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__mutex_release + * + * Purpose: Release the global "API" lock for accessing the HDF5 library. + * Passes back the previous lock count to the caller in a + * parameter. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__mutex_release(unsigned *lock_count) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Release the library's exclusive API lock */ + if (H5_UNLIKELY(H5TS__ex_release(&H5TS_api_info_p.api_lock, lock_count) < 0)) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__mutex_release */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_api_unlock + * + * Purpose: Decrements the global "API" lock counter for accessing the + * HDF5 library, releasing the lock when the counter reaches 0. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS_api_unlock(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Release the library's exclusive API lock */ + if (H5_UNLIKELY(H5TS__ex_unlock(&H5TS_api_info_p.api_lock) < 0)) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS_api_unlock */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__tinfo_init + * + * Purpose: Initialize thread-local key for per-thread info + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__tinfo_init(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Initialize the critical section for modifying the thread info globals */ + H5TS_mutex_init(&H5TS_tinfo_mtx_s); + + /* Initialize key for thread-specific API contexts */ +#ifdef H5_HAVE_WIN_THREADS + if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (H5TS_thrd_info_key_g = TlsAlloc()))) + ret_value = FAIL; +#else + if (H5_UNLIKELY(pthread_key_create(&H5TS_thrd_info_key_g, H5TS__tinfo_destroy))) + ret_value = FAIL; +#endif + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* end H5TS__tinfo_init() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__tinfo_create + * + * Purpose: Initialize per-thread info and set it for the thread-local key + * + * Return: Pointer to per-thread info node on success / NULL on failure + * + *-------------------------------------------------------------------------- + */ +static H5TS_tinfo_node_t * +H5TS__tinfo_create(void) +{ + uint64_t new_id; + H5TS_tinfo_node_t *tinfo_node; + H5TS_tinfo_node_t *ret_value; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Acquire the lock for modifying the thread info globals */ + /* Note: Must use lock here also, since 'destroy' callback can be + * invoked asynchronously when a thread is joined. + */ + H5TS_mutex_lock(&H5TS_tinfo_mtx_s); + + /* Reuse an info struct that's on the free list if possible */ + if (NULL != (tinfo_node = H5TS_tinfo_next_free_s)) + H5TS_tinfo_next_free_s = tinfo_node->next; + + /* Always use unique ID value for each thread, even when recycling a + * H5TS_tinfo_node_t from the free list. + * + * Note: Don't worry about overflow for ID values + */ + new_id = ++H5TS_next_thrd_id_s; + + /* Release the lock for modifying the thread info globals */ + H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); + + /* If a new info record is needed, allocate it */ + if (NULL == tinfo_node) { + if (H5_UNLIKELY(NULL == (tinfo_node = H5MM_malloc(sizeof(*tinfo_node))))) + HGOTO_DONE(NULL); + tinfo_node->next = NULL; + } + + /* Reset thread info struct */ + memset(tinfo_node, 0, sizeof(*tinfo_node)); + + /* Set up non-zero per-thread info */ + tinfo_node->info.id = new_id; /* ID */ + H5E__set_default_auto(&tinfo_node->info.err_stack); /* Error stack */ + + /* Set a thread-local pointer to the thread's info record */ + if (H5_UNLIKELY(H5TS__set_thread_local_value(H5TS_thrd_info_key_g, tinfo_node))) { + H5TS__tinfo_destroy(tinfo_node); + HGOTO_DONE(NULL); + } + + /* Success */ + ret_value = tinfo_node; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} + +/*-------------------------------------------------------------------------- + * Function: H5TS_thread_id + * + * Purpose: Return an identifier for the current thread. + * + * The ID satisfies the following properties: + * 1) 1 <= ID <= UINT64_MAX + * 2) ID is constant over a thread's lifetime. + * 3) No two threads share an ID + * + * ID 0 is reserved. H5TS_thread_id() returns 0 if the library + * was not built with thread safety or if an error prevents it + * from assigning an ID. + * + * Return: ID for the current thread on success / 0 on failure + * + *-------------------------------------------------------------------------- + */ +uint64_t +H5TS_thread_id(void) +{ + H5TS_tinfo_node_t *tinfo_node; + uint64_t ret_value; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(0); + + /* Set return value */ + ret_value = tinfo_node->info.id; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* H5TS_thread_id() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_get_api_ctx_ptr + * + * Purpose: Retrieve the address of the pointer to the head of API context + * stack for this thread. (i.e. an H5CX_node_t **) + * + * Return: Success: Non-NULL pointer to head pointer of API context stack for thread + * Failure: NULL + * + *-------------------------------------------------------------------------- + */ +struct H5CX_node_t ** +H5TS_get_api_ctx_ptr(void) +{ + H5TS_tinfo_node_t *tinfo_node; + struct H5CX_node_t **ret_value; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(NULL); + + /* Set return value */ + ret_value = &tinfo_node->info.api_ctx_node_ptr; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* H5TS_get_api_ctx_ptr() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_get_err_stack + * + * Purpose: Retrieve the address of error stack for this thread. + * (i.e. an H5E_t *) + * + * Return: Success: Non-NULL pointer to error stack for thread + * Failure: NULL + * + *-------------------------------------------------------------------------- + */ +H5E_t * +H5TS_get_err_stack(void) +{ + H5TS_tinfo_node_t *tinfo_node; + H5E_t *ret_value; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(NULL); + + /* Set return value */ + ret_value = &tinfo_node->info.err_stack; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* H5TS_get_err_stack() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__tinfo_destroy + * + * Purpose: When a thread shuts down, put its info record on the free list. + * + * Note: This routine runs asynchronously _outside_ of the library and + * is not covered by the library's API lock. Therefore, protect + * access to the global variable with a mutex. + * + * Return: None + * + *-------------------------------------------------------------------------- + */ +void +H5TS__tinfo_destroy(void *_tinfo_node) +{ + H5TS_tinfo_node_t *tinfo_node = _tinfo_node; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (tinfo_node) { + /* Add thread info node to the free list */ + H5TS_mutex_lock(&H5TS_tinfo_mtx_s); + tinfo_node->next = H5TS_tinfo_next_free_s; + H5TS_tinfo_next_free_s = tinfo_node; + H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); + } + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} + +/*-------------------------------------------------------------------------- + * Function: H5TS__tinfo_term + * + * Purpose: Terminate per-thread info at library shutdown + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__tinfo_term(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Release nodes on the free list */ + H5TS_mutex_lock(&H5TS_tinfo_mtx_s); + while(H5TS_tinfo_next_free_s) { + H5TS_tinfo_node_t *next = H5TS_tinfo_next_free_s->next; + H5MM_free(H5TS_tinfo_next_free_s); + H5TS_tinfo_next_free_s = next; + } + H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); + + /* Release critical section / mutex for modifying the thread info globals */ + H5TS_mutex_destroy(&H5TS_tinfo_mtx_s); + + /* Release key for thread-specific API contexts */ +#ifdef H5_HAVE_WIN_THREADS + if (H5TS_thrd_info_key_g != TLS_OUT_OF_INDEXES) + if (H5_UNLIKELY(H5TS__key_delete(H5TS_thrd_info_key_g) == 0)) + ret_value = FAIL; +#else + if (H5_UNLIKELY(H5TS__key_delete(H5TS_thrd_info_key_g))) + ret_value = FAIL; +#endif + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* end H5TS__tinfo_term() */ + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSkey.c b/src/H5TSkey.c new file mode 100644 index 00000000000..4076c5e8dce --- /dev/null +++ b/src/H5TSkey.c @@ -0,0 +1,344 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 key operations, + * equivalent to the pthread 'pthread_key_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 */ +/******************/ +#ifdef H5_HAVE_WIN_THREADS + +/* Forward declarations of kwd node structs */ +struct _H5TS_win_kwd_tid_node_t; +struct _H5TS_win_kwd_node_t; + +/* Global list of all kwd's */ +typedef struct _H5TS_win_kwd_node_t { + struct _H5TS_win_kwd_node_t *next; + H5TS_key_t key; + H5TS_key_destructor_func_t dtor; + struct _H5TS_win_kwd_tid_node_t *head_tid_node; +} H5TS_win_kwd_node_t; + +/* Sub-list of all threads that have set a value for a kwd */ +typedef struct _H5TS_win_kwd_tid_node_t { + struct _H5TS_win_kwd_tid_node_t *next; + struct _H5TS_win_kwd_tid_node_t *prev; + uint64_t tid; + H5TS_win_kwd_node_t *kwd_node; +} H5TS_win_kwd_tid_node_t; +#endif + + + +/********************/ +/* Local Prototypes */ +/********************/ +#ifdef H5_HAVE_WIN_THREADS +static herr_t H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor); +static herr_t H5TS__set_kwd(H5TS_key_t key, const void *value); +#endif + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +#ifdef H5_HAVE_WIN_THREADS +/* Per-thread "key with destructor" ("kwd") info */ +static H5TS_key_t H5TS_win_kwd_info_key_s; + +/* Pointer to global list of thread-specific kwd's */ +static H5TS_win_kwd_node_t *H5TS_win_kwd_list_head_s = NULL; + +/* Mutices for access to H5TS_win_kwd_list_head_s & its sub-lists */ +static H5TS_mutex_t H5TS_win_kwd_list_mtx_s; +static H5TS_mutex_t H5TS_win_kwd_sublist_mtx_s; +#endif + + +#ifdef H5_HAVE_WIN_THREADS +/*-------------------------------------------------------------------------- + * Function: H5TS__win_kwd_init + * + * Purpose: Initialize thread-local "key with destructors" infrastructure + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__win_kwd_init(void) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Initialize the mutices for modifying the kwd list & sub-list */ + H5TS_mutex_init(&H5TS_win_kwd_list_mtx_s); + H5TS_mutex_init(&H5TS_win_kwd_sublist_mtx_s); + + /* Initialize "base" key for all the thread-specific "keys w/dtors" lists */ + if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (H5TS_win_kwd_info_key_s = TlsAlloc()))) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* end H5TS__win_kwd_init() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__add_kwd + * + * Purpose: Add a newly created key w/dtor to the global list of keys + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +static herr_t +H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor) +{ + H5TS_win_kwd_node_t *kwd_node; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Sanity checks */ + assert(dtor); + + /* Create the kwd node for the key */ + if (H5_UNLIKELY(NULL == (kwd_node = H5MM_malloc(sizeof(*kwd_node))))) + HGOTO_DONE(FAIL); + kwd_node->key = key; + kwd_node->dtor = dtor; + + /* Acquire the lock for accessing the kwd list */ + H5TS_mutex_lock(&H5TS_win_kwd_list_mtx_s); + +#ifdef H5TS_DEBUG + { + H5TS_win_kwd_node_t *tmp_kwd_node; + + /* Sanity check that the key isn't already in the list */ + tmp_kwd_node = H5TS_win_kwd_list_head_s; + while (NULL != tmp_kwd_node) { + if (H5_UNLIKELY(key == tmp_kwd_node->key)) + HGOTO_DONE(FAIL); + tmp_kwd_node = tmp_kwd_node->next; + } + } +#endif + + /* Add the kwd node to the list */ + kwd_node->next = H5TS_win_kwd_list_head_s; + H5TS_win_kwd_list_head_s = kwd_node; + + /* Release the lock for accessing the kwd list */ + H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* H5TS__add_kwd() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__set_kwd + * + * Purpose: Add a newly set key to the list of keys w/dtors for a thread + * (if the key has a dtor) + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +static herr_t +H5TS__set_kwd(H5TS_key_t key, const void *value) +{ + H5TS_win_kwd_node_t *kwd_node; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Sanity checks */ + assert(value); + + /* Acquire the lock for accessing the kwd list */ + H5TS_mutex_lock(&H5TS_win_kwd_list_mtx_s); + + /* Search the kwd list for the key */ + kwd_node = H5TS_win_kwd_list_head_s; + while (NULL != kwd_node) { + if (key == kwd_node->key) + break; + kwd_node = kwd_node->next; + } + + /* Release the lock for accessing the kwd list */ + H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); + + /* Check if this thread has been inserted already */ + if (NULL != kwd_node) { + H5TS_win_kwd_tid_node_t *kwd_tid_node; + uint64_t thread_id; + + /* Get the ID for this thread */ + if (H5_UNLIKELY(0 == (thread_id = H5TS_thread_id()))) + HGOTO_DONE(FAIL); + + /* Acquire the lock for accessing the kwd sub-list */ + H5TS_mutex_lock(&H5TS_win_kwd_sublist_mtx_s); + + kwd_tid_node = kwd_node->head_tid_node; + while (NULL != kwd_tid_node) { + if (thread_id == kwd_tid_node->tid) + break; + kwd_tid_node = kwd_tid_node->next; + } + + /* Release the lock for accessing the kwd sub-list */ + H5TS_mutex_unlock(&H5TS_win_kwd_sublist_mtx_s); + + /* If this thread isn't in the kwd tid sub-list, add it */ + if (NULL == kwd_tid_node) { + /* Create the kwd tid node for the thread */ + if (H5_UNLIKELY(NULL == (kwd_tid_node = H5MM_calloc(sizeof(*kwd_tid_node))))) + HGOTO_DONE(FAIL); + kwd_tid_node->tid = thread_id; + kwd_tid_node->kwd_node = kwd_node; + + /* Acquire both locks for accessing the kwd list & sub-lists */ + H5TS_mutex_lock(&H5TS_win_kwd_list_mtx_s); + H5TS_mutex_lock(&H5TS_win_kwd_sublist_mtx_s); + + /* Insert the new kwd tid node in the sub-list */ + kwd_tid_node->next = kwd_node->head_tid_node; + if (NULL != kwd_node->head_tid_node) + kwd_node->head_tid_node->prev = kwd_tid_node; + kwd_node->head_tid_node = kwd_tid_node; + + /* Release both locks for accessing the kwd list & sub-lists */ + H5TS_mutex_unlock(&H5TS_win_kwd_sublist_mtx_s); + H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); + } + } + + /* Add the kwd node to the list */ + kwd_node->next = H5TS_win_kwd_list_head_s; + H5TS_win_kwd_list_head_s = kwd_node; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ +} /* H5TS__add_kwd() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_key_create + * + * Purpose: Thread-local key creation + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_key_create(H5TS_key_t *key, H5TS_key_destructor_func_t dtor) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == key)) + HGOTO_DONE(FAIL); + + /* Create the key */ + if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (*key = TlsAlloc()))) + HGOTO_DONE(FAIL); + + /* If the key has a destructor callback, add it to the list of keys w/dtors */ + if (NULL != dtor) + if (H5TS__add_kwd(*key, dtor) < 0) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_key_create() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_key_set_value + * + * Purpose: Set a thread-specific value for a key + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_key_set_value(H5TS_key_t key, const void *value) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Set the value for this thread */ + if (H5_UNLIKELY(0 != TlsSetValue(key, (LPVOID)value))) + HGOTO_DONE(FAIL); + + /* Add the key to the kwd list for this thread, if non-NULL */ + if (NULL != value) + if (H5_UNLIKELY(H5TS_set_kwd(key, value))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_key_create() */ + + + +#endif + +#endif /* H5_HAVE_THREADSAFE */ + diff --git a/src/H5TSmodule.h b/src/H5TSmodule.h new file mode 100644 index 00000000000..2e8bb1d92a6 --- /dev/null +++ b/src/H5TSmodule.h @@ -0,0 +1,28 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 declarations which define macros for the + * H5TS package. Including this header means that the source file + * is part of the H5TS package. + */ +#ifndef H5TSmodule_H +#define H5TSmodule_H + +/* Define the proper control macros for the generic FUNC_ENTER/LEAVE and error + * reporting macros. + */ +#define H5TS_MODULE +#define H5_MY_PKG H5TS +#define H5_MY_PKG_ERR H5E_THREADSAFE + +#endif /* H5TSmodule_H */ diff --git a/src/H5TSmutex.c b/src/H5TSmutex.c new file mode 100644 index 00000000000..a6cc711e97b --- /dev/null +++ b/src/H5TSmutex.c @@ -0,0 +1,292 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 mutex locks, equivalent to the + * pthread 'pthread_mutex_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 */ +/****************/ +#define H5TS_NO_THREAD_SAFETY_ANALYSIS H5_ATTR_THREAD_ANNOT(no_thread_safety_analysis) + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + + +#ifdef H5_HAVE_WIN_THREADS +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_init + * + * Purpose: Initialize a H5TS_mutex_t (does not allocate it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_init(H5TS_mutex_t *mutex) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + InitializeCriticalSection(mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_mutex_init() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_lock + * + * Purpose: Lock a H5TS_mutex_t + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_lock(H5TS_mutex_t *mutex) H5TS_NO_THREAD_SAFETY_ANALYSIS +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + EnterCriticalSection(mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_mutex_lock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_try_lock + * + * Purpose: Attempt to lock a H5TS_mutex_t, sets *acquired to TRUE if so + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_try_lock(H5TS_mutex_t *mutex, bool *acquired) H5TS_NO_THREAD_SAFETY_ANALYSIS +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + *acquired = TryEnterCriticalSection(mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_mutex_try_lock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_unlock + * + * Purpose: Unlock a H5TS_mutex_t + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_unlock(H5TS_mutex_t *mutex) H5TS_NO_THREAD_SAFETY_ANALYSIS +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + LeaveCriticalSection(mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_mutex_unlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_destroy + * + * Purpose: Destroy a H5TS_mutex_t (does not free it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_destroy(H5TS_mutex_t *mutex) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + DeleteCriticalSection(mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_mutex_destroy() */ + +#else +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_init + * + * Purpose: Initialize a H5TS_mutex_t (does not allocate it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_init(H5TS_mutex_t *mutex) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_mutex_init(mutex, NULL))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_mutex_init() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_lock + * + * Purpose: Lock a H5TS_mutex_t + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_lock(H5TS_mutex_t *mutex) H5TS_NO_THREAD_SAFETY_ANALYSIS +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_mutex_lock(mutex))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_mutex_lock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_try_lock + * + * Purpose: Attempt to lock a H5TS_mutex_t, sets *acquired to TRUE if so + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_try_lock(H5TS_mutex_t *mutex, bool *acquired) H5TS_NO_THREAD_SAFETY_ANALYSIS +{ + int rc; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + rc = pthread_mutex_trylock(mutex); + if (0 == rc) + *acquired = true; + else if (EBUSY == rc) + *acquired = false; + else { + assert(EINVAL == rc); + HGOTO_DONE(FAIL); + } + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_mutex_try_lock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_unlock + * + * Purpose: Unlock a H5TS_mutex_t + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_unlock(H5TS_mutex_t *mutex) H5TS_NO_THREAD_SAFETY_ANALYSIS +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_mutex_unlock(mutex))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_mutex_unlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_mutex_destroy + * + * Purpose: Destroy a H5TS_mutex_t (does not free it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_mutex_destroy(H5TS_mutex_t *mutex) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(pthread_mutex_destroy(mutex))) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_mutex_destroy() */ + +#endif + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h new file mode 100644 index 00000000000..97d478b6587 --- /dev/null +++ b/src/H5TSpkg.h @@ -0,0 +1,370 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 declarations which are visible only within + * the H5TS package. Source files outside the H5TS package should + * include H5TSprivate.h instead. + */ +#if !(defined H5TS_FRIEND || defined H5TS_MODULE) +#error "Do not include this file outside the H5TS package!" +#endif + +#ifndef H5TSpkg_H +#define H5TSpkg_H + +#ifdef H5_HAVE_THREADSAFE +/* Get package's private header */ +#include "H5TSprivate.h" + +/* Other private headers needed by this file */ + +/**************************/ +/* Package Private Macros */ +/**************************/ + +#ifdef H5_HAVE_WIN_THREADS + +/* Scope Definitions (Pthreads only) */ +#define H5TS_SCOPE_SYSTEM 0 +#define H5TS_SCOPE_PROCESS 0 + +/* Portability function aliases */ +#define H5TS__get_thread_local_value(key) TlsGetValue(key) +#define H5TS__set_thread_local_value(key, value) TlsSetValue(key, value) +#define H5TS__key_delete(key) TlsFree(key) +#define H5TS__attr_init(attr) 0 +#define H5TS__attr_setscope(attr, scope) 0 +#define H5TS__attr_destroy(attr) 0 +#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) + +#else /* H5_HAVE_WIN_THREADS */ + +/* Scope Definitions (Pthreads only) */ +#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM +#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS + +/* Portability function aliases */ +#define H5TS__get_thread_local_value(key) pthread_getspecific(key) +#define H5TS__set_thread_local_value(key, value) pthread_setspecific(key, value) +#define H5TS__key_delete(key) pthread_key_delete(key) +#define H5TS__attr_init(attr) pthread_attr_init(attr) +#define H5TS__attr_setscope(attr, scope) pthread_attr_setscope(attr, scope) +#define H5TS__attr_destroy(attr) pthread_attr_destroy(attr) +#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) + +#endif /* H5_HAVE_WIN_THREADS */ + + +/****************************/ +/* Package Private Typedefs */ +/****************************/ + +/* Portability wrappers */ +#ifdef H5_HAVE_WIN_THREADS + +typedef HANDLE H5TS_attr_t; +typedef INIT_ONCE H5TS_once_t; + +#else + +typedef pthread_attr_t H5TS_attr_t; +typedef pthread_once_t H5TS_once_t; + +#endif /* H5_HAVE_WIN_THREADS */ + +/* Recursive exclusive locks */ +typedef struct H5TS_ex_lock_t { + H5TS_mutex_t mutex; + H5TS_cond_t cond_var; + H5TS_thread_t owner_thread; + unsigned lock_count; + +/* Thread cancellability only supported with pthreads */ +#ifdef H5_HAVE_PTHREAD_H + /* Cancellation control */ + bool disable_cancel; + int previous_state; +#endif /* H5_HAVE_PTHREAD_H */ +} H5TS_ex_lock_t; + +/* Thread Barrier */ +#ifdef H5_HAVE_PTHREAD_BARRIER +typedef pthread_barrier_t H5TS_barrier_t; +#else +typedef struct H5TS_barrier_t { + H5TS_mutex_t mutex; + H5TS_cond_t cv; + uint64_t count; + uint64_t entered; + uint64_t threshold; +} H5TS_barrier_t; +#endif + +/* Info for the global API lock */ +typedef struct H5TS_api_info_t { + /* API lock */ + H5TS_ex_lock_t api_lock; + + /* Count of # of attempts to acquire API lock */ + H5TS_mutex_t attempt_mutex; /* mutex for attempt_lock_count */ + unsigned attempt_lock_count; +} H5TS_api_info_t; + +#ifdef H5_HAVE_WIN_THREADS + +#else + +/* Enable statistics when H5TS debugging is enabled */ +#ifdef H5TS_DEBUG +#define H5TS_ENABLE_REC_RW_LOCK_STATS 1 +#else +#define H5TS_ENABLE_REC_RW_LOCK_STATS 0 +#endif + +#if H5TS_ENABLE_REC_RW_LOCK_STATS +/****************************************************************************** + * + * Structure H5TS_rw_lock_stats_t + * + * Catchall structure for statistics on the recursive p-threads based + * recursive R/W lock (see declaration of H5TS_rw_lock_t below). + * + * Since the mutex must be held when reading a consistent set of statistics + * from the recursibe R/W lock, it simplifies matters to bundle them into + * a single structure. This structure exists for that purpose. + * + * If you modify this structure, be sure to make equivalent changes to + * the reset_stats code in H5TS__rw_lock_reset_stats(). + * + * Individual fields are: + * + * Read lock stats: + * read_locks_granted: The total number of read locks granted, including + * recursive lock requests. + * + * read_locks_released: The total number of read locks released, including + * recursive lock requests. + * + * real_read_locks_granted: The total number of read locks granted, less + * any recursive lock requests. + * + * real_read_locks_released: The total number of read locks released, + * less any recursive lock releases. + * + * max_read_locks: The maximum number of read locks active at any point + * in time. + * + * max_read_lock_recursion_depth: The maximum recursion depth observed + * for any read lock. + * + * read_locks_delayed: The number of read locks not granted immediately. + * + * + * Write lock stats: + * write_locks_granted: The total number of write locks granted, + * including recursive lock requests. + * + * write_locks_released: The total number of write locks released, + * including recursive lock requests. + * + * real_write_locks_granted: The total number of write locks granted, + * less any recursive lock requests. + * + * real_write_locks_released: The total number of write locks released, + * less any recursive lock requests. + * + * max_write_locks: The maximum number of write locks active at any point + * in time. Must be either zero or one. + * + * max_write_lock_recursion_depth: The maximum recursion depth observed + * for any write lock. + * + * write_locks_delayed: The number of write locks not granted immediately. + * + * max_write_locks_pending: The maximum number of pending write locks at + * any point in time. + * + ******************************************************************************/ + +typedef struct H5TS_rw_lock_stats_t { + int64_t read_locks_granted; + int64_t read_locks_released; + int64_t real_read_locks_granted; + int64_t real_read_locks_released; + int64_t max_read_locks; + int64_t max_read_lock_recursion_depth; + int64_t read_locks_delayed; + int64_t write_locks_granted; + int64_t write_locks_released; + int64_t real_write_locks_granted; + int64_t real_write_locks_released; + int64_t max_write_locks; + int64_t max_write_lock_recursion_depth; + int64_t write_locks_delayed; + int64_t max_write_locks_pending; +} H5TS_rw_lock_stats_t; +#endif + +/****************************************************************************** + * + * Structure H5TS_rw_lock_t + * + * A readers / writer (R/W) lock is a lock that allows either an arbitrary + * number of readers, or a single writer into a critical region. A recursive + * lock is one that allows a thread that already holds a lock (read or + * write) to successfully request the lock again, only dropping the lock + * when the number of unlock calls equals the number of lock calls. + * + * This structure holds the fields needed to implement a recursive R/W lock + * that allows recursive write locks, and for the associated statistics + * collection fields. + * + * Note that we can't use the pthreads or Win32 R/W locks: they permit + * recursive read locks, but disallow recursive write locks. + * + * This recursive R/W lock implementation is an extension of the R/W lock + * implementation given in "UNIX network programming" Volume 2, Chapter 8 + * by w. Richard Stevens, 2nd edition. + * + * Individual fields are: + * + * mutex: Mutex used to maintain mutual exclusion on the fields of + * of this structure. + * + * lock_type: Whether the lock is unused, a reader, or a writer. + * + * writers_cv: Condition variable used for waiting writers. + * + * write_thread: The thread that owns a write lock, which is recursive + * for that thread. + * + * rec_write_lock_count: The # of recursive write locks outstanding + * for the thread that owns the write lock. + * + * waiting_writers_count: The count of waiting writers. + * + * readers_cv: Condition variable used for waiting readers. + * + * active_reader_threads: The # of threads holding a read lock. + * + * rec_read_lock_count_key: Instance of thread-local key used to maintain + * a thread-specific recursive lock count for each thread + * holding a read lock. + * + * stats: Instance of H5TS_rw_lock_stats_t used to track + * statistics on the recursive R/W lock. + * + ******************************************************************************/ + +typedef enum { + UNUSED = 0, /* Lock is currently unused */ + WRITE, /* Lock is a recursive write lock */ + READ /* Lock is a recursive read lock */ +} H5TS_rw_lock_type_t; + +typedef struct H5TS_rw_lock_t { + /* General fields */ + H5TS_mutex_t mutex; + H5TS_rw_lock_type_t lock_type; + + /* Writer fields */ + H5TS_cond_t writers_cv; + H5TS_thread_t write_thread; + int32_t rec_write_lock_count; + int32_t waiting_writers_count; + + /* Reader fields */ + bool is_key_registered; + H5TS_cond_t readers_cv; + int32_t active_reader_threads; + H5TS_key_t rec_read_lock_count_key; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Stats */ + H5TS_rw_lock_stats_t stats; +#endif +} H5TS_rw_lock_t; + +#endif /* H5_HAVE_WIN_THREADS */ + + +/*****************************/ +/* Package Private Variables */ +/*****************************/ + +/* API threadsafety info */ +extern H5TS_api_info_t H5TS_api_info_p; + +/* Per-thread info */ +extern H5TS_key_t H5TS_thrd_info_key_g; + +/******************************/ +/* Package Private Prototypes */ +/******************************/ +herr_t H5TS__mutex_acquire(unsigned lock_count, bool *acquired); +herr_t H5TS__mutex_release(unsigned *lock_count); +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 */ + +/* Thread-specific key routines */ +#ifdef H5_HAVE_WIN_THREADS +H5_DLL herr_t H5TS__win_kwd_init(void); +#endif + +/* 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); +H5_DLL herr_t H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock); +H5_DLL herr_t H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock); +H5_DLL herr_t H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock); + +/* Recursive exclusive lock related function declarations */ +H5_DLL herr_t H5TS__ex_lock_init(H5TS_ex_lock_t *lock, bool disable_cancel); +H5_DLL herr_t H5TS__ex_lock(H5TS_ex_lock_t *lock); +H5_DLL herr_t H5TS__ex_acquire(H5TS_ex_lock_t *lock, unsigned lock_count, bool *acquired); +H5_DLL herr_t H5TS__ex_release(H5TS_ex_lock_t *lock, unsigned int *lock_count); +H5_DLL herr_t H5TS__ex_unlock(H5TS_ex_lock_t *lock); +H5_DLL herr_t H5TS__ex_lock_destroy(H5TS_ex_lock_t *lock); + +/* Barrier related function declarations */ +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); + +#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); +H5_DLL herr_t H5TS__rw_lock_reset_stats(H5TS_rw_lock_t *rw_lock); +H5_DLL herr_t H5TS__rw_lock_print_stats(const char *header_str, H5TS_rw_lock_stats_t *stats); +#endif + +/* Testing routines */ +H5_DLL H5TS_thread_t H5TS__create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata); + +#endif /* H5TS_TESTING */ + +#endif /* H5_HAVE_THREADSAFE */ + +#endif /* H5TSpkg_H */ diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index e24c409437c..56da21d6f12 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -25,111 +25,105 @@ /* Include package's public headers */ #include "H5TSdevelop.h" +/**************************/ +/* Library Private Macros */ +/**************************/ + +/* Thread-safety sanity-checking annotations */ +#define H5TS_CAPABILITY(x) H5_ATTR_THREAD_ANNOT(capability(x)) +#define H5TS_ACQUIRE(...) H5_ATTR_THREAD_ANNOT(acquire_capability(__VA_ARGS__)) +#define H5TS_ACQUIRE_SHARED(...) H5_ATTR_THREAD_ANNOT(acquire_shared_capability(__VA_ARGS__)) +#define H5TS_RELEASE(...) H5_ATTR_THREAD_ANNOT(release_capability(__VA_ARGS__)) +#define H5TS_RELEASE_SHARED(...) H5_ATTR_THREAD_ANNOT(release_shared_capability(__VA_ARGS__)) +#define H5TS_TRY_ACQUIRE(...) H5_ATTR_THREAD_ANNOT(try_acquire_capability(__VA_ARGS__)) +#define H5TS_TRY_ACQUIRE_SHARED(...) H5_ATTR_THREAD_ANNOT(try_acquire_shared_capability(__VA_ARGS__)) + +/* Static initialization values */ #ifdef H5_HAVE_WIN_THREADS +#define H5TS_KEY_INITIALIZER {NULL, 0, NULL} +#define H5TS_MUTEX_INITIALIZER {NULL} +#define H5TS_COND_INITIALIZER CONDITION_VARIABLE_INIT +#else +#define H5TS_KEY_INITIALIZER (pthread_key_t)0 +#define H5TS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define H5TS_COND_INITIALIZER PTHREAD_COND_INITIALIZER +#endif + +/* Thread macros */ +#ifdef H5_HAVE_WIN_THREADS +#define H5TS_thread_self() GetCurrentThread() +#define H5TS_thread_equal(t1, t2) (GetThreadId(t1) == GetThreadId(t2)) +#else +#define H5TS_thread_self() pthread_self() +#define H5TS_thread_equal(t1, t2) pthread_equal(t1, t2) +#endif -/* Library level data structures */ - -/* Mutexes, Threads, and Attributes */ -typedef struct H5TS_mutex_struct { - CRITICAL_SECTION CriticalSection; -} H5TS_mutex_t; - -/* Portability wrappers around Windows Threads types */ -typedef CRITICAL_SECTION H5TS_mutex_simple_t; -typedef HANDLE H5TS_thread_t; -typedef HANDLE H5TS_attr_t; -typedef DWORD H5TS_key_t; -typedef INIT_ONCE H5TS_once_t; - -/* Defines */ -/* not used on windows side, but need to be defined to something */ -#define H5TS_SCOPE_SYSTEM 0 -#define H5TS_SCOPE_PROCESS 0 -#define H5TS_CALL_CONV WINAPI - -/* Portability function aliases */ -#define H5TS_get_thread_local_value(key) TlsGetValue(key) -#define H5TS_set_thread_local_value(key, value) TlsSetValue(key, value) -#define H5TS_attr_init(attr_ptr) 0 -#define H5TS_attr_setscope(attr_ptr, scope) 0 -#define H5TS_attr_destroy(attr_ptr) 0 -#define H5TS_wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) -#define H5TS_mutex_init(mutex) InitializeCriticalSection(mutex) -#define H5TS_mutex_lock_simple(mutex) EnterCriticalSection(mutex) -#define H5TS_mutex_unlock_simple(mutex) LeaveCriticalSection(mutex) - -/* Functions called from DllMain */ -H5_DLL BOOL CALLBACK H5TS_win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex); -H5_DLL void H5TS_win32_process_exit(void); -H5_DLL herr_t H5TS_win32_thread_enter(void); -H5_DLL herr_t H5TS_win32_thread_exit(void); - -#define H5TS_thread_id() ((uint64_t)GetCurrentThreadId()) - -#else /* H5_HAVE_WIN_THREADS */ - -/* Library level data structures */ - -/* Mutexes, Threads, and Attributes */ -typedef struct H5TS_mutex_struct { - pthread_t owner_thread; /* current lock owner */ - pthread_mutex_t atomic_lock; /* lock for atomicity of new mechanism */ - pthread_cond_t cond_var; /* condition variable */ - unsigned int lock_count; - - pthread_mutex_t atomic_lock2; /* lock for attempt_lock_count */ - unsigned int attempt_lock_count; -} H5TS_mutex_t; - -/* Portability wrappers around pthread types */ -typedef pthread_t H5TS_thread_t; -typedef pthread_attr_t H5TS_attr_t; -typedef pthread_mutex_t H5TS_mutex_simple_t; -typedef pthread_key_t H5TS_key_t; -typedef pthread_once_t H5TS_once_t; - -/* Scope Definitions */ -#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM -#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS -#define H5TS_CALL_CONV /* unused - Windows only */ - -/* Portability function aliases */ -#define H5TS_get_thread_local_value(key) pthread_getspecific(key) -#define H5TS_set_thread_local_value(key, value) pthread_setspecific(key, value) -#define H5TS_attr_init(attr_ptr) pthread_attr_init((attr_ptr)) -#define H5TS_attr_setscope(attr_ptr, scope) pthread_attr_setscope(attr_ptr, scope) -#define H5TS_attr_destroy(attr_ptr) pthread_attr_destroy(attr_ptr) -#define H5TS_wait_for_thread(thread) pthread_join(thread, NULL) -#define H5TS_mutex_init(mutex) pthread_mutex_init(mutex, NULL) -#define H5TS_mutex_lock_simple(mutex) pthread_mutex_lock(mutex) -#define H5TS_mutex_unlock_simple(mutex) pthread_mutex_unlock(mutex) - -/* Pthread-only routines */ -H5_DLL uint64_t H5TS_thread_id(void); -H5_DLL void H5TS_pthread_first_thread_init(void); +/****************************/ +/* Library Private Typedefs */ +/****************************/ -#endif /* H5_HAVE_WIN_THREADS */ +/* Key destructor callback */ +typedef void (*H5TS_key_destructor_func_t)(void *); -/* Library-scope global variables */ -extern H5TS_once_t H5TS_first_init_g; /* Library initialization */ -extern H5TS_key_t H5TS_errstk_key_g; /* Error stacks */ -#ifdef H5_HAVE_CODESTACK -extern H5TS_key_t H5TS_funcstk_key_g; /* Function stacks */ -#endif /* H5_HAVE_CODESTACK */ -extern H5TS_key_t H5TS_apictx_key_g; /* API contexts */ +/* Portability aliases */ +#ifdef H5_HAVE_WIN_THREADS +typedef HANDLE H5TS_thread_t; +typedef DWORD H5TS_key_t; +typedef CRITICAL_SECTION H5TS_CAPABILITY("mutex") H5TS_mutex_t; +typedef CONDITION_VARIABLE H5TS_cond_t; +#else +typedef pthread_t H5TS_thread_t; +typedef pthread_key_t H5TS_key_t; +typedef pthread_mutex_t H5TS_CAPABILITY("mutex") H5TS_mutex_t; +typedef pthread_cond_t H5TS_cond_t; +#endif + +/*****************************/ +/* Library-private Variables */ +/*****************************/ + + +/***************************************/ +/* Library-private Function Prototypes */ +/***************************************/ + +/* Library/thread init/term operations */ +H5_DLL void H5TS_term_package(void); +#ifdef H5_HAVE_WIN_THREADS +H5_DLL herr_t H5TS_win32_thread_enter(void); +H5_DLL herr_t H5TS_win32_thread_exit(void); +#endif /* H5_HAVE_WIN_THREADS */ -/* Library-scope routines */ -/* (Only used within H5private.h macros) */ -H5_DLL herr_t H5TS_mutex_lock(H5TS_mutex_t *mutex); -H5_DLL herr_t H5TS_mutex_unlock(H5TS_mutex_t *mutex); -H5_DLL herr_t H5TS_cancel_count_inc(void); -H5_DLL herr_t H5TS_cancel_count_dec(void); +/* API locking */ +H5_DLL herr_t H5TS_api_lock(void); +H5_DLL herr_t H5TS_api_unlock(void); -/* Testing routines */ -H5_DLL H5TS_thread_t H5TS_create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata); +/* Retrieve per-thread info */ +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); + +/* 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); +H5_DLL herr_t H5TS_mutex_try_lock(H5TS_mutex_t *mutex, bool *acquired) H5TS_TRY_ACQUIRE(SUCCEED, *mutex); +H5_DLL herr_t H5TS_mutex_unlock(H5TS_mutex_t *mutex) H5TS_RELEASE(*mutex); +H5_DLL herr_t H5TS_mutex_destroy(H5TS_mutex_t *mutex); + +/* Condition variable operations */ +H5_DLL herr_t H5TS_cond_init(H5TS_cond_t *cond); +H5_DLL herr_t H5TS_cond_wait(H5TS_cond_t *cond, H5TS_mutex_t *mutex); +H5_DLL herr_t H5TS_cond_signal(H5TS_cond_t *cond); +H5_DLL herr_t H5TS_cond_broadcast(H5TS_cond_t *cond); +H5_DLL herr_t H5TS_cond_destroy(H5TS_cond_t *cond); + +/* Thread-specific keys */ +H5_DLL herr_t H5TS_key_create(H5TS_key_t *key, H5TS_key_destructor_func_t dtor); +H5_DLL herr_t H5TS_key_set_value(H5TS_key_t key, const void *value); #else /* H5_HAVE_THREADSAFE */ +/* Non-threadsafe code needs this */ #define H5TS_thread_id() ((uint64_t)0) #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSpthread.c b/src/H5TSpthread.c new file mode 100644 index 00000000000..a0c3352128c --- /dev/null +++ b/src/H5TSpthread.c @@ -0,0 +1,791 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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: Pthread threadsafety routines + * + * 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 */ +#define H5TS_TESTING /* Suppress warning about H5TS testing funcs */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ + +#ifdef H5_HAVE_THREADSAFE + +#ifndef H5_HAVE_WIN_THREADS + +/****************/ +/* Local Macros */ +/****************/ + +/* R/W lock initialization macro */ +#if H5TS_ENABLE_REC_RW_LOCK_STATS +#define H5TS_RW_LOCK_INIT { \ + PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ + (H5TS_rw_lock_type_t)UNUSED, /* lock_type */ \ + PTHREAD_COND_INITIALIZER, /* writers_cv */ \ + 0, /* write_thread */ \ + 0, /* rec_write_lock_count */ \ + 0, /* waiting_writers_count */ \ + false, /* is_key_registered */ \ + PTHREAD_COND_INITIALIZER, /* readers_cv */ \ + 0, /* active_reader_threads */ \ + (H5TS_key_t)0, /* rec_read_lock_count_key */ \ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* stats */ \ + } +#else +#define H5TS_RW_LOCK_INIT { \ + PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ + (H5TS_rw_lock_type_t)UNUSED, /* lock_type */ \ + PTHREAD_COND_INITIALIZER, /* writers_cv */ \ + 0, /* write_thread */ \ + 0, /* rec_write_lock_count */ \ + 0, /* waiting_writers_count */ \ + false, /* is_key_registered */ \ + PTHREAD_COND_INITIALIZER, /* readers_cv */ \ + 0, /* active_reader_threads */ \ + (H5TS_key_t)0 /* rec_read_lock_count_key */ \ + } +#endif + + +/******************/ +/* Local Typedefs */ +/******************/ + +/****************************************************************************** + * + * Structure H5TS_rec_read_entry_count_t + * + * Structure associated with the rec_read_lock_count_key defined in + * H5TS_rw_lock_t. + * + * This structure maintains a count of recursive read locks so that the lock can + * be decrements when the thread-specific count drops to zero. + * + * Individual fields are: + * + * rec_lock_count: Count of the number of recursive lock calls, less + * the number of recursive unlock calls. The lock in question + * is decremented when the count drops to zero. + * + ******************************************************************************/ + +typedef struct H5TS_rec_entry_count { + int64_t rec_lock_count; +} H5TS_rec_entry_count_t; + + +/********************/ +/* Local Prototypes */ +/********************/ + +static void H5TS__key_destructor(void *key_val); + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +/* Default value to initialize R/W locks */ +static const H5TS_rw_lock_t H5TS_rw_lock_def = H5TS_RW_LOCK_INIT; + + +/*-------------------------------------------------------------------------- + * Function: H5TS__key_destructor + * + * Purpose: Frees the memory for a key. Called by each thread as it exits. + * Currently all the thread-specific information for all keys are + * simple structures allocated with malloc, so we can free them + * all uniformly. + * + * Return: None + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__key_destructor(void *key_val) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Use free here instead of H5MM_xfree(), to avoid calling the H5CS routines */ + if (NULL != key_val) + free(key_val); + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__key_destructor() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__pthread_first_thread_init + * + * Purpose: Initialize global API lock, keys for per-thread error stacks + * and cancallability information. Called by the first thread + * that enters the library. + * + * Return: None + * + *-------------------------------------------------------------------------- + */ +void +H5TS__pthread_first_thread_init(void) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Initialize global API lock */ + H5TS__ex_lock_init(&H5TS_api_info_p.api_lock, true); + + /* Initialize the "lock acquisition attempt" mutex & counter */ + H5TS_mutex_init(&H5TS_api_info_p.attempt_mutex); + H5TS_api_info_p.attempt_lock_count = 0; + + /* Set up thread-local thread-info struct */ + H5TS__tinfo_init(); + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__pthread_first_thread_init() */ + +#if H5TS_ENABLE_REC_RW_LOCK_STATS +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_rd_lock + * + * Purpose: Update stats for acquiring a read lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_rd_lock(H5TS_rw_lock_t *rw_lock, const H5TS_rec_entry_count_t *count) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(rw_lock); + assert(READ == rw_lock->lock_type); + assert(count); + assert(count->rec_lock_count >= 1); + + rw_lock->stats.read_locks_granted++; + + if (count->rec_lock_count == 1) { + rw_lock->stats.real_read_locks_granted++; + if (rw_lock->active_reader_threads > rw_lock->stats.max_read_locks) + rw_lock->stats.max_read_locks = rw_lock->active_reader_threads; + } + + if (count->rec_lock_count > rw_lock->stats.max_read_lock_recursion_depth) + rw_lock->stats.max_read_lock_recursion_depth = count->rec_lock_count; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_rd_lock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_rd_lock_delay + * + * Purpose: Update stats for delay in acquiring a read lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_rd_lock_delay(H5TS_rw_lock_t *rw_lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(rw_lock); + + rw_lock->stats.read_locks_delayed++; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_rd_lock_delay() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_rd_unlock + * + * Purpose: Update stats for releasing a read lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_rd_unlock(H5TS_rw_lock_t *rw_lock, const H5TS_rec_entry_count_t *count) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(rw_lock); + assert(READ == rw_lock->lock_type); + assert(count); + assert(count->rec_lock_count >= 0); + + rw_lock->stats.read_locks_released++; + + if (count->rec_lock_count == 0) + rw_lock->stats.real_read_locks_released++; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_rd_unlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_wr_lock + * + * Purpose: Update stats for acquiring a write lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_wr_lock(H5TS_rw_lock_t *rw_lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(rw_lock); + assert(WRITE == rw_lock->lock_type); + assert(rw_lock->rec_write_lock_count >= 1); + + rw_lock->stats.write_locks_granted++; + + if (rw_lock->rec_write_lock_count == 1) { + rw_lock->stats.real_write_locks_granted++; + if (rw_lock->rec_write_lock_count > rw_lock->stats.max_write_locks) + rw_lock->stats.max_write_locks = rw_lock->rec_write_lock_count; + } + + if (rw_lock->rec_write_lock_count > rw_lock->stats.max_write_lock_recursion_depth) + rw_lock->stats.max_write_lock_recursion_depth = rw_lock->rec_write_lock_count; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_wr_lock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_wr_lock_delay + * + * Purpose: Update stats for delay in acquiring a write lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_wr_lock_delay(H5TS_rw_lock_t *rw_lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(rw_lock); + + rw_lock->stats.write_locks_delayed++; + + if (rw_lock->stats.max_write_locks_pending <= rw_lock->waiting_writers_count) + rw_lock->stats.max_write_locks_pending = rw_lock->waiting_writers_count + 1; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_wr_lock_delay() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_wr_unlock + * + * Purpose: Update stats for releasing a write lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_wr_unlock(H5TS_rw_lock_t *rw_lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(rw_lock); + assert(WRITE == rw_lock->lock_type); + assert(rw_lock->rec_write_lock_count >= 0); + + rw_lock->stats.write_locks_released++; + + if (rw_lock->rec_write_lock_count == 0) + rw_lock->stats.real_write_locks_released++; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_wr_unlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_lock_get_stats + * + * Purpose: Obtain a copy of the current statistics for a recursive + * read / write lock. + * + * Note: To obtain a consistent set of statistics, the function must + * obtain the lock mutex. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock || NULL == stats)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Copy R/W lock stats */ + *stats = rw_lock->stats; + +done: + if (have_mutex) + H5TS_mutex_unlock(&rw_lock->mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_lock_get_stats() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_lock_reset_stats + * + * Purpose: Reset the statistics for the supplied recursive read / write + * lock. + * + * Note: To obtain a consistent set of statistics, the function must + * obtain the lock mutex. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_lock_reset_stats(H5TS_rw_lock_t *rw_lock) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Reset stats */ + memset(&rw_lock->stats, 0, sizeof(rw_lock->stats)); + +done: + if (have_mutex) + H5TS_mutex_unlock(&rw_lock->mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_lock_reset_stats() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_lock_print_stats + * + * Purpose: Print the supplied pthresds recursive R/W lock statistics. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_lock_print_stats(const char *header_str, H5TS_rw_lock_stats_t *stats) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == header_str || NULL == stats)) + HGOTO_DONE(FAIL); + + fprintf(stdout, "\n\n%s\n\n", header_str); + fprintf(stdout, " read_locks_granted = %" PRId64 "\n", stats->read_locks_granted); + fprintf(stdout, " read_locks_released = %" PRId64 "\n", stats->read_locks_released); + fprintf(stdout, " real_read_locks_granted = %" PRId64 "\n", stats->real_read_locks_granted); + fprintf(stdout, " real_read_locks_released = %" PRId64 "\n", stats->real_read_locks_released); + fprintf(stdout, " max_read_locks = %" PRId64 "\n", stats->max_read_locks); + fprintf(stdout, " max_read_lock_recursion_depth = %" PRId64 "\n", stats->max_read_lock_recursion_depth); + fprintf(stdout, " read_locks_delayed = %" PRId64 "\n", stats->read_locks_delayed); + fprintf(stdout, " write_locks_granted = %" PRId64 "\n", stats->write_locks_granted); + fprintf(stdout, " write_locks_released = %" PRId64 "\n", stats->write_locks_released); + fprintf(stdout, " real_write_locks_granted = %" PRId64 "\n", stats->real_write_locks_granted); + fprintf(stdout, " real_write_locks_released = %" PRId64 "\n", stats->real_write_locks_released); + fprintf(stdout, " max_write_locks = %" PRId64 "\n", stats->max_write_locks); + fprintf(stdout, " max_write_lock_recursion_depth = %" PRId64 "\n", stats->max_write_lock_recursion_depth); + fprintf(stdout, " write_locks_delayed = %" PRId64 "\n", stats->write_locks_delayed); + fprintf(stdout, " max_write_locks_pending = %" PRId64 "\n\n", stats->max_write_locks_pending); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_lock_print_stats() */ +#endif /* H5TS_ENABLE_REC_RW_LOCK_STATS */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_lock_init + * + * Purpose: Initialize the supplied instance of H5TS_rw_lock_t. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_lock_init(H5TS_rw_lock_t *rw_lock) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock)) + HGOTO_DONE(FAIL); + + /* Initialize the lock */ + memcpy(rw_lock, &H5TS_rw_lock_def, sizeof(H5TS_rw_lock_def)); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_lock_init() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_lock_destroy + * + * Purpose: Take down an instance of H5TS_rw_lock_t. All mutex, condition + * variables, and keys are destroyed. However, the instance of + * H5TS_rw_lock_t is not freed. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock)) + HGOTO_DONE(FAIL); + + /* Call the appropriate pthread destroy routines. We are committed + * to the destroy at this point, so call them all, even if one fails + * along the way. + */ + if (H5_UNLIKELY(H5TS_mutex_destroy(&rw_lock->mutex))) + ret_value = FAIL; + if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->readers_cv))) + ret_value = FAIL; + if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->writers_cv))) + ret_value = FAIL; + if (rw_lock->is_key_registered) + if (H5_UNLIKELY(H5TS__key_delete(rw_lock->rec_read_lock_count_key))) + ret_value = FAIL; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_lock_destroy() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_rdlock + * + * Purpose: Attempt to obtain a read lock on the associated recursive + * read / write lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) +{ + H5TS_rec_entry_count_t *count; + H5TS_thread_t my_thread_id = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Fail if attempting to acquire a read lock on a thread that holds + * a write lock + */ + if (H5_UNLIKELY(WRITE == rw_lock->lock_type && pthread_equal(my_thread_id, rw_lock->write_thread))) + HGOTO_DONE(FAIL); + + /* If there is no thread-specific data for this thread, set it up */ + if (!rw_lock->is_key_registered) { + if (H5_UNLIKELY(pthread_key_create(&rw_lock->rec_read_lock_count_key, H5TS__key_destructor))) + HGOTO_DONE(FAIL); + rw_lock->is_key_registered = true; + count = NULL; + } + else + count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); + if (NULL == count) { + if (H5_UNLIKELY(NULL == (count = calloc(1, sizeof(*count))))) + HGOTO_DONE(FAIL); + + if (H5_UNLIKELY(H5TS__set_thread_local_value(rw_lock->rec_read_lock_count_key, (void *)count))) + HGOTO_DONE(FAIL); + } + + if (count->rec_lock_count > 0) { /* This is a recursive lock */ + assert(READ == rw_lock->lock_type); + assert(rw_lock->active_reader_threads > 0 && rw_lock->rec_write_lock_count == 0); + } + else { /* This is an initial read lock request, on this thread */ + /* Readers defer to current or pending writers */ + if (WRITE == rw_lock->lock_type) { +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS__update_stats_rd_lock_delay(rw_lock); +#endif + + do { + if (H5_UNLIKELY(H5TS_cond_wait(&rw_lock->readers_cv, &rw_lock->mutex))) + HGOTO_DONE(FAIL); + } while (WRITE == rw_lock->lock_type); + } + + /* Set counter's lock type (which might already be set) & increment + * number of reader threads + */ + rw_lock->lock_type = READ; + rw_lock->active_reader_threads++; + } + + /* Increment read lock count for this thread */ + count->rec_lock_count++; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS__update_stats_rd_lock(rw_lock, count); +#endif + +done: + if (have_mutex) + H5TS_mutex_unlock(&rw_lock->mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_rdlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_wrlock + * + * Purpose: Attempt to obtain a write lock on the associated recursive + * read / write lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) +{ + H5TS_thread_t my_thread_id = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Check for initial write lock request on this thread */ + if (WRITE != rw_lock->lock_type || !pthread_equal(my_thread_id, rw_lock->write_thread)) { + /* Fail if attempting to acquire a write lock on a thread that holds + * a read lock + */ + if (READ == rw_lock->lock_type) { + H5TS_rec_entry_count_t *count; + + /* Sanity check */ + assert(rw_lock->is_key_registered); + + /* Fail if read lock count for this thread is > 0 */ + count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); + if (H5_UNLIKELY(NULL != count && count->rec_lock_count > 0)) + HGOTO_DONE(FAIL); + } + + /* If lock is already held, wait to acquire it */ + if (UNUSED != rw_lock->lock_type) { +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS__update_stats_wr_lock_delay(rw_lock); +#endif + + do { + int result; + + rw_lock->waiting_writers_count++; + result = H5TS_cond_wait(&rw_lock->writers_cv, &rw_lock->mutex); + rw_lock->waiting_writers_count--; + if (H5_UNLIKELY(result != 0)) + HGOTO_DONE(FAIL); + } while (UNUSED != rw_lock->lock_type); + } + + /* Set lock type & owner thread */ + rw_lock->lock_type = WRITE; + rw_lock->write_thread = my_thread_id; + } + + /* Increment write lock count for this thread */ + rw_lock->rec_write_lock_count++; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS__update_stats_wr_lock(rw_lock); +#endif + +done: + if (have_mutex) + H5TS_mutex_unlock(&rw_lock->mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_wrlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rw_unlock + * + * Purpose: Attempt to unlock either a read or a write lock on a + * recursive read / write lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == rw_lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Error check */ + if (H5_UNLIKELY(UNUSED == rw_lock->lock_type)) /* Unlocking an unused lock? */ + HGOTO_DONE(FAIL); + + if (WRITE == rw_lock->lock_type) { /* Drop a write lock */ + /* Sanity checks */ + assert(0 == rw_lock->active_reader_threads); + assert(rw_lock->rec_write_lock_count > 0); + + /* Decrement recursive lock count */ + rw_lock->rec_write_lock_count--; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS__update_stats_wr_unlock(rw_lock); +#endif + + /* Check if lock is unused now */ + if (0 == rw_lock->rec_write_lock_count) + rw_lock->lock_type = UNUSED; + } + else { /* Drop a read lock */ + H5TS_rec_entry_count_t *count; + + /* Sanity and error checks */ + assert(rw_lock->is_key_registered); + assert(rw_lock->active_reader_threads > 0); + assert(0 == rw_lock->rec_write_lock_count); + count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); + if (H5_UNLIKELY(NULL == count)) + HGOTO_DONE(FAIL); + assert(count->rec_lock_count > 0); + + /* Decrement recursive lock count for this thread */ + count->rec_lock_count--; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS__update_stats_rd_unlock(rw_lock, count); +#endif + + /* Check if this thread is releasing its last read lock */ + if (0 == count->rec_lock_count) { + /* Decrement the # of threads with a read lock */ + rw_lock->active_reader_threads--; + + /* Check if lock is unused now */ + if (0 == rw_lock->active_reader_threads) + rw_lock->lock_type = UNUSED; + } + } + + /* Signal condition variable if lock is unused now */ + if (UNUSED == rw_lock->lock_type) { + /* Prioritize pending writers if there are any */ + if (rw_lock->waiting_writers_count > 0) { + if (H5_UNLIKELY(H5TS_cond_signal(&rw_lock->writers_cv))) + HGOTO_DONE(FAIL); + } + else { + if (H5_UNLIKELY(H5TS_cond_broadcast(&rw_lock->readers_cv))) + HGOTO_DONE(FAIL); + } + } + +done: + if (have_mutex) + H5TS_mutex_unlock(&rw_lock->mutex); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rw_unlock() */ + +#endif /* H5_HAVE_WIN_THREADS */ + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSrwlock.c b/src/H5TSrwlock.c new file mode 100644 index 00000000000..a454c25facb --- /dev/null +++ b/src/H5TSrwlock.c @@ -0,0 +1,71 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 recursive R/W locks, equivalent to + * the pthread 'pthread_rwlock_t' type and capabilities, except that + * threads that hold write access for the lock are allowed to acquire + * write access again (and must match each lock with an unlock operation). + * + * 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 */ +/*******************/ + + + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TStest.c b/src/H5TStest.c new file mode 100644 index 00000000000..3ddbab9c92f --- /dev/null +++ b/src/H5TStest.c @@ -0,0 +1,107 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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: Threadsafety testing functions + * + * 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 */ +#define H5TS_TESTING /* Suppress warning about H5TS testing funcs */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5TSpkg.h" /* Threadsafety */ + +#ifdef H5_HAVE_THREADSAFE + +/****************/ +/* Local Macros */ +/****************/ + +/******************/ +/* Local Typedefs */ +/******************/ + +/* Function pointer typedef for thread callback function */ +typedef void *(*H5TS_thread_cb_t)(void *); + +/********************/ +/* Local Prototypes */ +/********************/ + +/*********************/ +/* Package Variables */ +/*********************/ + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + +/*******************/ +/* Local Variables */ +/*******************/ + + +/*-------------------------------------------------------------------------- + * NAME + * H5TS__create_thread + * + * RETURNS + * Thread identifier. + * + * DESCRIPTION + * Spawn off a new thread calling function 'func' with input 'udata'. + * + *-------------------------------------------------------------------------- + */ +H5TS_thread_t +H5TS__create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata) +{ + H5TS_thread_t ret_value; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + +#ifdef H5_HAVE_WIN_THREADS + /* When calling C runtime functions, you should use _beginthread or + * _beginthreadex instead of CreateThread. Threads created with + * CreateThread risk being killed in low-memory situations. Since we + * only create threads in our test code, this is unlikely to be an issue + * and we'll use the easier-to-deal-with CreateThread for now. + * + * NOTE: _beginthread() auto-recycles its handle when execution completes + * so you can't wait on it, making it unsuitable for the existing + * test code. + */ + ret_value = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, udata, 0, NULL); + +#else /* H5_HAVE_WIN_THREADS */ + + pthread_create(&ret_value, attr, (void *(*)(void *))func, udata); + +#endif /* H5_HAVE_WIN_THREADS */ + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__create_thread */ + +#endif /* H5_HAVE_THREADSAFE */ + diff --git a/src/H5TSthread.c b/src/H5TSthread.c new file mode 100644 index 00000000000..209d67e1339 --- /dev/null +++ b/src/H5TSthread.c @@ -0,0 +1,69 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 operations, equivalent to + * the pthread 'pthread_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 */ +/*******************/ + + + +#endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSwin.c b/src/H5TSwin.c new file mode 100644 index 00000000000..18c306ab1a5 --- /dev/null +++ b/src/H5TSwin.c @@ -0,0 +1,164 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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: Windows threadsafety routines + * + * 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 + +#ifdef H5_HAVE_WIN_THREADS + +/****************/ +/* Local Macros */ +/****************/ + + +/******************/ +/* Local Typedefs */ +/******************/ + + +/********************/ +/* Local Prototypes */ +/********************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + + +/*-------------------------------------------------------------------------- + * Function: H5TS__win32_process_enter + * + * Purpose: Per-process setup on Windows when using Win32 threads. + * + * Returns: TRUE on success, FALSE on failure + * + *-------------------------------------------------------------------------- + */ +H5_DLL BOOL CALLBACK +H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) +{ + BOOL ret_value = TRUE; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Initialize global API lock */ + H5TS__ex_lock_init(&H5TS_api_info_p.api_lock, true); + + /* Initialize the global "lock acquisition attempt" critical section & counter */ + H5TS_mutex_init(&H5TS_api_info_p.attempt_mutex); + H5TS_api_info_p.attempt_lock_count = 0; + + /* Set up per-thread key infrastructure */ + if (H5_UNLIKELY(H5TS__win_kwd_init() < 0)) + ret_value = FALSE; + + /* Initialize per-thread library info */ + if (H5_UNLIKELY(H5TS__tinfo_init() < 0)) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__win32_process_enter() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_win32_thread_enter + * + * Purpose: Per-thread setup on Windows when using Win32 threads. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +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. + */ + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* H5TS_win32_thread_enter() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_win32_thread_exit + * + * Purpose: Per-thread cleanup on Windows when using Win32 threads. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS_win32_thread_exit(void) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Windows uses a different thread local storage mechanism which does + * not support auto-freeing like pthreads' keys. + * + * WARNING: Do NOT use C standard library functions here. + * CRT functions are not allowed in DllMain, which is where this code + * is used. + */ + + /* Clean up per-thread thread local storage */ + if (H5TS_thrd_info_key_g != TLS_OUT_OF_INDEXES) { + LPVOID lpvData = H5TS__get_thread_local_value(H5TS_thrd_info_key_g); + if (lpvData) + H5TS__tinfo_destroy(lpvData); + } + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* H5TS_win32_thread_exit() */ + +#endif /* H5_HAVE_WIN_THREADS */ + +#endif /* H5_HAVE_THREADSAFE */ + + diff --git a/src/H5Tnative.c b/src/H5Tnative.c index 0e7d395bbc4..48f13debe5b 100644 --- a/src/H5Tnative.c +++ b/src/H5Tnative.c @@ -715,10 +715,12 @@ H5T__get_native_float(size_t size, H5T_direction_t direction, size_t *struct_ali match = H5T_NATIVE_FLOAT_MATCH_DOUBLE; native_size = sizeof(double); } +#if H5_SIZEOF_LONG_DOUBLE != H5_SIZEOF_DOUBLE else if (size <= sizeof(long double)) { match = H5T_NATIVE_FLOAT_MATCH_LDOUBLE; native_size = sizeof(long double); } +#endif else { /* If not match, return the biggest datatype */ match = H5T_NATIVE_FLOAT_MATCH_LDOUBLE; native_size = sizeof(long double); diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index 0d7cd1b96bf..3ec70ab04b6 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -221,7 +221,7 @@ H5VLinitialize(hid_t connector_id, hid_t vipl_id) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("e", "ii", connector_id, vipl_id); /* Check args */ @@ -233,7 +233,7 @@ H5VLinitialize(hid_t connector_id, hid_t vipl_id) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not initialize"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLinitialize() */ /*------------------------------------------------------------------------- @@ -252,7 +252,7 @@ H5VLterminate(hid_t connector_id) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE1("e", "i", connector_id); /* Check args */ @@ -264,7 +264,7 @@ H5VLterminate(hid_t connector_id) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not terminate cleanly"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLterminate() */ /*--------------------------------------------------------------------------- @@ -283,7 +283,7 @@ H5VLget_cap_flags(hid_t connector_id, uint64_t *cap_flags /*out*/) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("e", "i*UL", connector_id, cap_flags); /* Check args */ @@ -295,7 +295,7 @@ H5VLget_cap_flags(hid_t connector_id, uint64_t *cap_flags /*out*/) *cap_flags = cls->cap_flags; done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLget_cap_flags */ /*--------------------------------------------------------------------------- @@ -314,7 +314,7 @@ H5VLget_value(hid_t connector_id, H5VL_class_value_t *value /*out*/) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("e", "i*VC", connector_id, value); /* Check args */ @@ -326,7 +326,7 @@ H5VLget_value(hid_t connector_id, H5VL_class_value_t *value /*out*/) *value = cls->value; done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLget_value */ /*------------------------------------------------------------------------- @@ -433,7 +433,7 @@ H5VLcopy_connector_info(hid_t connector_id, void **dst_vol_info, void *src_vol_i H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "i**x*x", connector_id, dst_vol_info, src_vol_info); /* Check args and get class pointer */ @@ -445,7 +445,7 @@ H5VLcopy_connector_info(hid_t connector_id, void **dst_vol_info, void *src_vol_i HGOTO_ERROR(H5E_VOL, H5E_CANTCOPY, FAIL, "unable to copy VOL connector info object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLcopy_connector_info() */ /*------------------------------------------------------------------------- @@ -595,7 +595,7 @@ H5VLfree_connector_info(hid_t connector_id, void *info) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("e", "i*x", connector_id, info); /* Free the VOL connector info object */ @@ -603,7 +603,7 @@ H5VLfree_connector_info(hid_t connector_id, void *info) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL connector info object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLfree_connector_info() */ /*--------------------------------------------------------------------------- @@ -621,7 +621,7 @@ H5VLconnector_info_to_str(const void *info, hid_t connector_id, char **str) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*xi**s", info, connector_id, str); /* Only serialize info object, if it's non-NULL */ @@ -644,7 +644,7 @@ H5VLconnector_info_to_str(const void *info, hid_t connector_id, char **str) *str = NULL; done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLconnector_info_to_str() */ /*--------------------------------------------------------------------------- @@ -662,7 +662,7 @@ H5VLconnector_str_to_info(const char *str, hid_t connector_id, void **info /*out { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*si**x", str, connector_id, info); /* Call internal routine */ @@ -670,7 +670,7 @@ H5VLconnector_str_to_info(const char *str, hid_t connector_id, void **info /*out HGOTO_ERROR(H5E_VOL, H5E_CANTDECODE, FAIL, "can't deserialize connector info"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLconnector_str_to_info() */ /*--------------------------------------------------------------------------- @@ -689,7 +689,7 @@ H5VLget_object(void *obj, hid_t connector_id) H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("*x", "*xi", obj, connector_id); /* Check args */ @@ -705,7 +705,7 @@ H5VLget_object(void *obj, hid_t connector_id) ret_value = obj; done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLget_object */ /*------------------------------------------------------------------------- @@ -762,7 +762,7 @@ H5VLget_wrap_ctx(void *obj, hid_t connector_id, void **wrap_ctx /*out*/) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*xi**x", obj, connector_id, wrap_ctx); /* Check args and get class pointer */ @@ -774,7 +774,7 @@ H5VLget_wrap_ctx(void *obj, hid_t connector_id, void **wrap_ctx /*out*/) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to retrieve VOL connector object wrap context"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLget_wrap_ctx() */ /*------------------------------------------------------------------------- @@ -827,7 +827,7 @@ H5VLwrap_object(void *obj, H5I_type_t obj_type, hid_t connector_id, void *wrap_c H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("*x", "*xIti*x", obj, obj_type, connector_id, wrap_ctx); /* Check args and get class pointer */ @@ -841,7 +841,7 @@ H5VLwrap_object(void *obj, H5I_type_t obj_type, hid_t connector_id, void *wrap_c HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "unable to wrap object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLwrap_object */ /*------------------------------------------------------------------------- @@ -894,7 +894,7 @@ H5VLunwrap_object(void *obj, hid_t connector_id) H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("*x", "*xi", obj, connector_id); /* Check args and get class pointer */ @@ -908,7 +908,7 @@ H5VLunwrap_object(void *obj, hid_t connector_id) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "unable to unwrap object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLunwrap_object */ /*------------------------------------------------------------------------- @@ -958,7 +958,7 @@ H5VLfree_wrap_ctx(void *wrap_ctx, hid_t connector_id) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("e", "*xi", wrap_ctx, connector_id); /* Check args and get class pointer */ @@ -970,7 +970,7 @@ H5VLfree_wrap_ctx(void *wrap_ctx, hid_t connector_id) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release VOL connector object wrap context"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* H5VLfree_wrap_ctx() */ /*------------------------------------------------------------------------- @@ -1059,7 +1059,7 @@ H5VLattr_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_ H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE10("*x", "*x*#i*siiiii**x", obj, loc_params, connector_id, name, type_id, space_id, acpl_id, aapl_id, dxpl_id, req); @@ -1075,7 +1075,7 @@ H5VLattr_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_ HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "unable to create attribute"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_create() */ /*------------------------------------------------------------------------- @@ -1162,7 +1162,7 @@ H5VLattr_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_id H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE7("*x", "*x*#i*sii**x", obj, loc_params, connector_id, name, aapl_id, dxpl_id, req); /* Check args and get class pointer */ @@ -1176,7 +1176,7 @@ H5VLattr_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_id HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "unable to open attribute"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_open() */ /*------------------------------------------------------------------------- @@ -1259,7 +1259,7 @@ H5VLattr_read(void *obj, hid_t connector_id, hid_t mem_type_id, void *buf, hid_t H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*xii*xi**x", obj, connector_id, mem_type_id, buf, dxpl_id, req); /* Check args and get class pointer */ @@ -1273,7 +1273,7 @@ H5VLattr_read(void *obj, hid_t connector_id, hid_t mem_type_id, void *buf, hid_t HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "unable to read attribute"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_read() */ /*------------------------------------------------------------------------- @@ -1358,7 +1358,7 @@ H5VLattr_write(void *obj, hid_t connector_id, hid_t mem_type_id, const void *buf H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*xii*xi**x", obj, connector_id, mem_type_id, buf, dxpl_id, req); /* Check args and get class pointer */ @@ -1372,7 +1372,7 @@ H5VLattr_write(void *obj, hid_t connector_id, hid_t mem_type_id, const void *buf HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "unable to write attribute"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_write() */ /*------------------------------------------------------------------------- @@ -1455,7 +1455,7 @@ H5VLattr_get(void *obj, hid_t connector_id, H5VL_attr_get_args_t *args, hid_t dx H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -1471,7 +1471,7 @@ H5VLattr_get(void *obj, hid_t connector_id, H5VL_attr_get_args_t *args, hid_t dx HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to get attribute information"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_get() */ /*------------------------------------------------------------------------- @@ -1560,7 +1560,7 @@ H5VLattr_specific(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -1575,7 +1575,7 @@ H5VLattr_specific(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute attribute 'specific' callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_specific() */ /*------------------------------------------------------------------------- @@ -1661,7 +1661,7 @@ H5VLattr_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hid H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -1676,7 +1676,7 @@ H5VLattr_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hid HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute attribute optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_optional() */ /*------------------------------------------------------------------------- @@ -1795,7 +1795,7 @@ H5VLattr_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out*/) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xii**x", obj, connector_id, dxpl_id, req); /* Check args and get class pointer */ @@ -1809,7 +1809,7 @@ H5VLattr_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out*/) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "unable to close attribute"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLattr_close() */ /*------------------------------------------------------------------------- @@ -1901,7 +1901,7 @@ H5VLdataset_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t connect H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE11("*x", "*x*#i*siiiiii**x", obj, loc_params, connector_id, name, lcpl_id, type_id, space_id, dcpl_id, dapl_id, dxpl_id, req); @@ -1917,7 +1917,7 @@ H5VLdataset_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t connect HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "unable to create dataset"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_create() */ /*------------------------------------------------------------------------- @@ -2004,7 +2004,7 @@ H5VLdataset_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE7("*x", "*x*#i*sii**x", obj, loc_params, connector_id, name, dapl_id, dxpl_id, req); /* Check args and get class pointer */ @@ -2018,7 +2018,7 @@ H5VLdataset_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "unable to open dataset"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_open() */ /*------------------------------------------------------------------------- @@ -2181,7 +2181,7 @@ H5VLdataset_read(size_t count, void *obj[], hid_t connector_id, hid_t mem_type_i size_t i; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE9("e", "z**xi*i*i*ii**x**x", count, obj, connector_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req); @@ -2207,7 +2207,7 @@ H5VLdataset_read(size_t count, void *obj[], hid_t connector_id, hid_t mem_type_i HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to read dataset"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_read() */ /*------------------------------------------------------------------------- @@ -2371,7 +2371,7 @@ H5VLdataset_write(size_t count, void *obj[], hid_t connector_id, hid_t mem_type_ size_t i; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE9("e", "z**xi*i*i*ii**x**x", count, obj, connector_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req); @@ -2397,7 +2397,7 @@ H5VLdataset_write(size_t count, void *obj[], hid_t connector_id, hid_t mem_type_ HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, FAIL, "unable to write dataset"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_write() */ /*------------------------------------------------------------------------- @@ -2482,7 +2482,7 @@ H5VLdataset_get(void *obj, hid_t connector_id, H5VL_dataset_get_args_t *args, hi H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -2496,7 +2496,7 @@ H5VLdataset_get(void *obj, hid_t connector_id, H5VL_dataset_get_args_t *args, hi HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to execute dataset get callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_get() */ /*------------------------------------------------------------------------- @@ -2582,7 +2582,7 @@ H5VLdataset_specific(void *obj, hid_t connector_id, H5VL_dataset_specific_args_t H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -2596,7 +2596,7 @@ H5VLdataset_specific(void *obj, hid_t connector_id, H5VL_dataset_specific_args_t HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute dataset specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_specific() */ /*------------------------------------------------------------------------- @@ -2681,7 +2681,7 @@ H5VLdataset_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -2695,7 +2695,7 @@ H5VLdataset_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute dataset optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_optional() */ /*------------------------------------------------------------------------- @@ -2831,7 +2831,7 @@ H5VLdataset_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xii**x", obj, connector_id, dxpl_id, req); /* Check args and get class pointer */ @@ -2845,7 +2845,7 @@ H5VLdataset_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "unable to close dataset"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdataset_close() */ /*------------------------------------------------------------------------- @@ -2935,7 +2935,7 @@ H5VLdatatype_commit(void *obj, const H5VL_loc_params_t *loc_params, hid_t connec H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE10("*x", "*x*#i*siiiii**x", obj, loc_params, connector_id, name, type_id, lcpl_id, tcpl_id, tapl_id, dxpl_id, req); @@ -2951,7 +2951,7 @@ H5VLdatatype_commit(void *obj, const H5VL_loc_params_t *loc_params, hid_t connec HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "unable to commit datatype"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdatatype_commit() */ /*------------------------------------------------------------------------- @@ -3038,7 +3038,7 @@ H5VLdatatype_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE7("*x", "*x*#i*sii**x", obj, loc_params, connector_id, name, tapl_id, dxpl_id, req); /* Check args and get class pointer */ @@ -3052,7 +3052,7 @@ H5VLdatatype_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "unable to open datatype"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdatatype_open() */ /*------------------------------------------------------------------------- @@ -3137,7 +3137,7 @@ H5VLdatatype_get(void *obj, hid_t connector_id, H5VL_datatype_get_args_t *args, H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -3151,7 +3151,7 @@ H5VLdatatype_get(void *obj, hid_t connector_id, H5VL_datatype_get_args_t *args, HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to execute datatype get callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdatatype_get() */ /*------------------------------------------------------------------------- @@ -3237,7 +3237,7 @@ H5VLdatatype_specific(void *obj, hid_t connector_id, H5VL_datatype_specific_args H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -3251,7 +3251,7 @@ H5VLdatatype_specific(void *obj, hid_t connector_id, H5VL_datatype_specific_args HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute datatype specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdatatype_specific() */ /*------------------------------------------------------------------------- @@ -3380,7 +3380,7 @@ H5VLdatatype_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -3394,7 +3394,7 @@ H5VLdatatype_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute datatype optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdatatype_optional() */ /*------------------------------------------------------------------------- @@ -3524,7 +3524,7 @@ H5VLdatatype_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*ou H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xii**x", obj, connector_id, dxpl_id, req); /* Check args and get class pointer */ @@ -3538,7 +3538,7 @@ H5VLdatatype_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*ou HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "unable to close datatype"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLdatatype_close() */ /*------------------------------------------------------------------------- @@ -3627,7 +3627,7 @@ H5VLfile_create(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("*x", "*sIuiii**x", name, flags, fcpl_id, fapl_id, dxpl_id, req); /* Get the VOL info from the fapl */ @@ -3645,7 +3645,7 @@ H5VLfile_create(const char *name, unsigned flags, hid_t fcpl_id, hid_t fapl_id, HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "unable to create file"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLfile_create() */ /*------------------------------------------------------------------------- @@ -3888,7 +3888,7 @@ H5VLfile_open(const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, vo H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("*x", "*sIuii**x", name, flags, fapl_id, dxpl_id, req); /* Get the VOL info from the fapl */ @@ -3906,7 +3906,7 @@ H5VLfile_open(const char *name, unsigned flags, hid_t fapl_id, hid_t dxpl_id, vo HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "unable to open file"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLfile_open() */ /*------------------------------------------------------------------------- @@ -3989,7 +3989,7 @@ H5VLfile_get(void *obj, hid_t connector_id, H5VL_file_get_args_t *args, hid_t dx H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -4003,7 +4003,7 @@ H5VLfile_get(void *obj, hid_t connector_id, H5VL_file_get_args_t *args, hid_t dx HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to execute file get callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLfile_get() */ /*------------------------------------------------------------------------- @@ -4124,7 +4124,7 @@ H5VLfile_specific(void *obj, hid_t connector_id, H5VL_file_specific_args_t *args H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -4136,7 +4136,7 @@ H5VLfile_specific(void *obj, hid_t connector_id, H5VL_file_specific_args_t *args HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute file specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLfile_specific() */ /*------------------------------------------------------------------------- @@ -4220,7 +4220,7 @@ H5VLfile_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hid H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -4234,7 +4234,7 @@ H5VLfile_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hid HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute file optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLfile_optional() */ /*------------------------------------------------------------------------- @@ -4364,7 +4364,7 @@ H5VLfile_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out*/) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xii**x", obj, connector_id, dxpl_id, req); /* Check args and get class pointer */ @@ -4378,7 +4378,7 @@ H5VLfile_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out*/) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEFILE, FAIL, "unable to close file"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLfile_close() */ /*------------------------------------------------------------------------- @@ -4466,7 +4466,7 @@ H5VLgroup_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE9("*x", "*x*#i*siiii**x", obj, loc_params, connector_id, name, lcpl_id, gcpl_id, gapl_id, dxpl_id, req); @@ -4482,7 +4482,7 @@ H5VLgroup_create(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "unable to create group"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLgroup_create() */ /*------------------------------------------------------------------------- @@ -4569,7 +4569,7 @@ H5VLgroup_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_i H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE7("*x", "*x*#i*sii**x", obj, loc_params, connector_id, name, gapl_id, dxpl_id, req); /* Check args and get class pointer */ @@ -4583,7 +4583,7 @@ H5VLgroup_open(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_i HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, NULL, "unable to open group"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLgroup_open() */ /*------------------------------------------------------------------------- @@ -4666,7 +4666,7 @@ H5VLgroup_get(void *obj, hid_t connector_id, H5VL_group_get_args_t *args, hid_t H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -4680,7 +4680,7 @@ H5VLgroup_get(void *obj, hid_t connector_id, H5VL_group_get_args_t *args, hid_t HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to execute group get callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLgroup_get() */ /*------------------------------------------------------------------------- @@ -4765,7 +4765,7 @@ H5VLgroup_specific(void *obj, hid_t connector_id, H5VL_group_specific_args_t *ar H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -4779,7 +4779,7 @@ H5VLgroup_specific(void *obj, hid_t connector_id, H5VL_group_specific_args_t *ar HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute group specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLgroup_specific() */ /*------------------------------------------------------------------------- @@ -4866,7 +4866,7 @@ H5VLgroup_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hi H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -4881,7 +4881,7 @@ H5VLgroup_optional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hi HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute group optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLgroup_optional() */ /*------------------------------------------------------------------------- @@ -5011,7 +5011,7 @@ H5VLgroup_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out*/ H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xii**x", obj, connector_id, dxpl_id, req); /* Check args and get class pointer */ @@ -5025,7 +5025,7 @@ H5VLgroup_close(void *obj, hid_t connector_id, hid_t dxpl_id, void **req /*out*/ HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "unable to close group"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLgroup_close() */ /*------------------------------------------------------------------------- @@ -5126,7 +5126,7 @@ H5VLlink_create(H5VL_link_create_args_t *args, void *obj, const H5VL_loc_params_ H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE8("e", "*!*x*#iiii**x", args, obj, loc_params, connector_id, lcpl_id, lapl_id, dxpl_id, req); /* Get class pointer */ @@ -5138,7 +5138,7 @@ H5VLlink_create(H5VL_link_create_args_t *args, void *obj, const H5VL_loc_params_ HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, FAIL, "unable to create link"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLlink_create() */ /*------------------------------------------------------------------------- @@ -5232,7 +5232,7 @@ H5VLlink_copy(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE9("e", "*x*#*x*#iiii**x", src_obj, loc_params1, dst_obj, loc_params2, connector_id, lcpl_id, lapl_id, dxpl_id, req); @@ -5245,7 +5245,7 @@ H5VLlink_copy(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj HGOTO_ERROR(H5E_VOL, H5E_CANTCOPY, FAIL, "unable to copy object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLlink_copy() */ /*------------------------------------------------------------------------- @@ -5339,7 +5339,7 @@ H5VLlink_move(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE9("e", "*x*#*x*#iiii**x", src_obj, loc_params1, dst_obj, loc_params2, connector_id, lcpl_id, lapl_id, dxpl_id, req); @@ -5352,7 +5352,7 @@ H5VLlink_move(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_obj HGOTO_ERROR(H5E_VOL, H5E_CANTMOVE, FAIL, "unable to move object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLlink_move() */ /*------------------------------------------------------------------------- @@ -5438,7 +5438,7 @@ H5VLlink_get(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_id, H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -5452,7 +5452,7 @@ H5VLlink_get(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_id, HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to execute link get callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLlink_get() */ /*------------------------------------------------------------------------- @@ -5541,7 +5541,7 @@ H5VLlink_specific(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -5556,7 +5556,7 @@ H5VLlink_specific(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute link specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLlink_specific() */ /*------------------------------------------------------------------------- @@ -5642,7 +5642,7 @@ H5VLlink_optional(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -5656,7 +5656,7 @@ H5VLlink_optional(void *obj, const H5VL_loc_params_t *loc_params, hid_t connecto HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute link optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLlink_optional() */ /*------------------------------------------------------------------------- @@ -5804,7 +5804,7 @@ H5VLobject_open(void *obj, const H5VL_loc_params_t *params, hid_t connector_id, H5VL_class_t *cls; /* VOL connector's class struct */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("*x", "*x*#i*Iti**x", obj, params, connector_id, opened_type, dxpl_id, req); /* Check args and get class pointer */ @@ -5818,7 +5818,7 @@ H5VLobject_open(void *obj, const H5VL_loc_params_t *params, hid_t connector_id, HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "unable to open object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLobject_open() */ /*------------------------------------------------------------------------- @@ -5914,7 +5914,7 @@ H5VLobject_copy(void *src_obj, const H5VL_loc_params_t *src_loc_params, const ch H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE11("e", "*x*#*s*x*#*siiii**x", src_obj, src_loc_params, src_name, dst_obj, dst_loc_params, dst_name, connector_id, ocpypl_id, lcpl_id, dxpl_id, req); @@ -5930,7 +5930,7 @@ H5VLobject_copy(void *src_obj, const H5VL_loc_params_t *src_loc_params, const ch HGOTO_ERROR(H5E_VOL, H5E_CANTCOPY, FAIL, "unable to copy object"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLobject_copy() */ /*------------------------------------------------------------------------- @@ -6016,7 +6016,7 @@ H5VLobject_get(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_i H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -6030,7 +6030,7 @@ H5VLobject_get(void *obj, const H5VL_loc_params_t *loc_params, hid_t connector_i HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "unable to execute object get callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLobject_get() */ /*------------------------------------------------------------------------- @@ -6119,7 +6119,7 @@ H5VLobject_specific(void *obj, const H5VL_loc_params_t *loc_params, hid_t connec H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -6134,7 +6134,7 @@ H5VLobject_specific(void *obj, const H5VL_loc_params_t *loc_params, hid_t connec HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute object specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLobject_specific() */ /*------------------------------------------------------------------------- @@ -6220,7 +6220,7 @@ H5VLobject_optional(void *obj, const H5VL_loc_params_t *loc_params, hid_t connec H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*x*#i*!i**x", obj, loc_params, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -6234,7 +6234,7 @@ H5VLobject_optional(void *obj, const H5VL_loc_params_t *loc_params, hid_t connec HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute object optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLobject_optional() */ /*------------------------------------------------------------------------- @@ -6391,7 +6391,7 @@ H5VLintrospect_get_conn_cls(void *obj, hid_t connector_id, H5VL_get_conn_lvl_t l H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xiVL**#", obj, connector_id, lvl, conn_cls); /* Check args */ @@ -6409,7 +6409,7 @@ H5VLintrospect_get_conn_cls(void *obj, hid_t connector_id, H5VL_get_conn_lvl_t l HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't query connector class"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLintrospect_get_conn_cls() */ /*------------------------------------------------------------------------- @@ -6463,7 +6463,7 @@ H5VLintrospect_get_cap_flags(const void *info, hid_t connector_id, uint64_t *cap H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*xi*UL", info, connector_id, cap_flags); /* Check args */ @@ -6479,7 +6479,7 @@ H5VLintrospect_get_cap_flags(const void *info, hid_t connector_id, uint64_t *cap HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't query connector's capability flags"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLintrospect_get_cap_flags() */ /*------------------------------------------------------------------------- @@ -6567,7 +6567,7 @@ H5VLintrospect_opt_query(void *obj, hid_t connector_id, H5VL_subclass_t subcls, H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xiVSIs*UL", obj, connector_id, subcls, opt_type, flags); /* Get class pointer */ @@ -6579,7 +6579,7 @@ H5VLintrospect_opt_query(void *obj, hid_t connector_id, H5VL_subclass_t subcls, HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't query optional operation support"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLintrospect_opt_query() */ /*------------------------------------------------------------------------- @@ -6670,7 +6670,7 @@ H5VLrequest_wait(void *req, hid_t connector_id, uint64_t timeout, H5VL_request_s H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xiUL*#", req, connector_id, timeout, status); /* Get class pointer */ @@ -6682,7 +6682,7 @@ H5VLrequest_wait(void *req, hid_t connector_id, uint64_t timeout, H5VL_request_s HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to wait on request"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLrequest_wait() */ /*------------------------------------------------------------------------- @@ -6775,7 +6775,7 @@ H5VLrequest_notify(void *req, hid_t connector_id, H5VL_request_notify_t cb, void H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xiVN*x", req, connector_id, cb, ctx); /* Get class pointer */ @@ -6787,7 +6787,7 @@ H5VLrequest_notify(void *req, hid_t connector_id, H5VL_request_notify_t cb, void HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "unable to register notify callback for request"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLrequest_notify() */ /*------------------------------------------------------------------------- @@ -6877,7 +6877,7 @@ H5VLrequest_cancel(void *req, hid_t connector_id, H5VL_request_status_t *status H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*xi*#", req, connector_id, status); /* Get class pointer */ @@ -6889,7 +6889,7 @@ H5VLrequest_cancel(void *req, hid_t connector_id, H5VL_request_status_t *status HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to cancel request"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLrequest_cancel() */ /*------------------------------------------------------------------------- @@ -6981,7 +6981,7 @@ H5VLrequest_specific(void *req, hid_t connector_id, H5VL_request_specific_args_t H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*xi*!", req, connector_id, args); /* Get class pointer */ @@ -6994,7 +6994,7 @@ H5VLrequest_specific(void *req, hid_t connector_id, H5VL_request_specific_args_t "unable to execute asynchronous request specific callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLrequest_specific() */ /*------------------------------------------------------------------------- @@ -7086,7 +7086,7 @@ H5VLrequest_optional(void *req, hid_t connector_id, H5VL_optional_args_t *args) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE3("e", "*xi*!", req, connector_id, args); /* Get class pointer */ @@ -7099,7 +7099,7 @@ H5VLrequest_optional(void *req, hid_t connector_id, H5VL_optional_args_t *args) "unable to execute asynchronous request optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLrequest_optional() */ /*------------------------------------------------------------------------- @@ -7226,7 +7226,7 @@ H5VLrequest_free(void *req, hid_t connector_id) H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE2("e", "*xi", req, connector_id); /* Get class pointer */ @@ -7238,7 +7238,7 @@ H5VLrequest_free(void *req, hid_t connector_id) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to free request"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLrequest_free() */ /*------------------------------------------------------------------------- @@ -7319,7 +7319,7 @@ H5VLblob_put(void *obj, hid_t connector_id, const void *buf, size_t size, void * H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*xi*xz*x*x", obj, connector_id, buf, size, blob_id, ctx); /* Get class pointer */ @@ -7333,7 +7333,7 @@ H5VLblob_put(void *obj, hid_t connector_id, const void *buf, size_t size, void * HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "blob put failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLblob_put() */ /*------------------------------------------------------------------------- @@ -7414,7 +7414,7 @@ H5VLblob_get(void *obj, hid_t connector_id, const void *blob_id, void *buf /*out H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE6("e", "*xi*x*xz*x", obj, connector_id, blob_id, buf, size, ctx); /* Get class pointer */ @@ -7428,7 +7428,7 @@ H5VLblob_get(void *obj, hid_t connector_id, const void *blob_id, void *buf /*out HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "blob get failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLblob_get() */ /*------------------------------------------------------------------------- @@ -7508,7 +7508,7 @@ H5VLblob_specific(void *obj, hid_t connector_id, void *blob_id, H5VL_blob_specif H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xi*x*!", obj, connector_id, blob_id, args); /* Get class pointer */ @@ -7522,7 +7522,7 @@ H5VLblob_specific(void *obj, hid_t connector_id, void *blob_id, H5VL_blob_specif HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "blob specific operation failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLblob_specific() */ /*------------------------------------------------------------------------- @@ -7602,7 +7602,7 @@ H5VLblob_optional(void *obj, hid_t connector_id, void *blob_id, H5VL_optional_ar H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE4("e", "*xi*x*!", obj, connector_id, blob_id, args); /* Get class pointer */ @@ -7616,7 +7616,7 @@ H5VLblob_optional(void *obj, hid_t connector_id, void *blob_id, H5VL_optional_ar HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "blob optional operation failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLblob_optional() */ /*------------------------------------------------------------------------- @@ -7724,7 +7724,7 @@ H5VLtoken_cmp(void *obj, hid_t connector_id, const H5O_token_t *token1, const H5 H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*k*k*Is", obj, connector_id, token1, token2, cmp_value); /* Check args and get class pointer */ @@ -7740,7 +7740,7 @@ H5VLtoken_cmp(void *obj, hid_t connector_id, const H5O_token_t *token1, const H5 HGOTO_ERROR(H5E_VOL, H5E_CANTCOMPARE, FAIL, "object token comparison failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLtoken_cmp() */ /*------------------------------------------------------------------------- @@ -7829,7 +7829,7 @@ H5VLtoken_to_str(void *obj, H5I_type_t obj_type, hid_t connector_id, const H5O_t H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xIti*k**s", obj, obj_type, connector_id, token, token_str); /* Check args and get class pointer */ @@ -7847,7 +7847,7 @@ H5VLtoken_to_str(void *obj, H5I_type_t obj_type, hid_t connector_id, const H5O_t HGOTO_ERROR(H5E_VOL, H5E_CANTSERIALIZE, FAIL, "object token to string failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLtoken_to_str() */ /*------------------------------------------------------------------------- @@ -7936,7 +7936,7 @@ H5VLtoken_from_str(void *obj, H5I_type_t obj_type, hid_t connector_id, const cha H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xIti*s*k", obj, obj_type, connector_id, token_str, token); /* Check args and get class pointer */ @@ -7954,7 +7954,7 @@ H5VLtoken_from_str(void *obj, H5I_type_t obj_type, hid_t connector_id, const cha HGOTO_ERROR(H5E_VOL, H5E_CANTUNSERIALIZE, FAIL, "object token from string failed"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLtoken_from_str() */ /*------------------------------------------------------------------------- @@ -8037,7 +8037,7 @@ H5VLoptional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hid_t dx H5VL_class_t *cls; /* VOL connector's class struct */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API_NOINIT + FUNC_ENTER_API_REENTER H5TRACE5("e", "*xi*!i**x", obj, connector_id, args, dxpl_id, req); /* Check args and get class pointer */ @@ -8051,5 +8051,5 @@ H5VLoptional(void *obj, hid_t connector_id, H5VL_optional_args_t *args, hid_t dx HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute optional callback"); done: - FUNC_LEAVE_API_NOINIT(ret_value) + FUNC_LEAVE_API_REENTER(ret_value) } /* end H5VLoptional() */ diff --git a/src/H5err.txt b/src/H5err.txt index fceb72618c1..23cab2c0e56 100644 --- a/src/H5err.txt +++ b/src/H5err.txt @@ -78,6 +78,7 @@ MAJOR, H5E_PAGEBUF, Page Buffering MAJOR, H5E_CONTEXT, API Context MAJOR, H5E_MAP, Map MAJOR, H5E_EVENTSET, Event Set +MAJOR, H5E_THREADSAFE, Threadsafety MAJOR, H5E_NONE_MAJOR, No error # Sections (for grouping minor errors) diff --git a/src/H5private.h b/src/H5private.h index 8cc52180679..b33056805e9 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -148,13 +148,15 @@ #include "uthash.h" /* - * NT doesn't define SIGBUS, but since NT only runs on processors - * that do not have alignment constraints a SIGBUS would never be - * raised, so we just replace it with SIGILL (which also should - * never be raised by the hdf5 library). + * Does the compiler support the __builtin_expect() syntax? + * It's not a problem if not. */ -#ifndef SIGBUS -#define SIGBUS SIGILL +#if H5_HAVE_BUILTIN_EXPECT +#define H5_LIKELY(expression) __builtin_expect(!!(expression), 1) +#define H5_UNLIKELY(expression) __builtin_expect(!!(expression), 0) +#else +#define H5_LIKELY(expression) (expression) +#define H5_UNLIKELY(expression) (expression) #endif /* @@ -231,6 +233,13 @@ # define H5_ATTR_NO_OPTIMIZE /*void*/ # endif +/* Enable thread-safety annotations when built with clang */ +# if defined(__clang__) +# define H5_ATTR_THREAD_ANNOT(X) __attribute__((X)) +# else +# define H5_ATTR_THREAD_ANNOT(X) /*void*/ +# endif + #else # define H5_ATTR_FORMAT(X, Y, Z) /*void*/ # define H5_ATTR_UNUSED /*void*/ @@ -245,6 +254,7 @@ # define H5_ATTR_FALLTHROUGH /*void*/ # define H5_ATTR_MALLOC /*void*/ # define H5_ATTR_NO_OPTIMIZE /*void*/ +# define H5_ATTR_THREAD_ANNOT(X) /*void*/ #endif /* clang-format on */ @@ -1250,54 +1260,24 @@ H5_DLL herr_t H5_trace_args(struct H5RS_str_t *rs, const char *type, va_list ap) /* global library version information string */ extern char H5_lib_vers_info_g[]; +/* Lock headers */ #include "H5TSprivate.h" -/* Lock headers */ #ifdef H5_HAVE_THREADSAFE -/* replacement structure for original global variable */ -typedef struct H5_api_struct { - H5TS_mutex_t init_lock; /* API entrance mutex */ - bool H5_libinit_g; /* Has the library been initialized? */ - bool H5_libterm_g; /* Is the library being shutdown? */ -} H5_api_t; - -/* Macros for accessing the global variables */ -#define H5_INIT_GLOBAL (H5_g.H5_libinit_g) -#define H5_TERM_GLOBAL (H5_g.H5_libterm_g) - -/* Macro for first thread initialization */ -#ifdef H5_HAVE_WIN_THREADS -#define H5_FIRST_THREAD_INIT InitOnceExecuteOnce(&H5TS_first_init_g, H5TS_win32_process_enter, NULL, NULL); -#else -#define H5_FIRST_THREAD_INIT pthread_once(&H5TS_first_init_g, H5TS_pthread_first_thread_init); -#endif - -/* Macros for threadsafe HDF5 Phase I locks */ -#define H5_API_LOCK H5TS_mutex_lock(&H5_g.init_lock); -#define H5_API_UNLOCK H5TS_mutex_unlock(&H5_g.init_lock); - -/* Macros for thread cancellation-safe mechanism */ -#define H5_API_UNSET_CANCEL H5TS_cancel_count_inc(); - -#define H5_API_SET_CANCEL H5TS_cancel_count_dec(); - -extern H5_api_t H5_g; +/* Macros for acquiring & releasing threadsafe API lock */ +#define H5_API_LOCK H5TS_api_lock(); +#define H5_API_UNLOCK H5TS_api_unlock(); #else /* H5_HAVE_THREADSAFE */ -/* disable any first thread init mechanism */ -#define H5_FIRST_THREAD_INIT - -/* disable locks (sequential version) */ +/* No locks (non-threadsafe builds) */ #define H5_API_LOCK #define H5_API_UNLOCK -/* disable cancellability (sequential version) */ -#define H5_API_UNSET_CANCEL -#define H5_API_SET_CANCEL +#endif /* H5_HAVE_THREADSAFE */ -/* extern global variables */ +/* Library init / term status (global) */ extern bool H5_libinit_g; /* Has the library been initialized? */ extern bool H5_libterm_g; /* Is the library being shutdown? */ @@ -1305,8 +1285,6 @@ extern bool H5_libterm_g; /* Is the library being shutdown? */ #define H5_INIT_GLOBAL (H5_libinit_g) #define H5_TERM_GLOBAL (H5_libterm_g) -#endif /* H5_HAVE_THREADSAFE */ - #ifdef H5_HAVE_CODESTACK /* Include required function stack header */ @@ -1329,7 +1307,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); { \ static bool func_check = false; \ \ - if (!func_check) { \ + if (H5_UNLIKELY(!func_check)) { \ /* Check function naming status */ \ assert(asrt && \ "Function naming conventions are incorrect - check H5_IS_API|PUB|PRIV|PKG macros in " \ @@ -1350,39 +1328,30 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); #define FUNC_ENTER_COMMON_NOERR(asrt) FUNC_ENTER_CHECK_NAME(asrt); -/* Threadsafety initialization code for API routines */ -#define FUNC_ENTER_API_THREADSAFE \ - /* Initialize the thread-safe code */ \ - H5_FIRST_THREAD_INIT \ - \ - /* Grab the mutex for the library */ \ - H5_API_UNSET_CANCEL \ - H5_API_LOCK - /* Local variables for API routines */ #define FUNC_ENTER_API_VARS H5TRACE_DECL #define FUNC_ENTER_API_COMMON \ FUNC_ENTER_API_VARS \ FUNC_ENTER_COMMON(H5_IS_API(__func__)); \ - FUNC_ENTER_API_THREADSAFE; + H5_API_LOCK #define FUNC_ENTER_API_INIT(err) \ /* Initialize the library */ \ - if (!H5_INIT_GLOBAL && !H5_TERM_GLOBAL) { \ - if (H5_init_library() < 0) \ + if (H5_UNLIKELY(!H5_INIT_GLOBAL && !H5_TERM_GLOBAL)) { \ + if (H5_UNLIKELY(H5_init_library() < 0)) \ HGOTO_ERROR(H5E_FUNC, H5E_CANTINIT, err, "library initialization failed"); \ } #define FUNC_ENTER_API_PUSH(err) \ - /* Push the name of this function on the function stack */ \ - H5_PUSH_FUNC \ - \ /* Push the API context */ \ - if (H5CX_push() < 0) \ + if (H5_UNLIKELY(H5CX_push() < 0)) \ HGOTO_ERROR(H5E_FUNC, H5E_CANTSET, err, "can't set API context"); \ else \ api_ctx_pushed = true; + \ + /* Push the name of this function on the function stack */ \ + H5_PUSH_FUNC /* Use this macro for all "normal" API functions */ #define FUNC_ENTER_API(err) \ @@ -1411,11 +1380,27 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); FUNC_ENTER_API_PUSH(err); \ { +/* + * Use this macro for "developer" API functions that re-enter the library from + * a plugin / connector / filter / etc, and shouldn't (need to) perform + * initialization of the library or an interface, just perform tracing, etc. + * Examples are: H5allocate_memory, public VOL callback + * wrappers (e.g. H5VLfile_create, H5VLdataset_read, etc.), public VFL + * callback wrappers (e.g. H5FDopen, H5FDwrite, etc.), etc. + * + */ +#define FUNC_ENTER_API_REENTER \ + { \ + { \ + { \ + FUNC_ENTER_API_COMMON \ + H5_PUSH_FUNC \ + { + /* * Use this macro for API functions that shouldn't perform _any_ initialization * of the library or an interface, just perform tracing, etc. Examples - * are: H5allocate_memory, H5is_library_threadsafe, public VOL callback - * wrappers (e.g. H5VLfile_create, H5VLdataset_read, etc.), etc. + * are: H5is_library_threadsafe, H5VLretrieve_lib_state, etc. * */ #define FUNC_ENTER_API_NOINIT \ @@ -1423,7 +1408,6 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); { \ { \ FUNC_ENTER_API_COMMON \ - H5_PUSH_FUNC \ { /* @@ -1440,7 +1424,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); { \ FUNC_ENTER_API_VARS \ FUNC_ENTER_COMMON_NOERR(H5_IS_API(__func__)); \ - FUNC_ENTER_API_THREADSAFE; \ + H5_API_LOCK \ { /* @@ -1456,7 +1440,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); { \ { \ FUNC_ENTER_COMMON(H5_IS_API(__func__)); \ - FUNC_ENTER_API_THREADSAFE; \ + H5_API_LOCK \ FUNC_ENTER_API_INIT(err); \ { @@ -1529,13 +1513,12 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); #define FUNC_ENTER_NOAPI_NOFS \ { \ FUNC_ENTER_COMMON(!H5_IS_API(__func__)); \ - \ { /* * Use this macro for non-API functions which fall into these categories: * - functions which shouldn't push their name on the function stack - * (so far, just the H5CS routines themselves) + * (so far, just the H5CS routines themselves and H5CX_get_fstack) * * This macro is used for functions which fit the above categories _and_ * also don't use the 'FUNC' variable (i.e. don't push errors on the error stack) @@ -1626,10 +1609,6 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); * the last statement executed by a function. *------------------------------------------------------------------------- */ -/* Threadsafety termination code for API routines */ -#define FUNC_LEAVE_API_THREADSAFE \ - H5_API_UNLOCK \ - H5_API_SET_CANCEL #define FUNC_LEAVE_API_COMMON(ret_value) H5TRACE_RETURN(ret_value); @@ -1637,27 +1616,40 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); ; \ } /*end scope from end of FUNC_ENTER*/ \ FUNC_LEAVE_API_COMMON(ret_value); \ - if (api_ctx_pushed) { \ + H5_POP_FUNC \ + if (H5_LIKELY(api_ctx_pushed)) { \ (void)H5CX_pop(true); \ api_ctx_pushed = false; \ } \ - H5_POP_FUNC \ - if (err_occurred) \ + if (H5_UNLIKELY(err_occurred)) \ (void)H5E_dump_api_stack(true); \ - FUNC_LEAVE_API_THREADSAFE \ + H5_API_UNLOCK \ return (ret_value); \ } \ } /*end scope from beginning of FUNC_ENTER*/ +/* Use this macro to match the FUNC_ENTER_API_REENTER macro */ +#define FUNC_LEAVE_API_REENTER(ret_value) \ + ; \ + } /*end scope from end of FUNC_ENTER*/ \ + FUNC_LEAVE_API_COMMON(ret_value); \ + H5_POP_FUNC \ + if (H5_UNLIKELY(err_occurred)) \ + (void)H5E_dump_api_stack(TRUE); \ + H5_API_UNLOCK \ + return (ret_value); \ + } \ + } \ + } /*end scope from beginning of FUNC_ENTER*/ + /* Use this macro to match the FUNC_ENTER_API_NOINIT macro */ #define FUNC_LEAVE_API_NOINIT(ret_value) \ ; \ } /*end scope from end of FUNC_ENTER*/ \ FUNC_LEAVE_API_COMMON(ret_value); \ - H5_POP_FUNC \ - if (err_occurred) \ + if (H5_UNLIKELY(err_occurred)) \ (void)H5E_dump_api_stack(true); \ - FUNC_LEAVE_API_THREADSAFE \ + H5_API_UNLOCK \ return (ret_value); \ } \ } \ @@ -1668,7 +1660,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); ; \ } /*end scope from end of FUNC_ENTER*/ \ FUNC_LEAVE_API_COMMON(ret_value); \ - FUNC_LEAVE_API_THREADSAFE \ + H5_API_UNLOCK \ return (ret_value); \ } \ } \ @@ -1679,9 +1671,9 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); #define FUNC_LEAVE_API_NOPUSH(ret_value) \ ; \ } /*end scope from end of FUNC_ENTER*/ \ - if (err_occurred) \ + if (H5_UNLIKELY(err_occurred)) \ (void)H5E_dump_api_stack(true); \ - FUNC_LEAVE_API_THREADSAFE \ + H5_API_UNLOCK \ return (ret_value); \ } \ } \ @@ -1718,7 +1710,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); /* * Use this macro for non-API functions which fall into these categories: * - functions which didn't push their name on the function stack - * (so far, just the H5CS routines themselves) + * (so far, just the H5CS routines themselves and H5CX_get_fstack) */ #define FUNC_LEAVE_NOAPI_NOFS(ret_value) \ ; \ diff --git a/src/Makefile.am b/src/Makefile.am index e6625777712..70bef1fb7c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -96,7 +96,9 @@ libhdf5_la_SOURCES= H5.c H5build_settings.c H5checksum.c H5dbg.c H5system.c \ H5Tfloat.c H5Tinit_float.c H5Tnative.c H5Toffset.c H5Toh.c H5Topaque.c \ H5Torder.c H5Tref.c H5Tpad.c H5Tprecis.c H5Tstrpad.c H5Tvisit.c \ H5Tvlen.c \ - H5TS.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 \ 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 \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 34e6f29e4d5..a9b2bc614c9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -343,11 +343,14 @@ set(mirror_vfd_SOURCES set (ttsafe_SOURCES ${HDF5_TEST_SOURCE_DIR}/ttsafe.h ${HDF5_TEST_SOURCE_DIR}/ttsafe.c - ${HDF5_TEST_SOURCE_DIR}/ttsafe_dcreate.c - ${HDF5_TEST_SOURCE_DIR}/ttsafe_error.c - ${HDF5_TEST_SOURCE_DIR}/ttsafe_cancel.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_acreate.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_attr_vlen.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_cancel.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_dcreate.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_develop.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_error.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_rec_rw_lock.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_thread_id.c ) set (H5_TESTS @@ -582,24 +585,6 @@ if (HDF5_ENABLE_FORMATTERS) clang_format (HDF5_TEST_ttsafe_FORMAT ttsafe) endif () -######### Special handling for extra link lib of threads ############# -#-- Adding test for thread_id -add_executable (thread_id ${HDF5_TEST_SOURCE_DIR}/thread_id.c) -target_compile_options(thread_id PRIVATE "${HDF5_CMAKE_C_FLAGS}") -target_compile_definitions(thread_id PRIVATE "${HDF5_TEST_COMPILE_DEFS_PRIVATE}") -target_include_directories (thread_id PRIVATE "${HDF5_SRC_INCLUDE_DIRS};${HDF5_SRC_BINARY_DIR};$<$:${MPI_C_INCLUDE_DIRS}>") -if (NOT BUILD_SHARED_LIBS) - TARGET_C_PROPERTIES (thread_id STATIC) - target_link_libraries (thread_id PRIVATE ${HDF5_TEST_LIB_TARGET}) - if (NOT WIN32) - target_link_libraries (thread_id PRIVATE "$<$:Threads::Threads>") - endif () -else () - TARGET_C_PROPERTIES (thread_id SHARED) - target_link_libraries (thread_id PRIVATE ${HDF5_TEST_LIBSH_TARGET} "$<$:Threads::Threads>") -endif () -set_target_properties (thread_id PROPERTIES FOLDER test) - #----------------------------------------------------------------------------- # Add Target to clang-format #----------------------------------------------------------------------------- diff --git a/test/Makefile.am b/test/Makefile.am index fdd83e5bdeb..eb5bdd0f88a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -69,8 +69,7 @@ TEST_PROG= testhdf5 \ flush1 flush2 app_ref enum set_extent ttsafe enc_dec_plist \ enc_dec_plist_cross_platform getname vfd ros3 s3comms hdfs ntypes \ dangle dtransform reserved cross_read freespace mf vds file_image \ - unregister cache_logging cork swmr thread_id vol timer event_set \ - onion + unregister cache_logging cork swmr vol timer event_set onion # List programs to be built when testing here # @@ -161,8 +160,9 @@ libh5test_la_SOURCES=h5test.c testframe.c cache_common.c swmr_common.c external_ LDADD=libh5test.la $(LIBHDF5) # List the source files for tests that have more than one -ttsafe_SOURCES=ttsafe.c ttsafe_dcreate.c ttsafe_error.c ttsafe_cancel.c \ - ttsafe_acreate.c ttsafe_attr_vlen.c +ttsafe_SOURCES=ttsafe.c ttsafe_acreate.c ttsafe_attr_vlen.c ttsafe_cancel.c \ + ttsafe_dcreate.c ttsafe_develop.c ttsafe_error.c ttsafe_rec_rw_lock.c \ + ttsafe_thread_id.c cache_image_SOURCES=cache_image.c genall5.c mirror_vfd_SOURCES=mirror_vfd.c genall5.c diff --git a/test/onion.c b/test/onion.c index 5b9bb929dc6..eba52668753 100644 --- a/test/onion.c +++ b/test/onion.c @@ -1537,6 +1537,12 @@ compare_file_bytes_exactly(const char *filepath, hid_t fapl_id, size_t nbytes, c H5FD_t *raw_vfile = NULL; /* virtual file to look at raw file contents */ unsigned char *act_buf = NULL; /* allocated area for actual file bytes */ uint64_t filesize = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ + + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; if (NULL == (raw_vfile = H5FDopen(filepath, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF))) TEST_ERROR; @@ -1570,9 +1576,17 @@ compare_file_bytes_exactly(const char *filepath, hid_t fapl_id, size_t nbytes, c TEST_ERROR; free(act_buf); + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + if (raw_vfile != NULL) H5FDclose(raw_vfile); free(act_buf); @@ -1599,6 +1613,7 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt uint64_t readsize = 0; uint8_t *ui8p = NULL; uint32_t buf_checksum = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* memset to avoid bad frees on errors */ memset(&rev_out, 0, sizeof(H5FD_onion_revision_record_t)); @@ -1613,6 +1628,11 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt rev_out.version = H5FD_ONION_REVISION_RECORD_VERSION_CURR; rev_out.archival_index.version = H5FD_ONION_ARCHIVAL_INDEX_VERSION_CURR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + filesize = (uint64_t)H5FDget_eof(raw_file, H5FD_MEM_DRAW); if (H5FDset_eoa(raw_file, H5FD_MEM_DRAW, filesize) < 0) TEST_ERROR; @@ -1780,12 +1800,20 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt free(rev_out.archival_index.list); } + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + free(history_out.record_locs); history_out.record_locs = NULL; return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + free(buf); free(rev_out.comment); free(rev_out.archival_index.list); @@ -1828,6 +1856,7 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl }; unsigned char *ptr = NULL; uint32_t checksum = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Finish populating expected header bytes */ ptr = hdr_exp_bytes + 8; /* WARNING: must match format */ @@ -1843,6 +1872,11 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl UINT32ENCODE(ptr, checksum); ptr = NULL; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Look at h5 file: should have zero bytes */ file = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF); @@ -1869,6 +1903,11 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl TEST_ERROR; file = NULL; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* Look at onion file: should have header */ if (compare_file_bytes_exactly(paths->onion, fapl_id, H5FD_ONION_ENCODED_SIZE_HEADER, hdr_exp_bytes) < 0) TEST_ERROR; @@ -1884,6 +1923,9 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + if (file != NULL) (void)H5FDclose(file); free(act_buf); @@ -1928,6 +1970,7 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) H5FD_t *vfile_ro = NULL; /* Onion virtual file for read-only */ struct expected_history filter; char *buf = NULL; + bool api_ctx_pushed = false; /* Whether API context pushed */ if (true == truncate_canonical && true == with_initial_data) TESTING("onion creation; truncate extant canonical; w/ initial data"); @@ -1954,6 +1997,11 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) HDremove(paths->onion); HDremove(paths->recovery); + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Create canonical file to be truncated */ if (true == truncate_canonical) { /* Create canonical file. */ @@ -2001,9 +2049,19 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) if (NULL == vfile_rw) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + if (verify_stored_onion_create_0_open(paths, &onion_info) < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + H5E_BEGIN_TRY { vfile_ro = H5FDopen(paths->canon, H5F_ACC_RDONLY, fapl_id, HADDR_UNDEF); @@ -2085,11 +2143,21 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) TEST_ERROR; vfile_rw = NULL; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* Look at h5 file: should be known-empty */ if (compare_file_bytes_exactly(paths->canon, onion_info.backing_fapl_id, 8, (const unsigned char *)"ONIONEOF") < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Look at recovery file: should be gone */ H5E_BEGIN_TRY { @@ -2104,6 +2172,11 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) if (NULL == vfile_raw) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + filter.page_size = onion_info.page_size; filter.n_revisions = 1; filter.origin_eof = 0; @@ -2116,6 +2189,11 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) if (verify_history_as_expected_onion(vfile_raw, &filter) < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + if (H5FDclose(vfile_raw) < 0) TEST_ERROR; vfile_raw = NULL; @@ -2155,6 +2233,11 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) TEST_ERROR; vfile_ro = NULL; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* * CLEANUP */ @@ -2171,6 +2254,9 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + if (paths != NULL) { HDremove(paths->canon); @@ -2241,6 +2327,7 @@ test_several_revisions_with_logical_gaps(void) uint64_t a_off = ONION_TEST_PAGE_SIZE_5 + 7; /* 39 */ uint64_t b_off = (((a_off + a_list_size_s + ONION_TEST_PAGE_SIZE_5 - 1) >> 5) << 5) + ONION_TEST_PAGE_SIZE_5 + 7; /* full page between */ + bool api_ctx_pushed = false; /* Whether API context pushed */ TESTING("multiple revisions with gaps and overlap"); @@ -2295,6 +2382,11 @@ test_several_revisions_with_logical_gaps(void) if (do_onion_open_and_writes(paths->canon, &onion_info, 4, about) < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Inspect logical file */ /* THIS IS THE INITIAL FILE, SHOULD ONLY HAVE 8 BYTES */ @@ -2477,6 +2569,11 @@ test_several_revisions_with_logical_gaps(void) if (NULL == file) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + filter.page_size = onion_info.page_size; filter.n_revisions = 4; filter.origin_eof = 0; @@ -2509,10 +2606,20 @@ test_several_revisions_with_logical_gaps(void) if (verify_history_as_expected_onion(file, &filter) < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + if (H5FDclose(file) < 0) TEST_ERROR; file = NULL; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* CLEANUP */ if (H5Pclose(onion_info.backing_fapl_id) < 0) @@ -2527,6 +2634,9 @@ test_several_revisions_with_logical_gaps(void) return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + if (paths != NULL) { HDremove(paths->canon); @@ -2572,6 +2682,12 @@ do_onion_open_and_writes(const char *filename, H5FD_onion_fapl_info_t *onion_inf H5FD_t *file = NULL; /* Onion virtual file for read/write */ unsigned char *buf_vfy = NULL; size_t i = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ + + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; for (i = 0; i < n_ops; i++) { size_t j = 0; @@ -2633,9 +2749,17 @@ do_onion_open_and_writes(const char *filename, H5FD_onion_fapl_info_t *onion_inf fapl_id = H5I_INVALID_HID; } /* end for each open-close cycle */ + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + if (file != NULL) (void)H5FDclose(file); @@ -2685,6 +2809,7 @@ test_page_aligned_history_create(void) H5FD_onion_history_t history_out; size_t i = 0; uint64_t a_off = b_list_size_s - a_list_size_s; + bool api_ctx_pushed = false; /* Whether API context pushed */ TESTING("page-aligned history on onion-created file"); @@ -2731,6 +2856,11 @@ test_page_aligned_history_create(void) if (do_onion_open_and_writes(paths->canon, &onion_info, 2, about) < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Inspect logical file */ if (NULL == (buf = malloc(b_list_size_s * sizeof(unsigned char)))) TEST_ERROR; @@ -2817,6 +2947,11 @@ test_page_aligned_history_create(void) TEST_ERROR; file = NULL; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* CLEANUP */ if (H5Pclose(onion_info.backing_fapl_id) < 0) @@ -2835,6 +2970,8 @@ test_page_aligned_history_create(void) return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); if (paths != NULL) { HDremove(paths->canon); diff --git a/test/thread_id.c b/test/thread_id.c deleted file mode 100644 index ed1e0a8a611..00000000000 --- a/test/thread_id.c +++ /dev/null @@ -1,324 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * 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. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* Check that a thread ID returned by H5TS_thread_id() possesses the - * following properties: - * - * 1 ID >= 1. - * 2 The ID is constant over the thread's lifetime. - * 3 No two threads share an ID during their lifetimes. - * 4 A thread's ID is available for reuse as soon as it is joined. - */ - -/* - * Include required headers. This file tests internal library functions, - * so we include the private headers here. - */ -#include "testhdf5.h" - -#if defined(H5_HAVE_THREADSAFE) && !defined(H5_HAVE_WIN_THREADS) - -static void my_errx(int, const char *, ...) H5_ATTR_FORMAT(printf, 2, 3); - -static void -my_errx(int code, const char *fmt, ...) -{ - va_list ap; - - (void)fprintf(stderr, "thread_id: "); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fputc('\n', stderr); - exit(code); -} - -#if defined(H5_HAVE_DARWIN) - -typedef struct _pthread_barrierattr { - uint8_t unused; -} pthread_barrierattr_t; - -typedef struct _pthread_barrier { - uint32_t magic; - unsigned int count; - uint64_t nentered; - pthread_cond_t cv; - pthread_mutex_t mtx; -} pthread_barrier_t; - -int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *, unsigned int); -int pthread_barrier_wait(pthread_barrier_t *); -int pthread_barrier_destroy(pthread_barrier_t *); - -static const uint32_t barrier_magic = 0xf00dd00f; - -int -pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) -{ - int rc; - - if (count == 0) - return EINVAL; - - if (attr != NULL) - return EINVAL; - - memset(barrier, 0, sizeof(*barrier)); - - barrier->count = count; - - if ((rc = pthread_cond_init(&barrier->cv, NULL)) != 0) - return rc; - - if ((rc = pthread_mutex_init(&barrier->mtx, NULL)) != 0) { - (void)pthread_cond_destroy(&barrier->cv); - return rc; - } - - barrier->magic = barrier_magic; - - return 0; -} - -static void -barrier_lock(pthread_barrier_t *barrier) -{ - int rc; - - if ((rc = pthread_mutex_lock(&barrier->mtx)) != 0) { - my_errx(EXIT_FAILURE, "%s: pthread_mutex_lock: %s", __func__, strerror(rc)); - } -} - -static void -barrier_unlock(pthread_barrier_t *barrier) -{ - int rc; - - if ((rc = pthread_mutex_unlock(&barrier->mtx)) != 0) { - my_errx(EXIT_FAILURE, "%s: pthread_mutex_unlock: %s", __func__, strerror(rc)); - } -} - -int -pthread_barrier_destroy(pthread_barrier_t *barrier) -{ - int rc; - - barrier_lock(barrier); - if (barrier->magic != barrier_magic) - rc = EINVAL; - else if (barrier->nentered % barrier->count != 0) - rc = EBUSY; - else { - rc = 0; - barrier->magic = ~barrier->magic; - } - barrier_unlock(barrier); - - if (rc != 0) - return rc; - - (void)pthread_cond_destroy(&barrier->cv); - (void)pthread_mutex_destroy(&barrier->mtx); - - return 0; -} - -int -pthread_barrier_wait(pthread_barrier_t *barrier) -{ - int rc; - uint64_t threshold; - - if (barrier == NULL) - return EINVAL; - - barrier_lock(barrier); - if (barrier->magic != barrier_magic) { - rc = EINVAL; - goto out; - } - /* Compute the release `threshold`. All threads entering with count = 5 - * and `nentered` in [0, 4] should be released once `nentered` reaches 5: - * call 5 the release `threshold`. All threads entering with count = 5 - * and `nentered` in [5, 9] should be released once `nentered` reaches 10. - */ - threshold = (barrier->nentered / barrier->count + 1) * barrier->count; - barrier->nentered++; - while (barrier->nentered < threshold) { - if ((rc = pthread_cond_wait(&barrier->cv, &barrier->mtx)) != 0) - goto out; - } - rc = pthread_cond_broadcast(&barrier->cv); -out: - barrier_unlock(barrier); - return rc; -} - -#endif /* H5_HAVE_DARWIN */ - -static void my_err(int, const char *, ...) H5_ATTR_FORMAT(printf, 2, 3); - -static void -my_err(int code, const char *fmt, ...) -{ - va_list ap; - int errno_copy = errno; - - (void)fprintf(stderr, "thread_id: "); - va_start(ap, fmt); - (void)vfprintf(stderr, fmt, ap); - va_end(ap); - (void)fprintf(stderr, ": %s\n", strerror(errno_copy)); - exit(code); -} - -#define threads_failure(_call, _result) \ - do { \ - my_errx(EXIT_FAILURE, "%s.%d: " #_call ": %s", __func__, __LINE__, strerror(_result)); \ - } while (false) - -#define NTHREADS 5 - -static volatile bool failed = false; -static pthread_barrier_t barrier; -static bool used[NTHREADS]; -static pthread_mutex_t used_lock; - -static void -atomic_printf(const char *fmt, ...) -{ - char buf[80]; - va_list ap; - ssize_t nprinted, nwritten; - - va_start(ap, fmt); - nprinted = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - if (nprinted == -1) - my_err(EXIT_FAILURE, "%s.%d: vsnprintf", __func__, __LINE__); - else if (nprinted >= (ssize_t)sizeof(buf)) - my_errx(EXIT_FAILURE, "%s.%d: vsnprintf overflowed", __func__, __LINE__); - - nwritten = HDwrite(STDOUT_FILENO, buf, (size_t)nprinted); - if (nwritten < nprinted) { - my_errx(EXIT_FAILURE, "%s.%d: write error or short write", __func__, __LINE__); - } -} - -/* Each thread runs this routine. The routine fetches the current - * thread's ID, makes sure that it is in the expected range, makes - * sure that in this round of testing, no two threads shared the - * same ID, and checks that each thread's ID is constant over its lifetime. - * - * main() checks that every ID in [1, NTHREADS] is used in each round - * of testing. All NTHREADS threads synchronize on a barrier after each - * has fetched its ID. The barrier guarantees that all threads' lifetimes - * overlap at least momentarily, so the IDs will be unique, and there - * will be NTHREADS of them. Further, since thread IDs are assigned - * starting with 1, and the number of threads with IDs alive never exceeds - * NTHREADS, the least ID has to be 1 and the greatest, NTHREADS. - */ -static void * -thread_main(void H5_ATTR_UNUSED *arg) -{ - uint64_t ntid, tid; - - tid = H5TS_thread_id(); - - if (tid < 1 || NTHREADS < tid) { - atomic_printf("unexpected tid %" PRIu64 " FAIL\n", tid); - goto pre_barrier_error; - } - pthread_mutex_lock(&used_lock); - if (used[tid - 1]) { - atomic_printf("reused tid %" PRIu64 " FAIL\n", tid); - pthread_mutex_unlock(&used_lock); - goto pre_barrier_error; - } - used[tid - 1] = true; - pthread_mutex_unlock(&used_lock); - - atomic_printf("tid %" PRIu64 " in [1, %d] PASS\n", tid, NTHREADS); - pthread_barrier_wait(&barrier); - - ntid = H5TS_thread_id(); - if (ntid != tid) { - atomic_printf("tid changed from %" PRIu64 " to %" PRIu64 " FAIL\n", tid, ntid); - failed = true; - } - return NULL; -pre_barrier_error: - pthread_barrier_wait(&barrier); - failed = true; - return NULL; -} - -int -main(void) -{ - int i, rc, times; - pthread_t threads[NTHREADS]; - - /* Run H5open() to initialize the library's thread-ID freelist, - * mutex, etc. - */ - if (H5open() != SUCCEED) - my_errx(EXIT_FAILURE, "%s.%d: H5open failed", __func__, __LINE__); - - if ((rc = pthread_mutex_init(&used_lock, NULL)) == -1) - threads_failure(pthread_mutex_init, rc); - - if ((rc = pthread_barrier_init(&barrier, NULL, NTHREADS)) != 0) - threads_failure(pthread_barrier_init, rc); - - /* Start the test threads and join them twice to make sure that - * the thread IDs are recycled in the second round. - */ - for (times = 0; times < 2; times++) { - - for (i = 0; i < NTHREADS; i++) - used[i] = false; // access synchronized by thread create/join - - for (i = 0; i < NTHREADS; i++) { - rc = pthread_create(&threads[i], NULL, thread_main, NULL); - if (rc != 0) - threads_failure(pthread_create, rc); - } - - for (i = 0; i < NTHREADS; i++) { - rc = pthread_join(threads[i], NULL); - if (rc != 0) - threads_failure(pthread_join, rc); - } - - for (i = 0; i < NTHREADS; i++) { - if (!used[i]) // access synchronized by thread create/join - my_errx(EXIT_FAILURE, "thread ID %d did not run.", i + 1); - } - } - if ((rc = pthread_barrier_destroy(&barrier)) != 0) - threads_failure(pthread_barrier_destroy, rc); - return failed ? EXIT_FAILURE : EXIT_SUCCESS; -} - -#else /*H5_HAVE_THREADSAFE && !H5_HAVE_WIN_THREADS*/ -int -main(void) -{ - fprintf(stderr, "not implemented in this configuration.\n"); - return EXIT_SUCCESS; -} -#endif /*H5_HAVE_THREADSAFE && !H5_HAVE_WIN_THREADS*/ diff --git a/test/ttsafe.c b/test/ttsafe.c index 6fe14fcc390..de0f211dcda 100644 --- a/test/ttsafe.c +++ b/test/ttsafe.c @@ -102,6 +102,8 @@ main(int argc, char *argv[]) /* Tests are generally arranged from least to most complexity... */ AddTest("is_threadsafe", tts_is_threadsafe, NULL, "library threadsafe status", NULL); #ifdef H5_HAVE_THREADSAFE + AddTest("thread_id", tts_thread_id, NULL, "thread IDs", NULL); + AddTest("dcreate", tts_dcreate, cleanup_dcreate, "multi-dataset creation", NULL); AddTest("error", tts_error, cleanup_error, "per-thread error stacks", NULL); #ifdef H5_HAVE_PTHREAD_H @@ -111,6 +113,15 @@ main(int argc, char *argv[]) AddTest("acreate", tts_acreate, cleanup_acreate, "multi-attribute creation", NULL); AddTest("attr_vlen", tts_attr_vlen, cleanup_attr_vlen, "multi-file-attribute-vlen read", NULL); + /* Recursive R/W locks */ + AddTest("rec_rwlock_1", tts_rec_rw_lock_smoke_check_1, NULL, "recursive R/W lock smoke check 1 -- basic", NULL); + AddTest("rec_rwlock_2", tts_rec_rw_lock_smoke_check_2, NULL, "recursive R/W lock smoke check 2 -- mob of readers", NULL); + AddTest("rec_rwlock_3", tts_rec_rw_lock_smoke_check_3, NULL, "recursive R/W lock smoke check 3 -- mob of writers", NULL); + AddTest("rec_rwlock_4", tts_rec_rw_lock_smoke_check_4, NULL, "recursive R/W lock smoke check 4 -- mixed mob", NULL); + + /* Developer API routine tests */ + AddTest("developer", tts_develop_api, NULL, "developer API routines", NULL); + #else /* H5_HAVE_THREADSAFE */ printf("Most thread-safety tests skipped because THREADSAFE not enabled\n"); diff --git a/test/ttsafe.h b/test/ttsafe.h index ce92c0173de..b6ea7660a6a 100644 --- a/test/ttsafe.h +++ b/test/ttsafe.h @@ -23,6 +23,14 @@ */ #include "testhdf5.h" +/* + * This file needs to access private datatypes from the H5TS package. + * This file also needs to access the threadsafety testing code. + */ +#define H5TS_FRIEND /*suppress error about including H5TSpkg */ +#define H5TS_TESTING +#include "H5TSpkg.h" + /* Prototypes for the support routines */ extern char *gen_name(int); @@ -34,6 +42,12 @@ void tts_error(void); void tts_cancel(void); void tts_acreate(void); void tts_attr_vlen(void); +void tts_thread_id(void); +void tts_rec_rw_lock_smoke_check_1(void); +void tts_rec_rw_lock_smoke_check_2(void); +void tts_rec_rw_lock_smoke_check_3(void); +void tts_rec_rw_lock_smoke_check_4(void); +void tts_develop_api(void); /* Prototypes for the cleanup routines */ void cleanup_dcreate(void); diff --git a/test/ttsafe_acreate.c b/test/ttsafe_acreate.c index 84e5c6ba9de..83b94923b6e 100644 --- a/test/ttsafe_acreate.c +++ b/test/ttsafe_acreate.c @@ -102,11 +102,11 @@ tts_acreate(void) attrib_data->datatype = datatype; attrib_data->dataspace = dataspace; attrib_data->current_index = i; - threads[i] = H5TS_create_thread(tts_acreate_thread, NULL, attrib_data); + threads[i] = H5TS__create_thread(tts_acreate_thread, NULL, attrib_data); } for (i = 0; i < NUM_THREADS; i++) - H5TS_wait_for_thread(threads[i]); + H5TS__wait_for_thread(threads[i]); /* verify the correctness of the test */ for (i = 0; i < NUM_THREADS; i++) { diff --git a/test/ttsafe_attr_vlen.c b/test/ttsafe_attr_vlen.c index bfc2067e19c..2c577a5e13d 100644 --- a/test/ttsafe_attr_vlen.c +++ b/test/ttsafe_attr_vlen.c @@ -106,12 +106,12 @@ tts_attr_vlen(void) /* Start multiple threads and execute tts_attr_vlen_thread() for each thread */ for (i = 0; i < NUM_THREADS; i++) { - threads[i] = H5TS_create_thread(tts_attr_vlen_thread, NULL, NULL); + threads[i] = H5TS__create_thread(tts_attr_vlen_thread, NULL, NULL); } /* Wait for the threads to end */ for (i = 0; i < NUM_THREADS; i++) - H5TS_wait_for_thread(threads[i]); + H5TS__wait_for_thread(threads[i]); } /* end tts_attr_vlen() */ diff --git a/test/ttsafe_dcreate.c b/test/ttsafe_dcreate.c index 42c3f6c1276..a4dfda81283 100644 --- a/test/ttsafe_dcreate.c +++ b/test/ttsafe_dcreate.c @@ -67,11 +67,11 @@ tts_dcreate(void) herr_t status; /* set pthread attribute to perform global scheduling */ - H5TS_attr_init(&attribute); + H5TS__attr_init(&attribute); /* set thread scope to system */ #ifdef H5_HAVE_SYSTEM_SCOPE_THREADS - H5TS_attr_setscope(&attribute, H5TS_SCOPE_SYSTEM); + H5TS__attr_setscope(&attribute, H5TS_SCOPE_SYSTEM); #endif /* H5_HAVE_SYSTEM_SCOPE_THREADS */ /* @@ -86,11 +86,11 @@ tts_dcreate(void) thread_out[i].id = i; thread_out[i].file = file; thread_out[i].dsetname = dsetname[i]; - threads[i] = H5TS_create_thread(tts_dcreate_creator, NULL, &thread_out[i]); + threads[i] = H5TS__create_thread(tts_dcreate_creator, NULL, &thread_out[i]); } for (i = 0; i < NUM_THREAD; i++) - H5TS_wait_for_thread(threads[i]); + H5TS__wait_for_thread(threads[i]); /* compare data to see if it is written correctly */ @@ -124,7 +124,7 @@ tts_dcreate(void) CHECK(status, FAIL, "H5Fclose"); /* Destroy the thread attribute */ - H5TS_attr_destroy(&attribute); + H5TS__attr_destroy(&attribute); } /* end tts_dcreate() */ void * diff --git a/test/ttsafe_develop.c b/test/ttsafe_develop.c new file mode 100644 index 00000000000..95188747471 --- /dev/null +++ b/test/ttsafe_develop.c @@ -0,0 +1,160 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/******************************************************************** + * + * Test the correctness of the threadsafety developer API routines + * + ********************************************************************/ + +#include "ttsafe.h" + +#ifdef H5_HAVE_THREADSAFE + +typedef struct { + H5TS_barrier_t *barrier; +} tts_develop_api_udata_t; + +/* + ********************************************************************** + * tts_develop_api_thr_1 + * + ********************************************************************** + */ +static void * +tts_develop_api_thr_1(void *_udata) +{ + tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata; + unsigned lock_count = UINT_MAX; + bool acquired = false; + herr_t result; + + /* Acquire the API lock - should acquire it */ + result = H5TSmutex_acquire(1, &acquired); + CHECK_I(result, "H5TSmutex_acquire"); + VERIFY(acquired, true, "H5TSmutex_acquire"); + + H5TS__barrier_wait(udata->barrier); + + /* Thread #2 will attempt (unsuccessfully) to acquire the API lock */ + + H5TS__barrier_wait(udata->barrier); + + /* Release the API lock */ + result = H5TSmutex_release(&lock_count); + CHECK_I(result, "H5TSmutex_release"); + VERIFY(lock_count, 1, "H5TSmutex_release"); + + return NULL; +} /* end tts_develop_api_thr_1() */ + +/* + ********************************************************************** + * tts_develop_api_thr_2 + * + ********************************************************************** + */ +static void * +tts_develop_api_thr_2(void *_udata) +{ + tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata; + bool acquired = false; + herr_t result; + + /* Thread #1 will acquire the API lock */ + + H5TS__barrier_wait(udata->barrier); + + /* Attempt to acquire the API lock - should not acquire it */ + result = H5TSmutex_acquire(1, &acquired); + CHECK_I(result, "H5TSmutex_acquire"); + VERIFY(acquired, false, "H5TSmutex_acquire"); + + H5TS__barrier_wait(udata->barrier); + + /* Thread #1 will release the API lock */ + + return NULL; +} /* end tts_develop_api_thr_2() */ + +/* + ********************************************************************** + * tts_develop_api + * + ********************************************************************** + */ +void +tts_develop_api(void) +{ + H5TS_thread_t thread_1, thread_2; + H5TS_barrier_t barrier; + unsigned lock_count = UINT_MAX; + bool acquired = false; + tts_develop_api_udata_t udata; + unsigned api_count_1 = 0, api_count_2 = 0; + herr_t result; + + /* Check that API count increases with each API call */ + result = H5TSmutex_get_attempt_count(&api_count_1); + CHECK_I(result, "H5TSmutex_get_attempt_count"); + + /* No-op API call, to increment the API counter */ + result = H5garbage_collect(); + CHECK_I(result, "H5garbage_collect"); + + result = H5TSmutex_get_attempt_count(&api_count_2); + CHECK_I(result, "H5TSmutex_get_attempt_count"); + + VERIFY(api_count_2, (api_count_1 + 1), "H5TSmutex_get_attempt_count"); + + + /* Check H5TSmutex_acquire & H5TSmutex_release in thread callbacks */ + + /* Create the thread barrier for the two threads */ + result = H5TS__barrier_init(&barrier, 2); + CHECK_I(result, "H5TS__barrier_init"); + + /* Create the threads */ + udata.barrier = &barrier; + thread_1 = H5TS__create_thread(tts_develop_api_thr_1, NULL, &udata); + thread_2 = H5TS__create_thread(tts_develop_api_thr_2, NULL, &udata); + + /* Wait for threads to complete. */ + H5TS__wait_for_thread(thread_1); + H5TS__wait_for_thread(thread_2); + + result = H5TS__barrier_destroy(&barrier); + CHECK_I(result, "H5TS__barrier_destroy"); + + + /* Test multiple / recursive acquisition of the API lock */ + + /* Acquire the API lock - should acquire it */ + result = H5TSmutex_acquire(1, &acquired); + CHECK_I(result, "H5TSmutex_acquire"); + VERIFY(acquired, true, "H5TSmutex_acquire"); + + /* Acquire the API lock again - should acquire it, since it's the same thread */ + acquired = false; + result = H5TSmutex_acquire(1, &acquired); + CHECK_I(result, "H5TSmutex_acquire"); + VERIFY(acquired, true, "H5TSmutex_acquire"); + + /* Release the API lock */ + result = H5TSmutex_release(&lock_count); + CHECK_I(result, "H5TSmutex_release"); + VERIFY(lock_count, 2, "H5TSmutex_release"); + +} /* end tts_develop_api() */ + +#endif /*H5_HAVE_THREADSAFE*/ + diff --git a/test/ttsafe_error.c b/test/ttsafe_error.c index 560a7e1b2f7..6e5261d146e 100644 --- a/test/ttsafe_error.c +++ b/test/ttsafe_error.c @@ -48,7 +48,7 @@ hid_t error_file_g = H5I_INVALID_HID; int error_flag_g = 0; int error_count_g = 0; err_num_t expected_g[EXPECTED_ERROR_DEPTH]; -H5TS_mutex_simple_t error_mutex_g; +H5TS_mutex_t error_mutex_g; /* Prototypes */ static herr_t error_callback(hid_t, void *); @@ -104,11 +104,11 @@ tts_error(void) H5TS_mutex_init(&error_mutex_g); /* make thread scheduling global */ - H5TS_attr_init(&attribute); + H5TS__attr_init(&attribute); #ifdef H5_HAVE_SYSTEM_SCOPE_THREADS /* set thread scope to system */ - H5TS_attr_setscope(&attribute, H5TS_SCOPE_SYSTEM); + H5TS__attr_setscope(&attribute, H5TS_SCOPE_SYSTEM); #endif /* H5_HAVE_SYSTEM_SCOPE_THREADS */ def_fapl = H5Pcreate(H5P_FILE_ACCESS); @@ -125,10 +125,10 @@ tts_error(void) CHECK(error_file_g, H5I_INVALID_HID, "H5Fcreate"); for (i = 0; i < NUM_THREAD; i++) - threads[i] = H5TS_create_thread(tts_error_thread, &attribute, NULL); + threads[i] = H5TS__create_thread(tts_error_thread, &attribute, NULL); for (i = 0; i < NUM_THREAD; i++) - H5TS_wait_for_thread(threads[i]); + H5TS__wait_for_thread(threads[i]); if (error_flag_g) { TestErrPrintf( @@ -160,7 +160,8 @@ tts_error(void) status = H5Idec_ref(vol_id); CHECK(status, FAIL, "H5Idec_ref"); - H5TS_attr_destroy(&attribute); + H5TS__attr_destroy(&attribute); + H5TS_mutex_destroy(&error_mutex_g); } /* end tts_error() */ static void * @@ -221,9 +222,9 @@ tts_error_thread(void H5_ATTR_UNUSED *arg) static herr_t error_callback(hid_t H5_ATTR_UNUSED estack_id, void *client_data) { - H5TS_mutex_lock_simple(&error_mutex_g); + H5TS_mutex_lock(&error_mutex_g); error_count_g++; - H5TS_mutex_unlock_simple(&error_mutex_g); + H5TS_mutex_unlock(&error_mutex_g); return H5Ewalk2(H5E_DEFAULT, H5E_WALK_DOWNWARD, walk_error_callback, client_data); } diff --git a/test/ttsafe_rec_rw_lock.c b/test/ttsafe_rec_rw_lock.c new file mode 100644 index 00000000000..330b403d0f3 --- /dev/null +++ b/test/ttsafe_rec_rw_lock.c @@ -0,0 +1,1113 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/******************************************************************** + * + * Test the correctness of the recursive R/W lock in the HDF5 library + * ------------------------------------------------------------- + * + * Test the recursive R/W lock in isolation, using a combination of + * error return values and statistics collected by the recursive + * R/W lock to detect any failures. + * + * No file is created. + * + * Multiple threads are created, and allowed to compete for the lock. + * The number of threads, and the number of times they obtain the + * lock depends on the express test level. + * + ********************************************************************/ + +#include "ttsafe.h" + +#ifdef H5_HAVE_THREADSAFE +#ifndef H5_HAVE_WIN_THREADS + +#define MAX_NUM_THREADS 64 +#define MAX_LOCK_CYCLES (10 * 1000 * 1000) + +/* structure used to configure test threads in the recurive + * R/W/ lock tests. + */ +/*********************************************************************** + * + * Structure rec_rw_lock_test_udata_t + * + * Arrays of instances of rec_rw_lock_test_udata_t are used to configure + * the threads used to test the recursive R/W lock, and to collect + * statistics on their behaviour. These statistics are aggregated and + * used to cross-check the statistics collected by the recursive R/W + * lock proper. + * + * The fields of the structure are discussed below: + * + * rw_lock: Pointer to the recursive R/W under test. + * + * target_rd_lock_cycles: The number of times the test thread is + * required to obtain and drop the read lock. Note + * that this value restricts the number of initial + * read locks only. Additional recursive locks are + * possible -- see max_recursive_lock_depth below. + * + * target_wr_lock_cycles: The number of times the test thread is + * required to obtain and drop the write lock. Note + * that this value restricts the number of initial + * write locks only. Additional recursive locks are + * possible -- see max_recursive_lock_depth below. + * + * max_recursive_lock_depth: Once a test thread gains a lock, it does + * random recursive leocks and unlocks until it happens + * to drop the lock. The max_recursive_lock_depth + * places an upper bound on the net number of locks. + * Any attempt exceed this limit is converted into + * an unlock. + * + * The remaining fields are used for statistics collection. They are + * thread specific versions of the fields of the same name in + * H5TS_rw_lock_stats_t. See the header comment for that + * structure (in H5TSprivate.h) for further details. + * + ***********************************************************************/ +typedef struct rec_rw_lock_test_udata_t { + + /* thread control fields */ + H5TS_rw_lock_t *rw_lock; + int32_t target_rd_lock_cycles; + int32_t target_wr_lock_cycles; + int32_t max_recursive_lock_depth; + + /* thread stats fields */ + int64_t read_locks_granted; + int64_t read_locks_released; + int64_t real_read_locks_granted; + int64_t real_read_locks_released; + int64_t write_locks_granted; + int64_t write_locks_released; + int64_t real_write_locks_granted; + int64_t real_write_locks_released; + +} rec_rw_lock_test_udata_t; + +/* + ********************************************************************** + * tts_rw_lock_smoke_check_test_thread + * + * Perform a sequence of recursive read and/or write locks on the + * target recursive R/W lock as directed by the supplied user data. + * Record all operations in the user data for later cross-checking + * with the statistics maintained by the recursive R/W lock. + * + * Note: while the number of read and/or write locks is fixed, the + * number of _recursive_ lock and unlock calls is random, as is the + * order of the read and write locks, if both are enabled. + * + ********************************************************************** + */ +static void * +tts_rw_lock_smoke_check_test_thread(void *_udata) +{ + hbool_t read; + int32_t rec_lock_depth = 0; + int32_t max_rec_lock_depth; + int32_t rd_locks_remaining; + int32_t wr_locks_remaining; + herr_t result; + H5TS_rw_lock_t *rw_lock; + rec_rw_lock_test_udata_t *udata = (rec_rw_lock_test_udata_t *)_udata; + + assert(_udata); + rd_locks_remaining = udata->target_rd_lock_cycles; + wr_locks_remaining = udata->target_wr_lock_cycles; + max_rec_lock_depth = udata->max_recursive_lock_depth; + rw_lock = udata->rw_lock; + + while (rd_locks_remaining > 0 || wr_locks_remaining > 0) { + if (wr_locks_remaining == 0) + read = TRUE; + else if (rd_locks_remaining == 0) + read = FALSE; + else { + if ((HDrand() % 2) == 0) + read = TRUE; + else + read = FALSE; + } + + if (read) { + result = H5TS__rw_rdlock(rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + udata->read_locks_granted++; + udata->real_read_locks_granted++; + rd_locks_remaining--; + rec_lock_depth = 1; + + while (rec_lock_depth > 0) { + if (rec_lock_depth >= max_rec_lock_depth || (HDrand() % 2) == 0) { + result = H5TS__rw_unlock(rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + rec_lock_depth--; + udata->read_locks_released++; + } + else { + result = H5TS__rw_rdlock(rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + rec_lock_depth++; + udata->read_locks_granted++; + } + } + + udata->real_read_locks_released++; + } + else { + result = H5TS__rw_wrlock(rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + udata->write_locks_granted++; + udata->real_write_locks_granted++; + wr_locks_remaining--; + rec_lock_depth = 1; + + while (rec_lock_depth > 0) { + if (rec_lock_depth >= max_rec_lock_depth || (HDrand() % 2) == 0) { + result = H5TS__rw_unlock(rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + rec_lock_depth--; + udata->write_locks_released++; + } + else { + result = H5TS__rw_wrlock(rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + rec_lock_depth++; + udata->write_locks_granted++; + } + } + + udata->real_write_locks_released++; + } + } + + return NULL; +} /* end tts_rw_lock_smoke_check_test_thread() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_1 + * + * Single thread test to verify basic functionality and error + * rejection of the recursive R/W lock. + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Obtain a read lock. + * + * 3) Drop the read lock. + * + * 4) Verify the expected stats, and then reset them. + * + * 5) Obtain a read lock. + * + * 6) Obtain the read lock a second time. + * + * 7) Drop the read lock. + * + * 8) Drop the read lock a second time. + * + * 9) Verify the expected stats, and then reset them. + * + * 10) Obtain a write lock. + * + * 11) Drop the write lock. + * + * 12) Verify the expected stats, and then reset them. + * + * 13) Obtain a write lock. + * + * 14) Obtain the write lock a second time. + * + * 15) Drop the write lock. + * + * 16) Drop the write lock a second time. + * + * 17) Verify the expected stats, and then reset them. + * + * 18) Obtain a write lock. + * + * 19) Attempt to obtain a read lock -- should fail. + * + * 20) Drop the write lock. + * + * 21) Obtain a read lock. + * + * 22) Attempt to obtain a write lock -- should fail. + * + * 23) Drop the read lock. + * + * 24) Verify the expected stats, and then reset them. + * + * 25) Shut down the recursive R/W lock. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_1(void) +{ + herr_t result; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS_rw_lock_stats_t stats; +#endif + H5TS_rw_lock_t rec_rw_lock; + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Obtain a read lock. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 3) Drop the read lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 4) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 1 || + stats.read_locks_released != 1 || + stats.real_read_locks_granted != 1 || + stats.real_read_locks_released != 1 || + stats.max_read_locks != 1 || + stats.max_read_lock_recursion_depth != 1 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 0 || + stats.write_locks_released != 0 || + stats.real_write_locks_granted != 0 || + stats.real_write_locks_released != 0 || + stats.max_write_locks != 0 || + stats.max_write_lock_recursion_depth != 0 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 1"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 5) Obtain a read lock. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 6) Obtain the read lock a second time. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 7) Drop the read lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + /* 8) Drop the read lock a second time. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 9) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 2 || + stats.read_locks_released != 2 || + stats.real_read_locks_granted != 1 || + stats.real_read_locks_released != 1 || + stats.max_read_locks != 1 || + stats.max_read_lock_recursion_depth != 2 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 0 || + stats.write_locks_released != 0 || + stats.real_write_locks_granted != 0 || + stats.real_write_locks_released != 0 || + stats.max_write_locks != 0 || + stats.max_write_lock_recursion_depth != 0 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 2"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 10) Obtain a write lock. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 11) Drop the write lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 12) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 0 || + stats.read_locks_released != 0 || + stats.real_read_locks_granted != 0 || + stats.real_read_locks_released != 0 || + stats.max_read_locks != 0 || + stats.max_read_lock_recursion_depth != 0 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 1 || + stats.write_locks_released != 1 || + stats.real_write_locks_granted != 1 || + stats.real_write_locks_released != 1 || + stats.max_write_locks != 1 || + stats.max_write_lock_recursion_depth != 1 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 3"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 13) Obtain a write lock. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 14) Obtain the write lock a second time. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 15) Drop the write lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + /* 16) Drop the write lock a second time. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 17) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 0 || + stats.read_locks_released != 0 || + stats.real_read_locks_granted != 0 || + stats.real_read_locks_released != 0 || + stats.max_read_locks != 0 || + stats.max_read_lock_recursion_depth != 0 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 2 || + stats.write_locks_released != 2 || + stats.real_write_locks_granted != 1 || + stats.real_write_locks_released != 1 || + stats.max_write_locks != 1 || + stats.max_write_lock_recursion_depth != 2 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 4"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 18) Obtain a write lock. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 19) Attempt to obtain a read lock -- should fail. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + VERIFY(result, FAIL, "H5TS__rw_rdlock"); + + /* 20) Drop the write lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + /* 21) Obtain a read lock. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 22) Attempt to obtain a write lock -- should fail. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + VERIFY(result, FAIL, "H5TS__rw_wrlock"); + + /* 23) Drop the read lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 24) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 1 || + stats.read_locks_released != 1 || + stats.real_read_locks_granted != 1 || + stats.real_read_locks_released != 1 || + stats.max_read_locks != 1 || + stats.max_read_lock_recursion_depth != 1 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 1 || + stats.write_locks_released != 1 || + stats.real_write_locks_granted != 1 || + stats.real_write_locks_released != 1 || + stats.max_write_locks != 1 || + stats.max_write_lock_recursion_depth != 1 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 25) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); +} /* end tts_rec_rw_lock_smoke_check_1() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_2 -- mob of readers + * + * Multi-threaded test to check management of multiple readers ONLY by + * the recursive R/W lock. Test proceeds as follows: + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Setup the user data to be passed to each reader test thread. + * + * 3) Create the reader threads, each with its own user data. + * Activities of the reader threads is discussed in the header + * comment to tts_rw_lock_smoke_check_test_thread(). + * + * 4) Wait for all threads to complete. + * + * 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlocks. + * + * 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + * + * 7) Shut down the recursive R/W lock. + * + * The reader threads obtain and drop the read lock a specified + * number of times. Once a reader has a read lock, it does random + * recursive read locks / unlocks until drops the read lock, and then + * repeats the process until the specified number of read locks have + * been acquired and dropped. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_2(void) +{ + herr_t result; + int express_test; + int i; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rw_lock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; +#endif + H5TS_rw_lock_t rec_rw_lock; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Reset expected stats fields to zero -- we will construct the expected + * stats from the thread udata after completion. + */ + memset(&expected, 0, sizeof(expected)); +#endif + + /* Allocate the udata */ + udata = malloc(sizeof(*udata) * MAX_NUM_THREADS); + if (NULL == udata) { + TestErrPrintf("thread udata allocation failed.\n"); + + /* We can't do anything without the udata, so just return */ + return; + } + + /* Reduce # of threads and test cycles for higher levels of express testing */ + express_test = GetTestExpress(); + if (express_test >= 1) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 2) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 3) { + num_threads /= 2; + lock_cycles /= 10; + } + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Setup the user data to be passed to each reader test thread. */ + for (i = 0; i < MAX_NUM_THREADS; i++) { + memset(&udata[i], 0, sizeof(udata[i])); + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_rd_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; + } + +uint64_t start_time = H5_now_usec(); + /* 3) Create the reader threads, each with its own user data. */ + for (i = 0; i < num_threads; i++) + threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &udata[i]); + + /* 4) Wait for all threads to complete. */ + for (i = 0; i < num_threads; i++) + H5TS__wait_for_thread(threads[i]); +uint64_t end_time = H5_now_usec(); +uint64_t elap_time = (unsigned long long)(end_time - start_time); +fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, (elap_time / (uint64_t)lock_cycles)); + + /* 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlocks. + * + * First, tally up the lock entries and exits from the test threads, + * and store this data in the expected recursive R/W/ lock stats.. + * In passing, verify that each thread has done the expected number + * of locks and unlocks. Do these as asserts -- will run checks on + * aggregate data shortly. + */ + + for (i = 0; i < num_threads; i++) { + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_granted); + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_released); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; + total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; + + expected.read_locks_granted += udata[i].read_locks_granted; + expected.read_locks_released += udata[i].read_locks_released; + expected.real_read_locks_granted += udata[i].real_read_locks_granted; + expected.real_read_locks_released += udata[i].real_read_locks_released; + expected.write_locks_granted += udata[i].write_locks_granted; + expected.write_locks_released += udata[i].write_locks_released; + expected.real_write_locks_granted += udata[i].real_write_locks_granted; + expected.real_write_locks_released += udata[i].real_write_locks_released; +#endif + } + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Verify that the threads executed the expected number of read and write + * lock cycles. If they didn't, some thread probably encountered an error + * and exited early. + */ + if (total_target_rd_lock_cycles != expected.real_read_locks_granted || + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) + TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); + + /* initialize remaining non-zero fields in the expected stats */ + expected.max_read_locks = num_threads; + expected.max_read_lock_recursion_depth = 10; + + /* 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + */ + + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + /* turn off clang-format for readability */ + /* clang-format off */ + if (stats.read_locks_granted != expected.read_locks_granted || + stats.read_locks_released != expected.read_locks_released || + stats.real_read_locks_granted != expected.real_read_locks_granted || + stats.real_read_locks_released != expected.real_read_locks_released || + stats.max_read_locks > expected.max_read_locks || + stats.max_read_locks < 1 || + stats.max_read_lock_recursion_depth > expected.max_read_lock_recursion_depth || + stats.max_read_lock_recursion_depth < 1 || + stats.read_locks_delayed != expected.read_locks_delayed || + stats.write_locks_granted != expected.write_locks_granted || + stats.write_locks_released != expected.write_locks_released || + stats.real_write_locks_granted != expected.real_write_locks_granted || + stats.real_write_locks_released != expected.real_write_locks_released || + stats.max_write_locks != expected.max_write_locks || + stats.max_write_lock_recursion_depth != expected.max_write_lock_recursion_depth || + stats.write_locks_delayed != expected.write_locks_delayed || + stats.max_write_locks_pending != expected.max_write_locks_pending) { + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rw_lock_print_stats("Expected stats", &expected); + } + /* clang-format on */ + + if (verbose) + H5TS__rw_lock_print_stats("mob of readers stats", &stats); +#endif + + /* 7) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); + + /* discard the udata if it exists */ + if (udata) + free(udata); +} /* end tts_rec_rw_lock_smoke_check_2() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_3 -- mob of writers + * + * Multi-thread test to check management of multiple writers ONLY by + * the recursive R/W lock. Test proceeds as follows: + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Setup the user data to be passed to each writer test thread. + * + * 3) Create the writer threads, each with its own user data. + * Activities of the writer threads is discussed in the header + * comment to tts_rw_lock_smoke_check_test_thread(). + * + * 4) Wait for all threads to complete. + * + * 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlock. + * + * 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + * + * 7) Shut down the recursive R/W lock. + * + * The writer threads obtain and drop the read lock a specified + * number of times. Once a writeer has a write lock, it does random + * recursive write locks / unlocks until drops the write lock, and then + * repeats the process until the specified number of write locks have + * been acquired and dropped. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_3(void) +{ + herr_t result; + int i; + int express_test; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rw_lock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; +#endif + H5TS_rw_lock_t rec_rw_lock; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Reset expected stats fields to zero -- we will construct the expected + * stats from the thread udata after completion. + */ + memset(&expected, 0, sizeof(expected)); +#endif + + /* Allocate the udata */ + udata = malloc(sizeof(*udata) * MAX_NUM_THREADS); + if (udata == NULL) { + TestErrPrintf("thread udata allocation failed.\n"); + + /* We can't do anything without the udata, so just return */ + return; + } + + /* Reduce # of threads and test cycles for higher levels of express testing */ + express_test = GetTestExpress(); + if (express_test >= 1) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 2) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 3) { + num_threads /= 2; + lock_cycles /= 10; + } + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Setup the user data to be passed to each writer test thread. */ + for (i = 0; i < MAX_NUM_THREADS; i++) { + memset(&udata[i], 0, sizeof(udata[i])); + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_wr_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; + } + +uint64_t start_time = H5_now_usec(); + /* 3) Create the writer threads, each with its own user data. */ + for (i = 0; i < num_threads; i++) + threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &(udata[i])); + + /* 4) Wait for all threads to complete. */ + for (i = 0; i < num_threads; i++) + H5TS__wait_for_thread(threads[i]); +uint64_t end_time = H5_now_usec(); +uint64_t elap_time = (unsigned long long)(end_time - start_time); +fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, (elap_time / (uint64_t)lock_cycles)); + + /* 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlock. + * + * First, tally up the lock entries and exits from the test threads, + * and store this data in the expected recursive R/W/ lock stats.. + * In passing, verify that each thread has done the expected number + * of locks and unlocks. Do these as asserts -- will run checks on + * aggregate data shortly. + */ + + for (i = 0; i < num_threads; i++) { + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_granted); + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_released); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; + total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; + + expected.read_locks_granted += udata[i].read_locks_granted; + expected.read_locks_released += udata[i].read_locks_released; + expected.real_read_locks_granted += udata[i].real_read_locks_granted; + expected.real_read_locks_released += udata[i].real_read_locks_released; + expected.write_locks_granted += udata[i].write_locks_granted; + expected.write_locks_released += udata[i].write_locks_released; + expected.real_write_locks_granted += udata[i].real_write_locks_granted; + expected.real_write_locks_released += udata[i].real_write_locks_released; +#endif + } + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Verify that the threads executed the expected number of read and write + * lock cycles. If they didn't, some thread probably encountered an error + * and exited early. + */ + if (total_target_rd_lock_cycles != expected.real_read_locks_granted || + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) + TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); + + /* initialize remaining non-zero fields in the expected stats */ + expected.max_write_locks = 1; + expected.max_write_lock_recursion_depth = 10; + expected.max_write_locks_pending = num_threads - 1; + + /* 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + /* turn off clang-format for readability */ + /* clang-format off */ + if (stats.read_locks_granted != expected.read_locks_granted || + stats.read_locks_released != expected.read_locks_released || + stats.real_read_locks_granted != expected.real_read_locks_granted || + stats.real_read_locks_released != expected.real_read_locks_released || + stats.max_read_locks != expected.max_read_locks || + stats.max_read_lock_recursion_depth != expected.max_read_lock_recursion_depth || + stats.read_locks_delayed != expected.read_locks_delayed || + stats.write_locks_granted != expected.write_locks_granted || + stats.write_locks_released != expected.write_locks_released || + stats.real_write_locks_granted != expected.real_write_locks_granted || + stats.real_write_locks_released != expected.real_write_locks_released || + stats.max_write_locks != expected.max_write_locks || + stats.max_write_lock_recursion_depth > expected.max_write_lock_recursion_depth || + stats.max_write_lock_recursion_depth < 1 || + stats.write_locks_delayed < expected.write_locks_delayed || + stats.max_write_locks_pending > expected.max_write_locks_pending) { + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rw_lock_print_stats("Expected stats", &expected); + } + /* clang-format on */ + + if (verbose) + H5TS__rw_lock_print_stats("Actual stats", &stats); +#endif + + /* 7) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); + + /* discard the udata if it exists */ + if (udata) + free(udata); +} /* end tts_rec_rw_lock_smoke_check_3() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_4 -- mixed mob + * + * Multi-thread test to check management of multiple readers and + * writers by the recursive R/W lock. Test proceeds as follows: + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Setup the user data to be passed to each writer test thread. + * + * 3) Create the reader / writer threads, each with its own user data. + * Activities of the reader / writer threads is discussed in the + * header comment to tts_rw_lock_smoke_check_test_thread(). + * + * 4) Wait for all threads to complete. + * + * 5) Examine the user data from the threads, to determine the + * total number of real and recursive read & write locks and + * unlock. + * + * 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + * + * 7) Shut down the recursive R/W lock. + * + * The reader / writer threads obtain and drop the read or write + * locks a specified number of times. Once a thread has a lock, it + * does random recursive locks / unlocks until drops the lock, and then + * repeats the process until the specified number of locks have + * been acquired and dropped. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_4(void) +{ + herr_t result; + int i; + int express_test; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rw_lock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; +#endif + H5TS_rw_lock_t rec_rw_lock; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Reset expected stats fields to zero -- we will construct the expected + * stats from the thread udata after completion. + */ + memset(&expected, 0, sizeof(expected)); +#endif + + /* Allocate the udata */ + udata = malloc(sizeof(*udata) * MAX_NUM_THREADS); + if (udata == NULL) { + TestErrPrintf("thread udata allocation failed.\n"); + + /* We can't do anything without the udata, so just return */ + return; + } + + /* Reduce # of threads and test cycles for higher levels of express testing */ + express_test = GetTestExpress(); + if (express_test >= 1) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 2) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 3) { + num_threads /= 2; + lock_cycles /= 10; + } + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Setup the user data to be passed to each writer test thread. */ + for (i = 0; i < MAX_NUM_THREADS; i++) { + memset(&udata[i], 0, sizeof(udata[i])); + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_rd_lock_cycles = lock_cycles; + udata[i].target_wr_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; + } + +uint64_t start_time = H5_now_usec(); + /* 3) Create the reader threads, each with its own user data. */ + for (i = 0; i < num_threads; i++) + threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &(udata[i])); + + /* 4) Wait for all threads to complete. */ + for (i = 0; i < num_threads; i++) + H5TS__wait_for_thread(threads[i]); +uint64_t end_time = H5_now_usec(); +uint64_t elap_time = (unsigned long long)(end_time - start_time); +fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, (elap_time / (uint64_t)lock_cycles)); + + /* 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlock. + * + * First, tally up the lock entries and exits from the test threads, + * and store this data in the expected recursive R/W/ lock stats.. + * In passing, verify that each thread has done the expected number + * of locks and unlocks. Do these as asserts -- will run checks on + * aggregate data shortly. + */ + + for (i = 0; i < num_threads; i++) { + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_granted); + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_released); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; + total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; + + expected.read_locks_granted += udata[i].read_locks_granted; + expected.read_locks_released += udata[i].read_locks_released; + expected.real_read_locks_granted += udata[i].real_read_locks_granted; + expected.real_read_locks_released += udata[i].real_read_locks_released; + expected.write_locks_granted += udata[i].write_locks_granted; + expected.write_locks_released += udata[i].write_locks_released; + expected.real_write_locks_granted += udata[i].real_write_locks_granted; + expected.real_write_locks_released += udata[i].real_write_locks_released; +#endif + } + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Verify that the threads executed the expected number of read and write + * lock cycles. If they didn't, some thread probably encountered an error + * and exited early. + */ + if (total_target_rd_lock_cycles != expected.real_read_locks_granted || + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) + TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); + + /* initialize remaining non-zero fields in the expected stats */ + expected.max_read_locks = num_threads; + expected.max_read_lock_recursion_depth = 10; + expected.max_write_locks = 1; + expected.max_write_lock_recursion_depth = 10; + expected.max_write_locks_pending = num_threads - 1; + + /* 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + /* turn off clang-format for readability */ + /* clang-format off */ + if (stats.read_locks_granted != expected.read_locks_granted || + stats.read_locks_released != expected.read_locks_released || + stats.real_read_locks_granted != expected.real_read_locks_granted || + stats.real_read_locks_released != expected.real_read_locks_released || + stats.max_read_locks > expected.max_read_locks || + stats.max_read_locks < 1 || + stats.max_read_lock_recursion_depth > expected.max_read_lock_recursion_depth || + stats.read_locks_delayed < expected.read_locks_delayed || + stats.write_locks_granted != expected.write_locks_granted || + stats.write_locks_released != expected.write_locks_released || + stats.real_write_locks_granted != expected.real_write_locks_granted || + stats.real_write_locks_released != expected.real_write_locks_released || + stats.max_write_locks != expected.max_write_locks || + stats.max_write_lock_recursion_depth > expected.max_write_lock_recursion_depth || + stats.max_write_lock_recursion_depth < 1 || + stats.write_locks_delayed < expected.write_locks_delayed || + stats.max_write_locks_pending > expected.max_write_locks_pending) { + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rw_lock_print_stats("Expected stats", &expected); + } + /* clang-format on */ + + if (verbose) + H5TS__rw_lock_print_stats("Actual stats", &stats); +#endif + + /* 7) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); + + /* discard the udata if it exists */ + if (udata) + free(udata); +} /* end tts_rec_rw_lock_smoke_check_4() */ + +#endif /*H5_HAVE_WIN_THREADS*/ +#endif /*H5_HAVE_THREADSAFE*/ diff --git a/test/ttsafe_thread_id.c b/test/ttsafe_thread_id.c new file mode 100644 index 00000000000..aa77499eb4b --- /dev/null +++ b/test/ttsafe_thread_id.c @@ -0,0 +1,137 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/******************************************************************** + * + * Test the correctness of the threadsafety developer API routines + * + ********************************************************************/ + +#include "ttsafe.h" + +#ifdef H5_HAVE_THREADSAFE + +#define CYCLE_COUNT 2 +#define NTHREADS 5 + +static volatile bool failed = false; +static H5TS_barrier_t barrier; +static int times; +static bool used[NTHREADS * CYCLE_COUNT]; +static H5TS_mutex_t used_lock = PTHREAD_MUTEX_INITIALIZER; + +/* Each thread runs this routine. The routine fetches the current + * thread's ID, makes sure that it is in the expected range, makes + * sure that in this round of testing, no two threads shared the + * same ID, and checks that each thread's ID is constant over its lifetime. + * + * main() checks that every ID in the range + * [(times * NTHREADS) + 2, (times * NTHREADS) + NTHREADS + 1] is used in each + * round of testing. All NTHREADS threads synchronize on a barrier after each + * has fetched its ID. The barrier guarantees that all threads' lifetimes + * overlap at least momentarily, so the IDs will be unique, and there + * will be NTHREADS of them. Further, since thread IDs are assigned + * starting with 1 (which the main thread gets), the number of threads with + * IDs alive never exceeds NTHREADS, and thread IDs are never recycled, the + * least ID has to be (times * NTHREADS) + 2 and the greatest, + * (times * NTHREADS) + NTHREADS + 1. + */ +static void * +thread_main(void H5_ATTR_UNUSED *arg) +{ + int min_id, max_id; + uint64_t ntid, tid; + + tid = H5TS_thread_id(); + + H5TS_mutex_lock(&used_lock); + min_id = (times * NTHREADS) + 2; + max_id = (times * NTHREADS) + NTHREADS + 1; + + /* Verify that thread ID is in correct range */ + if (tid < (uint64_t)min_id || (uint64_t)max_id < tid) { + TestErrPrintf("unexpected tid %" PRIu64 " FAIL\n", tid); + goto pre_barrier_error; + } + + /* Verify that the thread ID hasn't been re-used */ + if (used[tid - 2]) { + TestErrPrintf("reused tid %" PRIu64 " FAIL\n", tid); + H5TS_mutex_unlock(&used_lock); + goto pre_barrier_error; + } + used[tid - 2] = true; + H5TS_mutex_unlock(&used_lock); + + H5TS__barrier_wait(&barrier); + + /* Verify that the thread ID hasn't changed */ + ntid = H5TS_thread_id(); + if (ntid != tid) + TestErrPrintf("tid changed from %" PRIu64 " to %" PRIu64 " FAIL\n", tid, ntid); + + return NULL; + +pre_barrier_error: + H5TS__barrier_wait(&barrier); + + return NULL; +} + +/* + ********************************************************************** + * tts_thread_id + * + ********************************************************************** + */ +void +tts_thread_id(void) +{ + H5TS_thread_t threads[NTHREADS]; + uint64_t tid; + int i; + herr_t result; + + result = H5TS__barrier_init(&barrier, NTHREADS); + CHECK_I(result, "H5TS__barrier_init"); + + /* Get the thread ID for the main thread, so that the child threads + * always start from a thread ID of 2. + */ + tid = H5TS_thread_id(); + VERIFY(tid, 1, "H5TS_thread_id"); + + /* Start the test threads and join them twice to make sure that + * the thread IDs are recycled in the second round. + */ + memset(used, 0, sizeof(used)); + for (times = 0; times < CYCLE_COUNT; times++) { + for (i = 0; i < NTHREADS; i++) + threads[i] = H5TS__create_thread(thread_main, NULL, NULL); + + for (i = 0; i < NTHREADS; i++) + H5TS__wait_for_thread(threads[i]); + + /* Access synchronized by thread create/join */ + for (i = 0; i < NTHREADS; i++) { + if(!used[(times * NTHREADS) + i]) + TestErrPrintf("thread ID %d did not run.", i + 1); + } + } + result = H5TS__barrier_destroy(&barrier); + CHECK_I(result, "H5TS__barrier_init"); + +} /* end tts_thread_id() */ + +#endif /*H5_HAVE_THREADSAFE*/ + + diff --git a/test/vfd.c b/test/vfd.c index 5a86920652e..8ce87e82d02 100644 --- a/test/vfd.c +++ b/test/vfd.c @@ -4241,26 +4241,34 @@ test_vector_io__read_v_indiv(H5FD_t *lf, uint32_t count, H5FD_mem_t types[], had uint32_t i; size_t size = SIZE_MAX; H5FD_mem_t type = H5FD_MEM_NTYPES; + bool api_ctx_pushed = false; /* Whether API context pushed */ - for (i = 0; i < count; i++) { + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + for (i = 0; i < count; i++) { SET_SIZE(size_fixed, sizes, size, i); - SET_TYPE(type_fixed, types, type, i); - if (H5FDread(lf, type, H5P_DEFAULT, addrs[i], size, read_bufs[i]) < 0) { - - if (verbose) { - + if (verbose) fprintf(stdout, "%s: H5FDread() failed on entry %d.\n", __func__, i); - } result = false; break; } } - return (result); + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + +error: + if (api_ctx_pushed) + H5CX_pop(false); + return (result); } /* end test_vector_io__read_v_indiv() */ /*------------------------------------------------------------------------- @@ -4289,26 +4297,31 @@ test_vector_io__write_v_indiv(H5FD_t *lf, uint32_t count, H5FD_mem_t types[], ha uint32_t i; size_t size = SIZE_MAX; H5FD_mem_t type = H5FD_MEM_NTYPES; + bool api_ctx_pushed = false; /* Whether API context pushed */ - for (i = 0; i < count; i++) { + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + for (i = 0; i < count; i++) { SET_SIZE(size_fixed, sizes, size, i); - SET_TYPE(type_fixed, types, type, i); - if (H5FDwrite(lf, type, H5P_DEFAULT, addrs[i], size, write_bufs[i]) < 0) { - - if (verbose) { - + if (verbose) fprintf(stdout, "%s: HDwrite() failed on entry %d.\n", __func__, i); - } result = false; break; } } - return (result); + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; +error: + return (result); } /* end test_vector_io__write_v_indiv() */ /*------------------------------------------------------------------------- @@ -4466,12 +4479,12 @@ static herr_t test_vector_io(const char *vfd_name) { char test_title[80]; - bool size_fixed_0 = false; /* whether remaining entry */ - bool size_fixed_1 = false; /* sizes in vector are fixed. */ - bool size_fixed_2 = false; /* */ - bool type_fixed_0 = false; /* whether remaining entry */ - bool type_fixed_1 = false; /* types in vector are fixed. */ - bool type_fixed_2 = false; /* */ + bool size_fixed_0 = false; /* whether remaining entry */ + bool size_fixed_1 = false; /* sizes in vector are fixed. */ + bool size_fixed_2 = false; /* */ + bool type_fixed_0 = false; /* whether remaining entry */ + bool type_fixed_1 = false; /* types in vector are fixed. */ + bool type_fixed_2 = false; /* */ bool verbose = false; hid_t fapl_id = H5I_INVALID_HID; /* file access property list ID */ haddr_t eoa; /* file eoa */ @@ -4518,6 +4531,7 @@ test_vector_io(const char *vfd_name) void *f_read_bufs_0[VECTOR_LEN]; /* fixed read bufs vector */ void *f_read_bufs_1[VECTOR_LEN]; /* fixed read bufs vector */ void *f_read_bufs_2[VECTOR_LEN]; /* fixed read bufs vector */ + bool api_ctx_pushed = false; /* Whether API context pushed */ snprintf(test_title, sizeof(test_title), "vector I/O with %s VFD", vfd_name); @@ -4564,6 +4578,11 @@ test_vector_io(const char *vfd_name) f_read_bufs_2, 'B'))) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + flags = H5F_ACC_RDWR | H5F_ACC_CREAT | H5F_ACC_TRUNC; if (NULL == (lf = H5FDopen(filename, flags, fapl_id, HADDR_UNDEF))) @@ -4647,6 +4666,11 @@ test_vector_io(const char *vfd_name) if (H5FDread_vector(lf, H5P_DEFAULT, count, f_types_0, f_addrs_0, f_sizes_0, f_read_bufs_0) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* verify that the expected data is read */ if (!test_vector_io__verify_v(count, types_0, sizes_0, write_bufs_0, read_bufs_0, "zero")) TEST_ERROR; @@ -4660,6 +4684,11 @@ test_vector_io(const char *vfd_name) if (!test_vector_io__write_v_indiv(lf, count, types_1, addrs_1, sizes_1, write_bufs_1)) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + if (H5FDread_vector(lf, H5P_DEFAULT, 1, &(types_1[0]), &(addrs_1[0]), &(sizes_1[0]), &(read_bufs_1[0])) < 0) TEST_ERROR; @@ -4672,13 +4701,28 @@ test_vector_io(const char *vfd_name) &(read_bufs_1[3])) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* for fixed size, write individually, and the read back in a single call */ if (!test_vector_io__write_v_indiv(lf, count, f_types_1, f_addrs_1, f_sizes_1, f_write_bufs_1)) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + if (H5FDread_vector(lf, H5P_DEFAULT, count, f_types_1, f_addrs_1, f_sizes_1, f_read_bufs_1) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* verify that the expected data is read */ if (!test_vector_io__verify_v(count, types_1, sizes_1, write_bufs_1, read_bufs_1, "one")) TEST_ERROR; @@ -4686,6 +4730,11 @@ test_vector_io(const char *vfd_name) if (!test_vector_io__verify_v(count, f_types_1, f_sizes_1, f_write_bufs_1, f_read_bufs_1, "fixed one")) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Write the contents of a vector as several vector writes, then * read it back in individual reads. */ @@ -4701,13 +4750,28 @@ test_vector_io(const char *vfd_name) &(write_bufs_2[3])) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + if (!test_vector_io__read_v_indiv(lf, count, types_2, addrs_2, sizes_2, read_bufs_2)) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* for fixed size, write as a single vector, read back individually */ if (H5FDwrite_vector(lf, H5P_DEFAULT, count, f_types_2, f_addrs_2, f_sizes_2, f_write_bufs_2) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + if (!test_vector_io__read_v_indiv(lf, count, f_types_2, f_addrs_2, f_sizes_2, f_read_bufs_2)) TEST_ERROR; @@ -4718,6 +4782,11 @@ test_vector_io(const char *vfd_name) if (!test_vector_io__verify_v(count, f_types_2, f_sizes_2, f_write_bufs_2, f_read_bufs_2, "fixed two")) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* make note of eoa -- needed after we re-open the file */ if (HADDR_UNDEF == (eoa = H5FDget_eoa(lf, H5FD_MEM_DEFAULT))) TEST_ERROR; @@ -4804,6 +4873,11 @@ test_vector_io(const char *vfd_name) if (H5FDread_vector(lf, H5P_DEFAULT, count, f_types_2, f_addrs_2, f_sizes_2, f_read_bufs_2) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* verify the contents. */ if (!test_vector_io__verify_v(count, types_0, sizes_0, write_bufs_0, read_bufs_0, "zero-")) TEST_ERROR; @@ -4823,9 +4897,19 @@ test_vector_io(const char *vfd_name) if (!test_vector_io__verify_v(count, f_types_2, f_sizes_2, f_write_bufs_2, f_read_bufs_2, "fixed two-")) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + if (H5FDclose(lf) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + h5_delete_test_file(FILENAME[0], fapl_id); /* Close the fapl */ @@ -4877,6 +4961,9 @@ test_vector_io(const char *vfd_name) return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + H5E_BEGIN_TRY { H5Pclose(fapl_id); @@ -4908,6 +4995,7 @@ test_selection_io_write(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t mem_s const void **bufs; /* Avoids cast/const warnings */ int i; int j; + bool api_ctx_pushed = false; /* Whether API context pushed */ if (NULL == (bufs = calloc(count, sizeof(void *)))) TEST_ERROR; @@ -4920,16 +5008,29 @@ test_selection_io_write(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t mem_s bufs[i] = wbufs[i]; } + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Issue write call */ if (H5FDwrite_selection(lf, type, H5P_DEFAULT, count, mem_spaces, file_spaces, offsets, element_sizes, bufs) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + free(bufs); return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + free(bufs); return -1; } /* end test_selection_io_write() */ @@ -4957,6 +5058,7 @@ test_selection_io_read_verify(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t int *rbufs[2] = {rbuf1, rbuf2}; int i; int j; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Initialize read buffer */ for (i = 0; i < (int)rbufcount; i++) @@ -4970,11 +5072,21 @@ test_selection_io_read_verify(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t else rbufs[i] = rbufs[rbufcount - 1]; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Issue read call */ if (H5FDread_selection(lf, type, H5P_DEFAULT, count, mem_spaces, file_spaces, offsets, element_sizes, (void **)rbufs) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* Verify result */ for (i = 0; i < (int)rbufcount; i++) for (j = 0; j < SEL_IO_DIM0 * SEL_IO_DIM1; j++) @@ -5001,6 +5113,9 @@ test_selection_io_read_verify(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + return -1; } /* end test_selection_io_read_verify() */ @@ -5050,7 +5165,8 @@ test_selection_io(const char *vfd_name) int erbuf1[SEL_IO_DIM0 * SEL_IO_DIM1]; /* 1D expected read buffer */ int erbuf2[SEL_IO_DIM0][SEL_IO_DIM1]; /* 2D expected read buffer */ int *erbufs[2] = {erbuf1, erbuf2[0]}; /* Array of expected read buffers */ - int shorten_element_sizes; /* Whether to shorten the element sizes array */ + int shorten_element_sizes; /* Whether to shorten the element sizes array */ + bool api_ctx_pushed = false; /* Whether API context pushed */ snprintf(test_title, sizeof(test_title), "selection I/O with %s VFD", vfd_name); @@ -5098,18 +5214,38 @@ test_selection_io(const char *vfd_name) if ((file_spaces[1] = H5Screate_simple(2, dims2, NULL)) < 0) TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Create file */ flags = H5F_ACC_RDWR | H5F_ACC_CREAT | H5F_ACC_TRUNC; if (NULL == (lf = H5FDopen(filename, flags, fapl_id, HADDR_UNDEF))) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* Loop over memory types */ for (type = 1; type < H5FD_MEM_NTYPES; type++) { + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* Allocate space for I/O */ addrs[0] = H5FDalloc(lf, type, H5P_DEFAULT, (hsize_t)(sizeof(int) * SEL_IO_DIM0 * SEL_IO_DIM1)); addrs[1] = H5FDalloc(lf, type, H5P_DEFAULT, (hsize_t)(sizeof(int) * SEL_IO_DIM0 * SEL_IO_DIM1)); + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + /* * Test 1: Simple 1D contiguous I/O */ @@ -5823,6 +5959,11 @@ test_selection_io(const char *vfd_name) element_sizes[1] = element_sizes[0]; } + /* Push API context */ + if (H5CX_push() < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = true; + /* * Cleanup */ @@ -5830,6 +5971,11 @@ test_selection_io(const char *vfd_name) if (H5FDclose(lf) < 0) TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed && H5CX_pop(false) < 0) + FAIL_STACK_ERROR; + api_ctx_pushed = false; + h5_delete_test_file(FILENAME[0], fapl_id); /* Close the fapl */ @@ -5848,6 +5994,9 @@ test_selection_io(const char *vfd_name) return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + H5E_BEGIN_TRY { H5Pclose(fapl_id); diff --git a/testpar/t_vfd.c b/testpar/t_vfd.c index cce5cf775e8..07c44a93929 100644 --- a/testpar/t_vfd.c +++ b/testpar/t_vfd.c @@ -356,6 +356,7 @@ setup_vfd_test_file(int file_name_id, char *file_name, int mpi_size, H5FD_mpio_x hid_t dxpl_id = H5I_INVALID_HID; /* data access property list ID */ unsigned flags = 0; /* file open flags */ H5FD_t *lf = NULL; /* VFD struct ptr */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(vfd_name); assert(lf_ptr); @@ -509,6 +510,12 @@ setup_vfd_test_file(int file_name_id, char *file_name, int mpi_size, H5FD_mpio_x if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* Open the VFD test file with the specified VFD. */ if (pass) { @@ -595,6 +602,10 @@ setup_vfd_test_file(int file_name_id, char *file_name, int mpi_size, H5FD_mpio_x H5Pclose(dxpl_id); } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + return; } /* setup_vfd_test_file() */ @@ -616,6 +627,7 @@ takedown_vfd_test_file(int mpi_rank, char *filename, H5FD_t **lf_ptr, hid_t *fap const char *fcn_name = "takedown_vfd_test_file()"; int cp = 0; bool show_progress = false; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(lf_ptr); assert(fapl_id_ptr); @@ -624,6 +636,12 @@ takedown_vfd_test_file(int mpi_rank, char *filename, H5FD_t **lf_ptr, hid_t *fap if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* Close the test file if it is open, regardless of the value of pass. * This should let the test program shut down more cleanly. */ @@ -637,6 +655,11 @@ takedown_vfd_test_file(int mpi_rank, char *filename, H5FD_t **lf_ptr, hid_t *fap } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -745,6 +768,7 @@ vector_read_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[1]; size_t sizes[1]; void *bufs[1]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -788,6 +812,12 @@ vector_read_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire increasing_fi_buf to * the file. */ @@ -806,12 +836,23 @@ vector_read_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) On each rank, zero the read buffer, and then read * INTS_PER_RANK * sizeof(int32) bytes from the file * starting at offset mpi_rank * INTS_PER_RANK * @@ -867,6 +908,11 @@ vector_read_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -975,6 +1021,7 @@ vector_read_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[1]; size_t sizes[1]; void *bufs[1]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -1018,6 +1065,12 @@ vector_read_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire decreasing_fi_buf to * the file. */ @@ -1036,6 +1089,11 @@ vector_read_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); @@ -1054,6 +1112,12 @@ vector_read_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 5) On even ranks, read INTS_PER_RANK * sizeof(int32) * bytes from the file starting at offset mpi_rank * * INTS_PER_RANK * sizeof(int32_t) in both the file and @@ -1158,6 +1222,11 @@ vector_read_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -1276,6 +1345,7 @@ vector_read_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[4]; size_t sizes[4]; void *bufs[4]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -1319,6 +1389,12 @@ vector_read_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire negative_fi_buf to * the file. */ @@ -1337,6 +1413,11 @@ vector_read_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); @@ -1358,6 +1439,12 @@ vector_read_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 5) On each rank, do a vector read from the file, with * each rank's vector having four elements, with each * element reading INTS_PER_RANK / 4 * sizeof(int32) @@ -1428,6 +1515,11 @@ vector_read_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -1629,6 +1721,7 @@ vector_read_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[4]; size_t sizes[4]; void *bufs[4]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -1672,6 +1765,12 @@ vector_read_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire negative_fi_buf to * the file. */ @@ -1690,6 +1789,11 @@ vector_read_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); @@ -1708,6 +1812,12 @@ vector_read_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 5) For each rank, define base_index equal to: * * mpi_rank * INTS_PER_RANK @@ -1816,6 +1926,11 @@ vector_read_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 6) On each rank, verify that read_fi_buf contains the * the expected values -- that is the matching values from * increasing_fi_buf where ever there was a read, and zero @@ -2056,6 +2171,7 @@ vector_read_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[(INTS_PER_RANK / 16) + 1]; size_t sizes[2]; void *bufs[(INTS_PER_RANK / 16) + 1]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2099,6 +2215,12 @@ vector_read_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire negative_fi_buf to * the file. */ @@ -2117,6 +2239,11 @@ vector_read_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); @@ -2135,6 +2262,12 @@ vector_read_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 5) For each rank, define base_index equal to: * * mpi_rank * INTS_PER_RANK @@ -2176,6 +2309,11 @@ vector_read_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2292,6 +2430,7 @@ vector_write_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[1]; size_t sizes[1]; const void *bufs[1]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2335,6 +2474,12 @@ vector_write_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Write the entire increasing_fi_buf to the file, with * exactly one buffer per vector per rank. Use either * independent or collective I/O as specified. @@ -2355,6 +2500,11 @@ vector_write_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2365,6 +2515,12 @@ vector_write_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf. Report failure * if any differences are detected. @@ -2391,6 +2547,11 @@ vector_write_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2479,6 +2640,7 @@ vector_write_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[1]; size_t sizes[1]; const void *bufs[1]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2522,6 +2684,12 @@ vector_write_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Write the odd blocks of the increasing_fi_buf to the file, * with the odd ranks writing the odd blocks, and the even * ranks writing an empty vector. @@ -2589,6 +2757,11 @@ vector_write_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2599,6 +2772,12 @@ vector_write_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 5) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf. Report failure * if any differences are detected. @@ -2643,6 +2822,11 @@ vector_write_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2732,6 +2916,7 @@ vector_write_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[4]; size_t sizes[4]; const void *bufs[4]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2775,6 +2960,12 @@ vector_write_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) For each rank, construct a vector with base address * (mpi_rank * INTS_PER_RANK) and writing all bytes from * that address to ((mpi_rank + 1) * INTS_PER_RANK) - 1. @@ -2818,6 +3009,11 @@ vector_write_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2828,6 +3024,12 @@ vector_write_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf, * decreasing_fi_buf, negative_fi_buf, and zero_fi_buf as @@ -2897,6 +3099,11 @@ vector_write_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -2992,6 +3199,7 @@ vector_write_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[4]; size_t sizes[4]; const void *bufs[4]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -3035,6 +3243,12 @@ vector_write_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) For each rank, construct a vector with base address * (mpi_rank * INTS_PER_RANK) and writing all bytes from * that address to ((mpi_rank + 1) * INTS_PER_RANK) - 1. @@ -3079,6 +3293,11 @@ vector_write_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3089,6 +3308,12 @@ vector_write_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf, * decreasing_fi_buf, negative_fi_buf, and zero_fi_buf as @@ -3158,6 +3383,11 @@ vector_write_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3289,6 +3519,7 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[4]; size_t sizes[4]; const void *bufs[4]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -3332,6 +3563,12 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Set the test file in a known state by writing zeros * to all bytes in the test file. Since we have already * tested this, do this via a vector write of zero_fi_buf. @@ -3351,6 +3588,11 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3361,6 +3603,12 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) For each rank, define base_index equal to: * * mpi_rank * INTS_PER_RANK @@ -3468,6 +3716,11 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3477,6 +3730,12 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 6) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf, * decreasing_fi_buf, negative_fi_buf, and zero_fi_buf as @@ -3619,6 +3878,11 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3723,6 +3987,7 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[(INTS_PER_RANK / 16) + 1]; size_t sizes[2]; const void *bufs[(INTS_PER_RANK / 16) + 1]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -3766,6 +4031,12 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire negative_fi_buf to * the file. */ @@ -3783,12 +4054,23 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) For each rank, define base_index equal to: * * mpi_rank * INTS_PER_RANK @@ -3830,6 +4112,11 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3839,6 +4126,12 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 6) On each rank, read the entire file into the read_fi_buf, * and compare against zero_fi_buf, and increasing_fi_buf * as appropriate. Report failure if any differences are @@ -3872,6 +4165,11 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } /* end if */ + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -3980,6 +4278,7 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[8]; size_t sizes[8]; const void *bufs[8]; + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -4023,6 +4322,12 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Set the test file in a known state by writing zeros * to all bytes in the test file. Since we have already * tested this, do this via a vector write of zero_fi_buf. @@ -4042,6 +4347,11 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -4052,6 +4362,12 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + if (pass) { base_index = mpi_rank * INTS_PER_RANK; @@ -4075,6 +4391,11 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -4084,6 +4405,12 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 6) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf, and zero_fi_buf as * appropriate. Report failure if any differences are @@ -4133,6 +4460,11 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -4231,9 +4563,9 @@ vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer uint32_t count = 0; size_t sizes[4]; H5FD_mem_t types[2]; - haddr_t *tt_addrs = NULL; /* For storing addrs */ const void **tt_bufs = NULL; /* For storing buf pointers */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -4288,6 +4620,12 @@ vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 2) Using rank zero, write the entire negative_fi_buf to * the file. */ @@ -4305,12 +4643,23 @@ vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* 3) Barrier */ MPI_Barrier(comm); if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 4) For each rank, define base_index equal to: * * mpi_rank * INTS_PER_RANK @@ -4357,6 +4706,11 @@ vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -4366,6 +4720,12 @@ vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* 6) On each rank, read the entire file into the read_fi_buf, * and compare against increasing_fi_buf * Report failure if any differences are detected. @@ -4390,6 +4750,11 @@ vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer } } /* end if */ + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (show_progress) fprintf(stdout, "%s: cp = %d, pass = %d.\n", fcn_name, cp++, pass); @@ -4650,6 +5015,7 @@ test_selection_io_read_verify(hid_t dxpl, int mpi_rank, hsize_t start[], hsize_t size_t bufsize; int i; int j; + bool api_ctx_pushed = false; /* Whether API context pushed */ bufsize = (hsize_t)(sel_dim0 * sel_dim1) * sizeof(int); if ((rbuf1 = malloc(bufsize)) == NULL) @@ -4671,6 +5037,12 @@ test_selection_io_read_verify(hid_t dxpl, int mpi_rank, hsize_t start[], hsize_t else rbufs[i] = rbufs[rbufcount - 1]; + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* Issue read call */ if (H5FDread_selection(lf, type, dxpl, count, mem_spaces, file_spaces, offsets, element_sizes, (void **)rbufs) < 0) @@ -4709,6 +5081,11 @@ test_selection_io_read_verify(hid_t dxpl, int mpi_rank, hsize_t start[], hsize_t return 0; error: + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (rbuf1) free(rbuf1); if (rbuf2) @@ -4727,6 +5104,7 @@ test_selection_io_write(hid_t dxpl, H5FD_t *lf, H5FD_mem_t type, uint32_t count, const void **bufs = NULL; /* Avoids cast/const warnings */ int i; int j; + bool api_ctx_pushed = false; /* Whether API context pushed */ if (NULL == (bufs = calloc(count, sizeof(void *)))) goto error; @@ -4739,6 +5117,12 @@ test_selection_io_write(hid_t dxpl, H5FD_t *lf, H5FD_mem_t type, uint32_t count, bufs[i] = wb[i]; } + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* Issue write call */ if (H5FDwrite_selection(lf, type, dxpl, count, mem_spaces, file_spaces, offsets, element_sizes, bufs) < 0) goto error; @@ -4749,6 +5133,11 @@ test_selection_io_write(hid_t dxpl, H5FD_t *lf, H5FD_mem_t type, uint32_t count, return 0; error: + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + if (bufs) free(bufs); return -1; @@ -5959,13 +6348,13 @@ test_selection_io_real(int mpi_rank, int mpi_size, H5FD_t *lf, hid_t dxpl) hid_t file_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* file dataspaces vector */ hsize_t dims1[1]; /* 1d dimension sizes */ hsize_t dims2[2]; /* 2d dimension sizes */ - H5FD_mem_t type; /* File type */ haddr_t addrs[2]; /* File allocation address */ size_t element_sizes[2] = {sizeof(int), sizeof(int)}; /* Element size */ size_t bufsize; /* Buffer size */ int i; int j; + bool api_ctx_pushed = false; /* Whether API context pushed */ curr_nerrors = nerrors; @@ -6036,9 +6425,20 @@ test_selection_io_real(int mpi_rank, int mpi_size, H5FD_t *lf, hid_t dxpl) /* Loop over memory types */ for (type = 1; type < H5FD_MEM_NTYPES; type++) { + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + addrs[0] = H5FDalloc(lf, type, H5P_DEFAULT, (sizeof(int) * (hsize_t)sel_dim0 * (hsize_t)sel_dim1)); addrs[1] = H5FDalloc(lf, type, H5P_DEFAULT, (sizeof(int) * (hsize_t)sel_dim0 * (hsize_t)sel_dim1)); + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + test_selection_io_types_1d(mpi_rank, mpi_size, lf, dxpl, type, addrs, element_sizes, mem_spaces, file_spaces, dims1); test_selection_io_types_2d(mpi_rank, mpi_size, lf, dxpl, type, addrs, element_sizes, mem_spaces, @@ -6089,12 +6489,12 @@ test_selection_io(int mpi_rank, int mpi_size) hid_t fapl = H5I_INVALID_HID; /* File access property list */ char filename[1024]; /* Test file name */ unsigned flags = 0; /* File access flags */ - unsigned collective; /* Types of I/O for testing */ hid_t dxpl = H5I_INVALID_HID; /* Dataset transfer property list */ hid_t def_dxpl = H5I_INVALID_HID; /* dxpl: independent access */ hid_t col_xfer_dxpl = H5I_INVALID_HID; /* dxpl: collective access with collective I/O */ hid_t ind_io_dxpl = H5I_INVALID_HID; /* dxpl: collective access with individual I/O */ + bool api_ctx_pushed = false; /* Whether API context pushed */ /* If I use fapl in this call, I got an environment printout */ h5_fixname(SELECT_FNAME, H5P_DEFAULT, filename, sizeof(filename)); @@ -6105,12 +6505,23 @@ test_selection_io(int mpi_rank, int mpi_size) if (H5Pset_fapl_mpio(fapl, comm, info) < 0) P_TEST_ERROR; + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* Create file */ flags = H5F_ACC_RDWR | H5F_ACC_CREAT | H5F_ACC_TRUNC; if (NULL == (lf = H5FDopen(filename, flags, fapl, HADDR_UNDEF))) P_TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* Default dxpl which will be H5FD_MPIO_INDEPENDENT by default */ def_dxpl = H5Pcreate(H5P_DATASET_XFER); @@ -6148,10 +6559,21 @@ test_selection_io(int mpi_rank, int mpi_size) test_selection_io_real(mpi_rank, mpi_size, lf, dxpl); } + /* Push API context */ + if (H5CX_push() < 0) + pass = FALSE; + else + api_ctx_pushed = true; + /* Close file */ if (H5FDclose(lf) < 0) P_TEST_ERROR; + /* Pop API context */ + if (api_ctx_pushed) + H5CX_pop(false); + api_ctx_pushed = false; + /* Close the fapl */ if (H5Pclose(fapl) < 0) P_TEST_ERROR; diff --git a/utils/mirror_vfd/mirror_writer.c b/utils/mirror_vfd/mirror_writer.c index f1569657deb..f91b00c8f5d 100644 --- a/utils/mirror_vfd/mirror_writer.c +++ b/utils/mirror_vfd/mirror_writer.c @@ -220,12 +220,19 @@ session_init(struct mirror_writer_opts *opts) static int session_stop(struct mirror_session *session) { + bool api_ctx_pushed = false; /* Whether API context pushed */ int ret_value = 0; assert(session && (session->magic == MW_SESSION_MAGIC)); mirror_log(session->loginfo, V_INFO, "session_stop()"); + /* Push API context */ + if (H5CX_push() < 0) + ret_value--; + else + api_ctx_pushed = true; + /* Close HDF5 file if it is still open (probably in error) */ if (session->file) { mirror_log(session->loginfo, V_WARN, "HDF5 file still open at cleanup"); @@ -248,6 +255,9 @@ session_stop(struct mirror_session *session) session->magic++; free(session); + if (api_ctx_pushed) + H5CX_pop(false); + return ret_value; } /* end session_stop() */ @@ -396,11 +406,18 @@ reply_error(struct mirror_session *session, const char *msg) static int do_close(struct mirror_session *session) { + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC)); mirror_log(session->loginfo, V_INFO, "do_close()"); + /* Push API context */ + if (H5CX_push() < 0) + return -1; + else + api_ctx_pushed = true; + if (NULL == session->file) { mirror_log(session->loginfo, V_ERR, "no file to close!"); reply_error(session, "no file to close"); @@ -420,6 +437,9 @@ do_close(struct mirror_session *session) return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; } /* end do_close() */ @@ -436,11 +456,18 @@ do_lock(struct mirror_session *session, const unsigned char *xmit_buf) { size_t decode_ret = 0; H5FD_mirror_xmit_lock_t xmit_lock; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf); mirror_log(session->loginfo, V_INFO, "do_lock()"); + /* Push API context */ + if (H5CX_push() < 0) + return -1; + else + api_ctx_pushed = true; + decode_ret = H5FD_mirror_xmit_decode_lock(&xmit_lock, xmit_buf); if (H5FD_MIRROR_XMIT_LOCK_SIZE != decode_ret) { mirror_log(session->loginfo, V_ERR, "can't decode set-eoa xmit"); @@ -467,6 +494,9 @@ do_lock(struct mirror_session *session, const unsigned char *xmit_buf) return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; } /* end do_lock() */ @@ -484,6 +514,7 @@ do_open(struct mirror_session *session, const H5FD_mirror_xmit_open_t *xmit_open hid_t fapl_id = H5I_INVALID_HID; unsigned _flags = 0; haddr_t _maxaddr = HADDR_UNDEF; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_open && true == H5FD_mirror_xmit_is_open(xmit_open)); @@ -533,6 +564,12 @@ do_open(struct mirror_session *session, const H5FD_mirror_xmit_open_t *xmit_open goto error; } + /* Push API context */ + if (H5CX_push() < 0) + goto error; + else + api_ctx_pushed = true; + session->file = H5FDopen(xmit_open->filename, _flags, fapl_id, _maxaddr); if (NULL == session->file) { mirror_log(session->loginfo, V_ERR, "H5FDopen()"); @@ -553,9 +590,15 @@ do_open(struct mirror_session *session, const H5FD_mirror_xmit_open_t *xmit_open return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; error: + if (api_ctx_pushed) + H5CX_pop(false); + if (fapl_id > 0) { H5E_BEGIN_TRY { @@ -579,11 +622,18 @@ do_set_eoa(struct mirror_session *session, const unsigned char *xmit_buf) { size_t decode_ret = 0; H5FD_mirror_xmit_eoa_t xmit_seoa; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf); mirror_log(session->loginfo, V_INFO, "do_set_eoa()"); + /* Push API context */ + if (H5CX_push() < 0) + return -1; + else + api_ctx_pushed = true; + decode_ret = H5FD_mirror_xmit_decode_set_eoa(&xmit_seoa, xmit_buf); if (H5FD_MIRROR_XMIT_EOA_SIZE != decode_ret) { mirror_log(session->loginfo, V_ERR, "can't decode set-eoa xmit"); @@ -611,6 +661,9 @@ do_set_eoa(struct mirror_session *session, const unsigned char *xmit_buf) return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; } /* end do_set_eoa() */ @@ -625,11 +678,18 @@ do_set_eoa(struct mirror_session *session, const unsigned char *xmit_buf) static int do_truncate(struct mirror_session *session) { + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC)); mirror_log(session->loginfo, V_INFO, "do_truncate()"); + /* Push API context */ + if (H5CX_push() < 0) + return -1; + else + api_ctx_pushed = true; + /* default DXPL ID (0), 0 for "false" closing -- both probably unused */ if (H5FDtruncate(session->file, 0, 0) < 0) { mirror_log(session->loginfo, V_ERR, "H5FDtruncate()"); @@ -643,6 +703,9 @@ do_truncate(struct mirror_session *session) return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; } /* end do_truncate() */ @@ -657,10 +720,18 @@ do_truncate(struct mirror_session *session) static int do_unlock(struct mirror_session *session) { + bool api_ctx_pushed = false; /* Whether API context pushed */ + assert(session && (session->magic == MW_SESSION_MAGIC)); mirror_log(session->loginfo, V_INFO, "do_unlock()"); + /* Push API context */ + if (H5CX_push() < 0) + return -1; + else + api_ctx_pushed = true; + if (H5FDunlock(session->file) < 0) { mirror_log(session->loginfo, V_ERR, "H5FDunlock()"); reply_error(session, "remote H5FDunlock() failure"); @@ -673,6 +744,9 @@ do_unlock(struct mirror_session *session) return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; } /* end do_unlock() */ @@ -700,6 +774,7 @@ do_write(struct mirror_session *session, const unsigned char *xmit_buf) char *buf = NULL; ssize_t nbytes_in_packet = 0; H5FD_mirror_xmit_write_t xmit_write; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf); @@ -745,6 +820,12 @@ do_write(struct mirror_session *session, const unsigned char *xmit_buf) mirror_log(session->loginfo, V_INFO, "to write %zu bytes at %zu", xmit_write.size, addr); + /* Push API context */ + if (H5CX_push() < 0) + return -1; + else + api_ctx_pushed = true; + /* The given write may be: * 1. larger than the allowed single buffer size * 2. larger than the native size_t of this system @@ -790,6 +871,9 @@ do_write(struct mirror_session *session, const unsigned char *xmit_buf) return -1; } + if (api_ctx_pushed) + H5CX_pop(false); + return 0; } /* end do_write() */ From 488d02e476dc28a5fb8053a3d4c337118056ef95 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 00:05:26 +0000 Subject: [PATCH 002/522] Committing clang-format changes --- src/H5CS.c | 9 +- src/H5CSprivate.h | 3 - src/H5CX.c | 4 +- src/H5E.c | 82 ++++++------ src/H5Epkg.h | 4 +- src/H5FDsubfiling/H5FDioc_threads.c | 2 +- .../mercury/src/util/mercury_thread.c | 1 - .../mercury/src/util/mercury_thread.h | 2 +- .../mercury/src/util/mercury_thread_mutex.c | 3 +- .../mercury/src/util/mercury_util_error.h | 4 +- src/H5TS.c | 29 ++-- src/H5TSbarrier.c | 54 ++++---- src/H5TScond.c | 13 +- src/H5TSexlock.c | 85 ++++++------ src/H5TSint.c | 84 ++++++------ src/H5TSkey.c | 46 +++---- src/H5TSmutex.c | 15 +-- src/H5TSpkg.h | 52 ++++---- src/H5TSprivate.h | 45 ++++--- src/H5TSpthread.c | 111 ++++++++-------- src/H5TSrwlock.c | 13 +- src/H5TStest.c | 6 +- src/H5TSthread.c | 13 +- src/H5TSwin.c | 38 ++---- src/H5private.h | 6 +- test/onion.c | 48 ++++--- test/ttsafe.c | 12 +- test/ttsafe_develop.c | 35 +++-- test/ttsafe_error.c | 8 +- test/ttsafe_rec_rw_lock.c | 119 +++++++++-------- test/ttsafe_thread_id.c | 24 ++-- test/vfd.c | 32 ++--- testpar/t_vfd.c | 124 +++++++++--------- utils/mirror_vfd/mirror_writer.c | 26 ++-- 34 files changed, 537 insertions(+), 615 deletions(-) diff --git a/src/H5CS.c b/src/H5CS.c index 246ca3c0c4d..13ef69e4b7c 100644 --- a/src/H5CS.c +++ b/src/H5CS.c @@ -33,7 +33,6 @@ #define H5CS_MIN_NSLOTS 16 /* Minimum number of records in an function stack */ - /*------------------------------------------------------------------------- * Function: H5CS_print_stack * @@ -144,7 +143,7 @@ H5CS_pop(void) * and are not allocated, so there's no need to free them. */ free(fstack->rec); - fstack->rec = NULL; + fstack->rec = NULL; fstack->nalloc = 0; } /* end if */ @@ -163,9 +162,9 @@ H5CS_pop(void) H5CS_t * H5CS_copy_stack(void) { - H5CS_t *old_stack = H5CX_get_fstack(); /* Get function stack from API context */ - H5CS_t *new_stack; /* New function stack, for copy */ - H5CS_t *ret_value = NULL; /* Return value */ + H5CS_t *old_stack = H5CX_get_fstack(); /* Get function stack from API context */ + H5CS_t *new_stack; /* New function stack, for copy */ + H5CS_t *ret_value = NULL; /* Return value */ /* Don't push this function on the function stack... :-) */ FUNC_ENTER_NOAPI_NOFS diff --git a/src/H5CSprivate.h b/src/H5CSprivate.h index e8bb65b8889..60b70817946 100644 --- a/src/H5CSprivate.h +++ b/src/H5CSprivate.h @@ -23,7 +23,6 @@ /* Library Private Macros */ /**************************/ - /****************************/ /* Library Private Typedefs */ /****************************/ @@ -35,12 +34,10 @@ typedef struct H5CS_t { const char **rec; /* Array of function records */ } H5CS_t; - /*****************************/ /* Library-private Variables */ /*****************************/ - /***************************************/ /* Library-private Function Prototypes */ /***************************************/ diff --git a/src/H5CX.c b/src/H5CX.c index a9a50b50340..95d247318b6 100644 --- a/src/H5CX.c +++ b/src/H5CX.c @@ -201,7 +201,7 @@ typedef struct H5CX_t { #ifdef H5_HAVE_CODESTACK /* Internal: Function stack info */ - H5CS_t fstack; /* Current function stack for an API operation */ + H5CS_t fstack; /* Current function stack for an API operation */ #endif #ifdef H5_HAVE_PARALLEL @@ -1692,7 +1692,7 @@ H5CX_get_ring(void) H5CS_t * H5CX_get_fstack(void) { - H5CX_node_t **head = NULL; /* Pointer to head of API context list */ + H5CX_node_t **head = NULL; /* Pointer to head of API context list */ FUNC_ENTER_NOAPI_NOERR_NOFS diff --git a/src/H5E.c b/src/H5E.c index c31a16b741a..517529cdad0 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -92,57 +92,57 @@ static herr_t H5E__append_stack(H5E_t *dst_estack, const H5E_t *src_stack); /* Default value to initialize R/W locks */ static const H5E_t H5E_err_stack_def = { - 0, /* nused */ - { /*slot[] */ - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, - {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL} - }, - - /* H5E_auto_op_t */ + 0, /* nused */ + { /*slot[] */ + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}, + {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}}, + +/* H5E_auto_op_t */ #ifndef H5_NO_DEPRECATED_SYMBOLS #ifdef H5_USE_16_API_DEFAULT - {1, TRUE, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2}, + {1, TRUE, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2, (H5E_auto1_t)H5Eprint1, + (H5E_auto2_t)H5E__print2}, #else /* H5_USE_16_API */ - {2, TRUE, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2}, + {2, TRUE, (H5E_auto1_t)H5Eprint1, (H5E_auto2_t)H5E__print2, (H5E_auto1_t)H5Eprint1, + (H5E_auto2_t)H5E__print2}, #endif /* H5_USE_16_API_DEFAULT */ #else /* H5_NO_DEPRECATED_SYMBOLS */ {(H5E_auto2_t)H5E__print2}, #endif /* H5_NO_DEPRECATED_SYMBOLS */ - NULL /* auto_data */ + NULL /* auto_data */ }; - /*****************************/ /* Library Private Variables */ /*****************************/ diff --git a/src/H5Epkg.h b/src/H5Epkg.h index 0cdbeb0249e..611d0f5a540 100644 --- a/src/H5Epkg.h +++ b/src/H5Epkg.h @@ -122,8 +122,8 @@ H5_DLLVAR H5E_t H5E_stack_g[1]; /******************************/ /* Package Private Prototypes */ /******************************/ -H5_DLL herr_t H5E__term_deprec_interface(void); -H5_DLL void H5E__set_default_auto(H5E_t *stk); +H5_DLL herr_t H5E__term_deprec_interface(void); +H5_DLL void H5E__set_default_auto(H5E_t *stk); H5_DLL herr_t H5E__push_stack(H5E_t *estack, const char *file, const char *func, unsigned line, hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc); H5_DLL ssize_t H5E__get_msg(const H5E_msg_t *msg_ptr, H5E_type_t *type, char *msg, size_t size); diff --git a/src/H5FDsubfiling/H5FDioc_threads.c b/src/H5FDsubfiling/H5FDioc_threads.c index 65147f97438..37b5f78d63b 100644 --- a/src/H5FDsubfiling/H5FDioc_threads.c +++ b/src/H5FDsubfiling/H5FDioc_threads.c @@ -1403,7 +1403,7 @@ ioc_io_queue_dispatch_eligible_entries(ioc_data_t *ioc_data, bool try_lock) assert(ioc_data->io_queue.magic == H5FD_IOC__IO_Q_MAGIC); if (try_lock) { - bool acquired; + bool acquired; herr_t ret; ret = H5TS_mutex_try_lock(&ioc_data->io_queue.q_mutex, &acquired); diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c index 34d0db7c917..cfbac49b984 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c @@ -111,4 +111,3 @@ hg_thread_key_delete(hg_thread_key_t key) return HG_UTIL_SUCCESS; } - diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h index a9ea1cb27c9..165ba483804 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h @@ -20,7 +20,7 @@ typedef HANDLE hg_thread_t; typedef LPTHREAD_START_ROUTINE hg_thread_func_t; typedef DWORD hg_thread_ret_t; #define HG_THREAD_RETURN_TYPE hg_thread_ret_t WINAPI -typedef DWORD hg_thread_key_t; +typedef DWORD hg_thread_key_t; #else #include typedef pthread_t hg_thread_t; diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c index d4a927bfecd..e47433d701d 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c @@ -23,8 +23,7 @@ hg_thread_mutex_init(hg_thread_mutex_t *mutex) int rc; rc = pthread_mutex_init(mutex, NULL); - HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutex_init() failed (%s)", - strerror(rc)); + HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutex_init() failed (%s)", strerror(rc)); done: #endif diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h b/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h index edf0485d4f9..06f0067ea44 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h @@ -15,7 +15,7 @@ /* Check for cond, set ret to err_val and goto label */ #define HG_UTIL_CHECK_ERROR(cond, label, ret, err_val, ...) \ do { \ - if (H5_UNLIKELY(cond)) { \ + if (H5_UNLIKELY(cond)) { \ ret = err_val; \ goto label; \ } \ @@ -23,7 +23,7 @@ #define HG_UTIL_CHECK_ERROR_NORET(cond, label, ...) \ do { \ - if (H5_UNLIKELY(cond)) { \ + if (H5_UNLIKELY(cond)) { \ goto label; \ } \ } while (0) diff --git a/src/H5TS.c b/src/H5TS.c index d4cec185992..3f4805f9dda 100644 --- a/src/H5TS.c +++ b/src/H5TS.c @@ -31,9 +31,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -41,17 +41,14 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ @@ -63,12 +60,10 @@ H5TS_api_info_t H5TS_api_info_p; /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ - /*-------------------------------------------------------------------------- * Function: H5TSmutex_acquire * @@ -82,12 +77,11 @@ H5TS_api_info_t H5TS_api_info_p; *-------------------------------------------------------------------------- */ herr_t -H5TSmutex_acquire(unsigned lock_count, bool *acquired) -{ +H5TSmutex_acquire(unsigned lock_count, bool *acquired){ FUNC_ENTER_API_NAMECHECK_ONLY - FUNC_LEAVE_API_NAMECHECK_ONLY(H5TS__mutex_acquire(lock_count, acquired)) -} /* end H5TSmutex_acquire() */ + FUNC_LEAVE_API_NAMECHECK_ONLY(H5TS__mutex_acquire(lock_count, acquired))} +/* end H5TSmutex_acquire() */ /*-------------------------------------------------------------------------- * Function: H5TSmutex_get_attempt_count @@ -101,11 +95,10 @@ H5TSmutex_acquire(unsigned lock_count, bool *acquired) * *-------------------------------------------------------------------------- */ -herr_t -H5TSmutex_get_attempt_count(unsigned *count) +herr_t H5TSmutex_get_attempt_count(unsigned *count) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_API_NAMECHECK_ONLY @@ -118,8 +111,8 @@ H5TSmutex_get_attempt_count(unsigned *count) done: /* Release the lock */ - if(have_mutex) - if(H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.attempt_mutex) < 0)) + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.attempt_mutex) < 0)) ret_value = FAIL; FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value) diff --git a/src/H5TSbarrier.c b/src/H5TSbarrier.c index b2f0226ec49..76e8fb0af62 100644 --- a/src/H5TSbarrier.c +++ b/src/H5TSbarrier.c @@ -29,9 +29,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -41,36 +41,32 @@ #ifndef H5_HAVE_PTHREAD_BARRIER /* Barrier initialization macro */ -#define H5TS_BARRIER_INIT { \ - PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ - PTHREAD_COND_INITIALIZER, /* cv */ \ - 0, /* count */ \ - 0, /* entered */ \ - 0 /* threshold */ \ - } +#define H5TS_BARRIER_INIT \ + { \ + PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ + PTHREAD_COND_INITIALIZER, /* cv */ \ + 0, /* count */ \ + 0, /* entered */ \ + 0 /* threshold */ \ + } #endif - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ @@ -99,7 +95,7 @@ H5TS__barrier_init(H5TS_barrier_t *barrier, uint64_t count) if (H5_UNLIKELY(NULL == barrier || 0 == count)) HGOTO_DONE(FAIL); - /* Initialize the barrier */ + /* Initialize the barrier */ #ifdef H5_HAVE_PTHREAD_BARRIER if (pthread_barrier_init(barrier, NULL, count)) HGOTO_DONE(FAIL); @@ -150,23 +146,23 @@ H5TS__barrier_wait(H5TS_barrier_t *barrier) barrier->entered++; if (barrier->entered < barrier->threshold) { - if (H5_UNLIKELY(H5TS_cond_wait(&barrier->cv, &barrier->mutex))) - HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_cond_wait(&barrier->cv, &barrier->mutex))) + HGOTO_DONE(FAIL); } else { - if (H5_UNLIKELY(H5TS_cond_broadcast(&barrier->cv))) - HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_cond_broadcast(&barrier->cv))) + HGOTO_DONE(FAIL); - /* Increment threshold count of threads for next barrier */ - barrier->threshold += barrier->count; + /* Increment threshold count of threads for next barrier */ + barrier->threshold += barrier->count; } #endif done: #ifndef H5_HAVE_PTHREAD_BARRIER - if(have_mutex) - if(H5_UNLIKELY(H5TS_mutex_unlock(&barrier->mutex))) - ret_value = FAIL; + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&barrier->mutex))) + ret_value = FAIL; #endif FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -203,12 +199,12 @@ H5TS__barrier_destroy(H5TS_barrier_t *barrier) /* Check for barrier still in use */ if (H5_UNLIKELY((barrier->threshold - barrier->entered) != barrier->count)) { - (void)H5TS_mutex_unlock(&barrier->mutex); + (void)H5TS_mutex_unlock(&barrier->mutex); HGOTO_DONE(FAIL); } /* Release the barrier's mutex */ - if(H5_UNLIKELY(H5TS_mutex_unlock(&barrier->mutex))) + if (H5_UNLIKELY(H5TS_mutex_unlock(&barrier->mutex))) HGOTO_DONE(FAIL); /* Call the appropriate pthread destroy routines. We are committed @@ -216,9 +212,9 @@ H5TS__barrier_destroy(H5TS_barrier_t *barrier) * along the way. */ if (H5_UNLIKELY(H5TS_mutex_destroy(&barrier->mutex))) - ret_value = FAIL; + ret_value = FAIL; if (H5_UNLIKELY(H5TS_cond_destroy(&barrier->cv))) - ret_value = FAIL; + ret_value = FAIL; #endif done: diff --git a/src/H5TScond.c b/src/H5TScond.c index b0ed28be47f..06f73e45aad 100644 --- a/src/H5TScond.c +++ b/src/H5TScond.c @@ -29,9 +29,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -39,33 +39,26 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ - - #ifdef H5_HAVE_WIN_THREADS /*------------------------------------------------------------------------- * Function: H5TS_cond_init diff --git a/src/H5TSexlock.c b/src/H5TSexlock.c index bac81136529..51b859a4d4d 100644 --- a/src/H5TSexlock.c +++ b/src/H5TSexlock.c @@ -31,9 +31,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -43,44 +43,41 @@ /* Excl lock initialization macro */ #ifdef H5_HAVE_PTHREAD_H -#define H5TS_EX_LOCK_INIT { \ - H5TS_MUTEX_INITIALIZER, /* mutex */ \ - H5TS_COND_INITIALIZER, /* cond_var */ \ - 0, /* owner_thread */ \ - 0, /* lock_count */ \ - false, /* disable_cancel */ \ - 0 /* previous_state */ \ - } +#define H5TS_EX_LOCK_INIT \ + { \ + H5TS_MUTEX_INITIALIZER, /* mutex */ \ + H5TS_COND_INITIALIZER, /* cond_var */ \ + 0, /* owner_thread */ \ + 0, /* lock_count */ \ + false, /* disable_cancel */ \ + 0 /* previous_state */ \ + } #else -#define H5TS_EXL_LOCK_INIT { \ - H5TS_MUTEX_INITIALIZER, /* mutex */ \ - H5TS_COND_INITIALIZER, /* cond_var */ \ - 0, /* owner_thread */ \ - 0 /* lock_count */ \ - } +#define H5TS_EXL_LOCK_INIT \ + { \ + H5TS_MUTEX_INITIALIZER, /* mutex */ \ + H5TS_COND_INITIALIZER, /* cond_var */ \ + 0, /* owner_thread */ \ + 0 /* lock_count */ \ + } #endif - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ @@ -88,7 +85,6 @@ /* Default value to initialize exclusive locks */ static const H5TS_ex_lock_t H5TS_ex_lock_def = H5TS_EX_LOCK_INIT; - /*-------------------------------------------------------------------------- * Function: H5TS__ex_lock_init * @@ -135,8 +131,8 @@ herr_t H5TS__ex_lock(H5TS_ex_lock_t *lock) { H5TS_thread_t my_thread_id = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -168,8 +164,8 @@ H5TS__ex_lock(H5TS_ex_lock_t *lock) } done: - if(have_mutex) - if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) ret_value = FAIL; FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -189,9 +185,9 @@ H5TS__ex_lock(H5TS_ex_lock_t *lock) herr_t H5TS__ex_acquire(H5TS_ex_lock_t *lock, unsigned lock_count, bool *acquired) { - bool have_mutex = false; + bool have_mutex = false; H5TS_thread_t my_thread_id = H5TS_thread_self(); - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY @@ -220,8 +216,8 @@ H5TS__ex_acquire(H5TS_ex_lock_t *lock, unsigned lock_count, bool *acquired) done: /* Release the mutex, if acquired */ - if(have_mutex) - if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) ret_value = FAIL; FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -240,8 +236,8 @@ H5TS__ex_acquire(H5TS_ex_lock_t *lock, unsigned lock_count, bool *acquired) herr_t H5TS__ex_release(H5TS_ex_lock_t *lock, unsigned int *lock_count) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -251,7 +247,7 @@ H5TS__ex_release(H5TS_ex_lock_t *lock, unsigned int *lock_count) have_mutex = true; /* Reset the lock count for this thread */ - *lock_count = lock->lock_count; + *lock_count = lock->lock_count; lock->lock_count = 0; /* Signal the condition variable, to wake any thread waiting on the lock */ @@ -279,8 +275,8 @@ H5TS__ex_release(H5TS_ex_lock_t *lock, unsigned int *lock_count) herr_t H5TS__ex_unlock(H5TS_ex_lock_t *lock) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -308,8 +304,8 @@ H5TS__ex_unlock(H5TS_ex_lock_t *lock) } done: - if(have_mutex) - if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) ret_value = FAIL; FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -329,8 +325,8 @@ H5TS__ex_unlock(H5TS_ex_lock_t *lock) herr_t H5TS__ex_lock_destroy(H5TS_ex_lock_t *lock) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY @@ -356,17 +352,16 @@ H5TS__ex_lock_destroy(H5TS_ex_lock_t *lock) * along the way. */ if (H5_UNLIKELY(H5TS_mutex_destroy(&lock->mutex))) - ret_value = FAIL; + ret_value = FAIL; if (H5_UNLIKELY(H5TS_cond_destroy(&lock->cond_var))) - ret_value = FAIL; + ret_value = FAIL; done: - if(have_mutex) - if(H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) + if (have_mutex) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex))) ret_value = FAIL; FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS__ex_lock_destroy() */ #endif /* H5_HAVE_THREADSAFE */ - diff --git a/src/H5TSint.c b/src/H5TSint.c index 7d39fdab027..fd02ff3b4cd 100644 --- a/src/H5TSint.c +++ b/src/H5TSint.c @@ -43,31 +43,28 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ /* Per-thread info */ typedef struct H5TS_thread_info_t { - uint64_t id; /* Unique ID for each thread */ + uint64_t id; /* Unique ID for each thread */ struct H5CX_node_t *api_ctx_node_ptr; /* Pointer to an API context node */ - H5E_t err_stack; /* Error stack */ + H5E_t err_stack; /* Error stack */ } H5TS_thread_info_t; /* An H5TS_tinfo_node_t is a thread info that is available for reuse */ typedef struct H5TS_tinfo_node_t { struct H5TS_tinfo_node_t *next; - H5TS_thread_info_t info; + H5TS_thread_info_t info; } H5TS_tinfo_node_t; - /********************/ /* Local Prototypes */ /********************/ static H5TS_tinfo_node_t *H5TS__tinfo_create(void); - /*********************/ /* Package Variables */ /*********************/ @@ -75,12 +72,10 @@ static H5TS_tinfo_node_t *H5TS__tinfo_create(void); /* Per-thread info */ H5TS_key_t H5TS_thrd_info_key_g; - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ @@ -89,19 +84,18 @@ H5TS_key_t H5TS_thrd_info_key_g; #ifdef H5_HAVE_WIN_THREADS static H5TS_once_t H5TS_first_init_s; #else -static H5TS_once_t H5TS_first_init_s = PTHREAD_ONCE_INIT; +static H5TS_once_t H5TS_first_init_s = PTHREAD_ONCE_INIT; #endif - /* Pointer to first free thread info record or NULL. */ static H5TS_tinfo_node_t *H5TS_tinfo_next_free_s = NULL; -static uint64_t H5TS_next_thrd_id_s = 0; +static uint64_t H5TS_next_thrd_id_s = 0; /* Mutex for access to H5TS_tinfo_next_free_s and H5TS_next_thrd_id_s */ #ifdef H5_HAVE_WIN_THREADS static H5TS_mutex_t H5TS_tinfo_mtx_s; #else -static H5TS_mutex_t H5TS_tinfo_mtx_s = PTHREAD_MUTEX_INITIALIZER; +static H5TS_mutex_t H5TS_tinfo_mtx_s = PTHREAD_MUTEX_INITIALIZER; #endif /*------------------------------------------------------------------------- @@ -288,7 +282,7 @@ H5TS__tinfo_init(void) ret_value = FAIL; #endif - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS__tinfo_init() */ /*-------------------------------------------------------------------------- @@ -303,7 +297,7 @@ H5TS__tinfo_init(void) static H5TS_tinfo_node_t * H5TS__tinfo_create(void) { - uint64_t new_id; + uint64_t new_id; H5TS_tinfo_node_t *tinfo_node; H5TS_tinfo_node_t *ret_value; @@ -317,7 +311,7 @@ H5TS__tinfo_create(void) /* Reuse an info struct that's on the free list if possible */ if (NULL != (tinfo_node = H5TS_tinfo_next_free_s)) - H5TS_tinfo_next_free_s = tinfo_node->next; + H5TS_tinfo_next_free_s = tinfo_node->next; /* Always use unique ID value for each thread, even when recycling a * H5TS_tinfo_node_t from the free list. @@ -331,29 +325,29 @@ H5TS__tinfo_create(void) /* If a new info record is needed, allocate it */ if (NULL == tinfo_node) { - if (H5_UNLIKELY(NULL == (tinfo_node = H5MM_malloc(sizeof(*tinfo_node))))) - HGOTO_DONE(NULL); - tinfo_node->next = NULL; + if (H5_UNLIKELY(NULL == (tinfo_node = H5MM_malloc(sizeof(*tinfo_node))))) + HGOTO_DONE(NULL); + tinfo_node->next = NULL; } /* Reset thread info struct */ memset(tinfo_node, 0, sizeof(*tinfo_node)); /* Set up non-zero per-thread info */ - tinfo_node->info.id = new_id; /* ID */ + tinfo_node->info.id = new_id; /* ID */ H5E__set_default_auto(&tinfo_node->info.err_stack); /* Error stack */ /* Set a thread-local pointer to the thread's info record */ if (H5_UNLIKELY(H5TS__set_thread_local_value(H5TS_thrd_info_key_g, tinfo_node))) { - H5TS__tinfo_destroy(tinfo_node); - HGOTO_DONE(NULL); + H5TS__tinfo_destroy(tinfo_node); + HGOTO_DONE(NULL); } /* Success */ ret_value = tinfo_node; done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /*-------------------------------------------------------------------------- @@ -378,21 +372,21 @@ uint64_t H5TS_thread_id(void) { H5TS_tinfo_node_t *tinfo_node; - uint64_t ret_value; + uint64_t ret_value; FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) - /* Create thread info for this thread */ - if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) - HGOTO_DONE(0); + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(0); /* Set return value */ ret_value = tinfo_node->info.id; done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS_thread_id() */ /*-------------------------------------------------------------------------- @@ -409,22 +403,22 @@ H5TS_thread_id(void) struct H5CX_node_t ** H5TS_get_api_ctx_ptr(void) { - H5TS_tinfo_node_t *tinfo_node; + H5TS_tinfo_node_t *tinfo_node; struct H5CX_node_t **ret_value; FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) - /* Create thread info for this thread */ - if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) - HGOTO_DONE(NULL); + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(NULL); /* Set return value */ ret_value = &tinfo_node->info.api_ctx_node_ptr; done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS_get_api_ctx_ptr() */ /*-------------------------------------------------------------------------- @@ -442,21 +436,21 @@ H5E_t * H5TS_get_err_stack(void) { H5TS_tinfo_node_t *tinfo_node; - H5E_t *ret_value; + H5E_t *ret_value; FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) - /* Create thread info for this thread */ - if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) - HGOTO_DONE(NULL); + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(NULL); /* Set return value */ ret_value = &tinfo_node->info.err_stack; done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS_get_err_stack() */ /*-------------------------------------------------------------------------- @@ -480,11 +474,11 @@ H5TS__tinfo_destroy(void *_tinfo_node) FUNC_ENTER_PACKAGE_NAMECHECK_ONLY if (tinfo_node) { - /* Add thread info node to the free list */ - H5TS_mutex_lock(&H5TS_tinfo_mtx_s); - tinfo_node->next = H5TS_tinfo_next_free_s; - H5TS_tinfo_next_free_s = tinfo_node; - H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); + /* Add thread info node to the free list */ + H5TS_mutex_lock(&H5TS_tinfo_mtx_s); + tinfo_node->next = H5TS_tinfo_next_free_s; + H5TS_tinfo_next_free_s = tinfo_node; + H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); } FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY @@ -508,9 +502,9 @@ H5TS__tinfo_term(void) /* Release nodes on the free list */ H5TS_mutex_lock(&H5TS_tinfo_mtx_s); - while(H5TS_tinfo_next_free_s) { + while (H5TS_tinfo_next_free_s) { H5TS_tinfo_node_t *next = H5TS_tinfo_next_free_s->next; - H5MM_free(H5TS_tinfo_next_free_s); + H5MM_free(H5TS_tinfo_next_free_s); H5TS_tinfo_next_free_s = next; } H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); @@ -528,7 +522,7 @@ H5TS__tinfo_term(void) ret_value = FAIL; #endif - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS__tinfo_term() */ #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSkey.c b/src/H5TSkey.c index 4076c5e8dce..0a611356b53 100644 --- a/src/H5TSkey.c +++ b/src/H5TSkey.c @@ -29,9 +29,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -39,7 +39,6 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ @@ -51,9 +50,9 @@ struct _H5TS_win_kwd_node_t; /* Global list of all kwd's */ typedef struct _H5TS_win_kwd_node_t { - struct _H5TS_win_kwd_node_t *next; - H5TS_key_t key; - H5TS_key_destructor_func_t dtor; + struct _H5TS_win_kwd_node_t *next; + H5TS_key_t key; + H5TS_key_destructor_func_t dtor; struct _H5TS_win_kwd_tid_node_t *head_tid_node; } H5TS_win_kwd_node_t; @@ -61,13 +60,11 @@ typedef struct _H5TS_win_kwd_node_t { typedef struct _H5TS_win_kwd_tid_node_t { struct _H5TS_win_kwd_tid_node_t *next; struct _H5TS_win_kwd_tid_node_t *prev; - uint64_t tid; - H5TS_win_kwd_node_t *kwd_node; + uint64_t tid; + H5TS_win_kwd_node_t *kwd_node; } H5TS_win_kwd_tid_node_t; #endif - - /********************/ /* Local Prototypes */ /********************/ @@ -76,17 +73,14 @@ static herr_t H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor); static herr_t H5TS__set_kwd(H5TS_key_t key, const void *value); #endif - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ @@ -103,7 +97,6 @@ static H5TS_mutex_t H5TS_win_kwd_list_mtx_s; static H5TS_mutex_t H5TS_win_kwd_sublist_mtx_s; #endif - #ifdef H5_HAVE_WIN_THREADS /*-------------------------------------------------------------------------- * Function: H5TS__win_kwd_init @@ -129,7 +122,7 @@ H5TS__win_kwd_init(void) if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (H5TS_win_kwd_info_key_s = TlsAlloc()))) ret_value = FAIL; - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS__win_kwd_init() */ /*-------------------------------------------------------------------------- @@ -145,7 +138,7 @@ static herr_t H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor) { H5TS_win_kwd_node_t *kwd_node; - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -155,7 +148,7 @@ H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor) /* Create the kwd node for the key */ if (H5_UNLIKELY(NULL == (kwd_node = H5MM_malloc(sizeof(*kwd_node))))) HGOTO_DONE(FAIL); - kwd_node->key = key; + kwd_node->key = key; kwd_node->dtor = dtor; /* Acquire the lock for accessing the kwd list */ @@ -176,14 +169,14 @@ H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor) #endif /* Add the kwd node to the list */ - kwd_node->next = H5TS_win_kwd_list_head_s; + kwd_node->next = H5TS_win_kwd_list_head_s; H5TS_win_kwd_list_head_s = kwd_node; /* Release the lock for accessing the kwd list */ H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS__add_kwd() */ /*-------------------------------------------------------------------------- @@ -200,7 +193,7 @@ static herr_t H5TS__set_kwd(H5TS_key_t key, const void *value) { H5TS_win_kwd_node_t *kwd_node; - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -224,7 +217,7 @@ H5TS__set_kwd(H5TS_key_t key, const void *value) /* Check if this thread has been inserted already */ if (NULL != kwd_node) { H5TS_win_kwd_tid_node_t *kwd_tid_node; - uint64_t thread_id; + uint64_t thread_id; /* Get the ID for this thread */ if (H5_UNLIKELY(0 == (thread_id = H5TS_thread_id()))) @@ -248,7 +241,7 @@ H5TS__set_kwd(H5TS_key_t key, const void *value) /* Create the kwd tid node for the thread */ if (H5_UNLIKELY(NULL == (kwd_tid_node = H5MM_calloc(sizeof(*kwd_tid_node))))) HGOTO_DONE(FAIL); - kwd_tid_node->tid = thread_id; + kwd_tid_node->tid = thread_id; kwd_tid_node->kwd_node = kwd_node; /* Acquire both locks for accessing the kwd list & sub-lists */ @@ -268,11 +261,11 @@ H5TS__set_kwd(H5TS_key_t key, const void *value) } /* Add the kwd node to the list */ - kwd_node->next = H5TS_win_kwd_list_head_s; + kwd_node->next = H5TS_win_kwd_list_head_s; H5TS_win_kwd_list_head_s = kwd_node; done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) \ + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS__add_kwd() */ /*------------------------------------------------------------------------- @@ -336,9 +329,6 @@ H5TS_key_set_value(H5TS_key_t key, const void *value) FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS_key_create() */ - - #endif #endif /* H5_HAVE_THREADSAFE */ - diff --git a/src/H5TSmutex.c b/src/H5TSmutex.c index a6cc711e97b..92f4ecea220 100644 --- a/src/H5TSmutex.c +++ b/src/H5TSmutex.c @@ -29,9 +29,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -40,33 +40,26 @@ /****************/ #define H5TS_NO_THREAD_SAFETY_ANALYSIS H5_ATTR_THREAD_ANNOT(no_thread_safety_analysis) - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ - - #ifdef H5_HAVE_WIN_THREADS /*------------------------------------------------------------------------- * Function: H5TS_mutex_init @@ -222,7 +215,7 @@ H5TS_mutex_lock(H5TS_mutex_t *mutex) H5TS_NO_THREAD_SAFETY_ANALYSIS herr_t H5TS_mutex_try_lock(H5TS_mutex_t *mutex, bool *acquired) H5TS_NO_THREAD_SAFETY_ANALYSIS { - int rc; + int rc; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index 97d478b6587..9f5612e0d60 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -50,8 +50,8 @@ #else /* H5_HAVE_WIN_THREADS */ /* Scope Definitions (Pthreads only) */ -#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM -#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS +#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM +#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS /* Portability function aliases */ #define H5TS__get_thread_local_value(key) pthread_getspecific(key) @@ -64,7 +64,6 @@ #endif /* H5_HAVE_WIN_THREADS */ - /****************************/ /* Package Private Typedefs */ /****************************/ @@ -72,13 +71,13 @@ /* Portability wrappers */ #ifdef H5_HAVE_WIN_THREADS -typedef HANDLE H5TS_attr_t; -typedef INIT_ONCE H5TS_once_t; +typedef HANDLE H5TS_attr_t; +typedef INIT_ONCE H5TS_once_t; #else -typedef pthread_attr_t H5TS_attr_t; -typedef pthread_once_t H5TS_once_t; +typedef pthread_attr_t H5TS_attr_t; +typedef pthread_once_t H5TS_once_t; #endif /* H5_HAVE_WIN_THREADS */ @@ -92,8 +91,8 @@ typedef struct H5TS_ex_lock_t { /* Thread cancellability only supported with pthreads */ #ifdef H5_HAVE_PTHREAD_H /* Cancellation control */ - bool disable_cancel; - int previous_state; + bool disable_cancel; + int previous_state; #endif /* H5_HAVE_PTHREAD_H */ } H5TS_ex_lock_t; @@ -113,11 +112,11 @@ typedef struct H5TS_barrier_t { /* Info for the global API lock */ typedef struct H5TS_api_info_t { /* API lock */ - H5TS_ex_lock_t api_lock; + H5TS_ex_lock_t api_lock; /* Count of # of attempts to acquire API lock */ - H5TS_mutex_t attempt_mutex; /* mutex for attempt_lock_count */ - unsigned attempt_lock_count; + H5TS_mutex_t attempt_mutex; /* mutex for attempt_lock_count */ + unsigned attempt_lock_count; } H5TS_api_info_t; #ifdef H5_HAVE_WIN_THREADS @@ -267,27 +266,27 @@ typedef struct H5TS_rw_lock_stats_t { ******************************************************************************/ typedef enum { - UNUSED = 0, /* Lock is currently unused */ - WRITE, /* Lock is a recursive write lock */ - READ /* Lock is a recursive read lock */ + UNUSED = 0, /* Lock is currently unused */ + WRITE, /* Lock is a recursive write lock */ + READ /* Lock is a recursive read lock */ } H5TS_rw_lock_type_t; typedef struct H5TS_rw_lock_t { /* General fields */ - H5TS_mutex_t mutex; - H5TS_rw_lock_type_t lock_type; + H5TS_mutex_t mutex; + H5TS_rw_lock_type_t lock_type; /* Writer fields */ - H5TS_cond_t writers_cv; - H5TS_thread_t write_thread; - int32_t rec_write_lock_count; - int32_t waiting_writers_count; + H5TS_cond_t writers_cv; + H5TS_thread_t write_thread; + int32_t rec_write_lock_count; + int32_t waiting_writers_count; /* Reader fields */ - bool is_key_registered; - H5TS_cond_t readers_cv; - int32_t active_reader_threads; - H5TS_key_t rec_read_lock_count_key; + bool is_key_registered; + H5TS_cond_t readers_cv; + int32_t active_reader_threads; + H5TS_key_t rec_read_lock_count_key; #if H5TS_ENABLE_REC_RW_LOCK_STATS /* Stats */ @@ -297,7 +296,6 @@ typedef struct H5TS_rw_lock_t { #endif /* H5_HAVE_WIN_THREADS */ - /*****************************/ /* Package Private Variables */ /*****************************/ @@ -314,7 +312,7 @@ extern H5TS_key_t H5TS_thrd_info_key_g; herr_t H5TS__mutex_acquire(unsigned lock_count, bool *acquired); herr_t H5TS__mutex_release(unsigned *lock_count); herr_t H5TS__tinfo_init(void); -void H5TS__tinfo_destroy(void *tinfo_node); +void H5TS__tinfo_destroy(void *tinfo_node); herr_t H5TS__tinfo_term(void); #ifdef H5_HAVE_WIN_THREADS diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index 56da21d6f12..2072fd90fd4 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -30,19 +30,25 @@ /**************************/ /* Thread-safety sanity-checking annotations */ -#define H5TS_CAPABILITY(x) H5_ATTR_THREAD_ANNOT(capability(x)) -#define H5TS_ACQUIRE(...) H5_ATTR_THREAD_ANNOT(acquire_capability(__VA_ARGS__)) -#define H5TS_ACQUIRE_SHARED(...) H5_ATTR_THREAD_ANNOT(acquire_shared_capability(__VA_ARGS__)) -#define H5TS_RELEASE(...) H5_ATTR_THREAD_ANNOT(release_capability(__VA_ARGS__)) -#define H5TS_RELEASE_SHARED(...) H5_ATTR_THREAD_ANNOT(release_shared_capability(__VA_ARGS__)) -#define H5TS_TRY_ACQUIRE(...) H5_ATTR_THREAD_ANNOT(try_acquire_capability(__VA_ARGS__)) -#define H5TS_TRY_ACQUIRE_SHARED(...) H5_ATTR_THREAD_ANNOT(try_acquire_shared_capability(__VA_ARGS__)) +#define H5TS_CAPABILITY(x) H5_ATTR_THREAD_ANNOT(capability(x)) +#define H5TS_ACQUIRE(...) H5_ATTR_THREAD_ANNOT(acquire_capability(__VA_ARGS__)) +#define H5TS_ACQUIRE_SHARED(...) H5_ATTR_THREAD_ANNOT(acquire_shared_capability(__VA_ARGS__)) +#define H5TS_RELEASE(...) H5_ATTR_THREAD_ANNOT(release_capability(__VA_ARGS__)) +#define H5TS_RELEASE_SHARED(...) H5_ATTR_THREAD_ANNOT(release_shared_capability(__VA_ARGS__)) +#define H5TS_TRY_ACQUIRE(...) H5_ATTR_THREAD_ANNOT(try_acquire_capability(__VA_ARGS__)) +#define H5TS_TRY_ACQUIRE_SHARED(...) H5_ATTR_THREAD_ANNOT(try_acquire_shared_capability(__VA_ARGS__)) /* Static initialization values */ #ifdef H5_HAVE_WIN_THREADS -#define H5TS_KEY_INITIALIZER {NULL, 0, NULL} -#define H5TS_MUTEX_INITIALIZER {NULL} -#define H5TS_COND_INITIALIZER CONDITION_VARIABLE_INIT +#define H5TS_KEY_INITIALIZER \ + { \ + NULL, 0, NULL \ + } +#define H5TS_MUTEX_INITIALIZER \ + { \ + NULL \ + } +#define H5TS_COND_INITIALIZER CONDITION_VARIABLE_INIT #else #define H5TS_KEY_INITIALIZER (pthread_key_t)0 #define H5TS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -67,22 +73,21 @@ typedef void (*H5TS_key_destructor_func_t)(void *); /* Portability aliases */ #ifdef H5_HAVE_WIN_THREADS -typedef HANDLE H5TS_thread_t; -typedef DWORD H5TS_key_t; -typedef CRITICAL_SECTION H5TS_CAPABILITY("mutex") H5TS_mutex_t; -typedef CONDITION_VARIABLE H5TS_cond_t; +typedef HANDLE H5TS_thread_t; +typedef DWORD H5TS_key_t; +typedef CRITICAL_SECTION H5TS_CAPABILITY("mutex") H5TS_mutex_t; +typedef CONDITION_VARIABLE H5TS_cond_t; #else -typedef pthread_t H5TS_thread_t; -typedef pthread_key_t H5TS_key_t; +typedef pthread_t H5TS_thread_t; +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_cond_t H5TS_cond_t; #endif /*****************************/ /* Library-private Variables */ /*****************************/ - /***************************************/ /* Library-private Function Prototypes */ /***************************************/ @@ -99,9 +104,9 @@ H5_DLL herr_t H5TS_api_lock(void); H5_DLL herr_t H5TS_api_unlock(void); /* Retrieve per-thread info */ -H5_DLL uint64_t H5TS_thread_id(void); +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); +H5_DLL struct H5E_t *H5TS_get_err_stack(void); /* Mutex operations */ H5_DLL herr_t H5TS_mutex_init(H5TS_mutex_t *mutex); diff --git a/src/H5TSpthread.c b/src/H5TSpthread.c index a0c3352128c..be7213269a7 100644 --- a/src/H5TSpthread.c +++ b/src/H5TSpthread.c @@ -29,9 +29,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -43,35 +43,38 @@ /* R/W lock initialization macro */ #if H5TS_ENABLE_REC_RW_LOCK_STATS -#define H5TS_RW_LOCK_INIT { \ - PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ - (H5TS_rw_lock_type_t)UNUSED, /* lock_type */ \ - PTHREAD_COND_INITIALIZER, /* writers_cv */ \ - 0, /* write_thread */ \ - 0, /* rec_write_lock_count */ \ - 0, /* waiting_writers_count */ \ - false, /* is_key_registered */ \ - PTHREAD_COND_INITIALIZER, /* readers_cv */ \ - 0, /* active_reader_threads */ \ - (H5TS_key_t)0, /* rec_read_lock_count_key */ \ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* stats */ \ - } +#define H5TS_RW_LOCK_INIT \ + { \ + PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ + (H5TS_rw_lock_type_t)UNUSED, /* lock_type */ \ + PTHREAD_COND_INITIALIZER, /* writers_cv */ \ + 0, /* write_thread */ \ + 0, /* rec_write_lock_count */ \ + 0, /* waiting_writers_count */ \ + false, /* is_key_registered */ \ + PTHREAD_COND_INITIALIZER, /* readers_cv */ \ + 0, /* active_reader_threads */ \ + (H5TS_key_t)0, /* rec_read_lock_count_key */ \ + { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + } /* stats */ \ + } #else -#define H5TS_RW_LOCK_INIT { \ - PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ - (H5TS_rw_lock_type_t)UNUSED, /* lock_type */ \ - PTHREAD_COND_INITIALIZER, /* writers_cv */ \ - 0, /* write_thread */ \ - 0, /* rec_write_lock_count */ \ - 0, /* waiting_writers_count */ \ - false, /* is_key_registered */ \ - PTHREAD_COND_INITIALIZER, /* readers_cv */ \ - 0, /* active_reader_threads */ \ - (H5TS_key_t)0 /* rec_read_lock_count_key */ \ - } +#define H5TS_RW_LOCK_INIT \ + { \ + PTHREAD_MUTEX_INITIALIZER, /* mutex */ \ + (H5TS_rw_lock_type_t)UNUSED, /* lock_type */ \ + PTHREAD_COND_INITIALIZER, /* writers_cv */ \ + 0, /* write_thread */ \ + 0, /* rec_write_lock_count */ \ + 0, /* waiting_writers_count */ \ + false, /* is_key_registered */ \ + PTHREAD_COND_INITIALIZER, /* readers_cv */ \ + 0, /* active_reader_threads */ \ + (H5TS_key_t)0 /* rec_read_lock_count_key */ \ + } #endif - /******************/ /* Local Typedefs */ /******************/ @@ -95,27 +98,23 @@ ******************************************************************************/ typedef struct H5TS_rec_entry_count { - int64_t rec_lock_count; + int64_t rec_lock_count; } H5TS_rec_entry_count_t; - /********************/ /* Local Prototypes */ /********************/ static void H5TS__key_destructor(void *key_val); - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ @@ -123,7 +122,6 @@ static void H5TS__key_destructor(void *key_val); /* Default value to initialize R/W locks */ static const H5TS_rw_lock_t H5TS_rw_lock_def = H5TS_RW_LOCK_INIT; - /*-------------------------------------------------------------------------- * Function: H5TS__key_destructor * @@ -357,8 +355,8 @@ H5TS__update_stats_wr_unlock(H5TS_rw_lock_t *rw_lock) herr_t H5TS__rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY @@ -396,8 +394,8 @@ H5TS__rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats) herr_t H5TS__rw_lock_reset_stats(H5TS_rw_lock_t *rw_lock) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY @@ -451,7 +449,8 @@ H5TS__rw_lock_print_stats(const char *header_str, H5TS_rw_lock_stats_t *stats) fprintf(stdout, " real_write_locks_granted = %" PRId64 "\n", stats->real_write_locks_granted); fprintf(stdout, " real_write_locks_released = %" PRId64 "\n", stats->real_write_locks_released); fprintf(stdout, " max_write_locks = %" PRId64 "\n", stats->max_write_locks); - fprintf(stdout, " max_write_lock_recursion_depth = %" PRId64 "\n", stats->max_write_lock_recursion_depth); + fprintf(stdout, " max_write_lock_recursion_depth = %" PRId64 "\n", + stats->max_write_lock_recursion_depth); fprintf(stdout, " write_locks_delayed = %" PRId64 "\n", stats->write_locks_delayed); fprintf(stdout, " max_write_locks_pending = %" PRId64 "\n\n", stats->max_write_locks_pending); @@ -512,14 +511,14 @@ H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock) * along the way. */ if (H5_UNLIKELY(H5TS_mutex_destroy(&rw_lock->mutex))) - ret_value = FAIL; + ret_value = FAIL; if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->readers_cv))) - ret_value = FAIL; + ret_value = FAIL; if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->writers_cv))) - ret_value = FAIL; + ret_value = FAIL; if (rw_lock->is_key_registered) - if (H5_UNLIKELY(H5TS__key_delete(rw_lock->rec_read_lock_count_key))) - ret_value = FAIL; + if (H5_UNLIKELY(H5TS__key_delete(rw_lock->rec_read_lock_count_key))) + ret_value = FAIL; done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -539,9 +538,9 @@ herr_t H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) { H5TS_rec_entry_count_t *count; - H5TS_thread_t my_thread_id = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; + H5TS_thread_t my_thread_id = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY @@ -564,7 +563,7 @@ H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) if (H5_UNLIKELY(pthread_key_create(&rw_lock->rec_read_lock_count_key, H5TS__key_destructor))) HGOTO_DONE(FAIL); rw_lock->is_key_registered = true; - count = NULL; + count = NULL; } else count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); @@ -627,8 +626,8 @@ herr_t H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) { H5TS_thread_t my_thread_id = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -648,7 +647,7 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) if (READ == rw_lock->lock_type) { H5TS_rec_entry_count_t *count; - /* Sanity check */ + /* Sanity check */ assert(rw_lock->is_key_registered); /* Fail if read lock count for this thread is > 0 */ @@ -675,7 +674,7 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) } /* Set lock type & owner thread */ - rw_lock->lock_type = WRITE; + rw_lock->lock_type = WRITE; rw_lock->write_thread = my_thread_id; } @@ -705,8 +704,8 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) herr_t H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -719,7 +718,7 @@ H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) have_mutex = true; /* Error check */ - if (H5_UNLIKELY(UNUSED == rw_lock->lock_type)) /* Unlocking an unused lock? */ + if (H5_UNLIKELY(UNUSED == rw_lock->lock_type)) /* Unlocking an unused lock? */ HGOTO_DONE(FAIL); if (WRITE == rw_lock->lock_type) { /* Drop a write lock */ diff --git a/src/H5TSrwlock.c b/src/H5TSrwlock.c index a454c25facb..f61cdc68fa5 100644 --- a/src/H5TSrwlock.c +++ b/src/H5TSrwlock.c @@ -31,9 +31,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -41,31 +41,24 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ - - #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TStest.c b/src/H5TStest.c index 3ddbab9c92f..caea665bf51 100644 --- a/src/H5TStest.c +++ b/src/H5TStest.c @@ -29,8 +29,8 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -61,7 +61,6 @@ typedef void *(*H5TS_thread_cb_t)(void *); /* Local Variables */ /*******************/ - /*-------------------------------------------------------------------------- * NAME * H5TS__create_thread @@ -104,4 +103,3 @@ H5TS__create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata) } /* H5TS__create_thread */ #endif /* H5_HAVE_THREADSAFE */ - diff --git a/src/H5TSthread.c b/src/H5TSthread.c index 209d67e1339..479c04225da 100644 --- a/src/H5TSthread.c +++ b/src/H5TSthread.c @@ -29,9 +29,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -39,31 +39,24 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ - - #endif /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSwin.c b/src/H5TSwin.c index 18c306ab1a5..71b182ed1eb 100644 --- a/src/H5TSwin.c +++ b/src/H5TSwin.c @@ -28,9 +28,9 @@ /***********/ /* Headers */ /***********/ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5TSpkg.h" /* Threadsafety */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ #ifdef H5_HAVE_THREADSAFE @@ -40,32 +40,26 @@ /* Local Macros */ /****************/ - /******************/ /* Local Typedefs */ /******************/ - /********************/ /* Local Prototypes */ /********************/ - /*********************/ /* Package Variables */ /*********************/ - /*****************************/ /* Library Private Variables */ /*****************************/ - /*******************/ /* Local Variables */ /*******************/ - /*-------------------------------------------------------------------------- * Function: H5TS__win32_process_enter * @@ -110,20 +104,17 @@ 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 @@ -134,8 +125,7 @@ H5TS_win32_thread_enter(void) * *-------------------------------------------------------------------------- */ -herr_t -H5TS_win32_thread_exit(void) +herr_t H5TS_win32_thread_exit(void) { FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -160,5 +150,3 @@ H5TS_win32_thread_exit(void) #endif /* H5_HAVE_WIN_THREADS */ #endif /* H5_HAVE_THREADSAFE */ - - diff --git a/src/H5private.h b/src/H5private.h index b33056805e9..1246fddade5 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1307,7 +1307,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); { \ static bool func_check = false; \ \ - if (H5_UNLIKELY(!func_check)) { \ + if (H5_UNLIKELY(!func_check)) { \ /* Check function naming status */ \ assert(asrt && \ "Function naming conventions are incorrect - check H5_IS_API|PUB|PRIV|PKG macros in " \ @@ -1348,7 +1348,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); if (H5_UNLIKELY(H5CX_push() < 0)) \ HGOTO_ERROR(H5E_FUNC, H5E_CANTSET, err, "can't set API context"); \ else \ - api_ctx_pushed = true; + api_ctx_pushed = true; \ \ /* Push the name of this function on the function stack */ \ H5_PUSH_FUNC @@ -1617,7 +1617,7 @@ H5_DLL herr_t H5CX_pop(bool update_dxpl_props); } /*end scope from end of FUNC_ENTER*/ \ FUNC_LEAVE_API_COMMON(ret_value); \ H5_POP_FUNC \ - if (H5_LIKELY(api_ctx_pushed)) { \ + if (H5_LIKELY(api_ctx_pushed)) { \ (void)H5CX_pop(true); \ api_ctx_pushed = false; \ } \ diff --git a/test/onion.c b/test/onion.c index eba52668753..881fa8d5b0c 100644 --- a/test/onion.c +++ b/test/onion.c @@ -1534,10 +1534,10 @@ test_revision_record_encode_decode(void) static int compare_file_bytes_exactly(const char *filepath, hid_t fapl_id, size_t nbytes, const unsigned char *exp) { - H5FD_t *raw_vfile = NULL; /* virtual file to look at raw file contents */ - unsigned char *act_buf = NULL; /* allocated area for actual file bytes */ - uint64_t filesize = 0; - bool api_ctx_pushed = false; /* Whether API context pushed */ + H5FD_t *raw_vfile = NULL; /* virtual file to look at raw file contents */ + unsigned char *act_buf = NULL; /* allocated area for actual file bytes */ + uint64_t filesize = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Push API context */ if (H5CX_push() < 0) @@ -1609,11 +1609,11 @@ verify_history_as_expected_onion(H5FD_t *raw_file, struct expected_history *filt H5FD_onion_header_t hdr_out; H5FD_onion_history_t history_out; H5FD_onion_revision_record_t rev_out; - uint64_t filesize = 0; - uint64_t readsize = 0; - uint8_t *ui8p = NULL; - uint32_t buf_checksum = 0; - bool api_ctx_pushed = false; /* Whether API context pushed */ + uint64_t filesize = 0; + uint64_t readsize = 0; + uint8_t *ui8p = NULL; + uint32_t buf_checksum = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* memset to avoid bad frees on errors */ memset(&rev_out, 0, sizeof(H5FD_onion_revision_record_t)); @@ -1854,9 +1854,9 @@ verify_stored_onion_create_0_open(struct onion_filepaths *paths, H5FD_onion_fapl unsigned char history_exp_bytes[] = { 'O', 'W', 'H', 'S', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* checksum encoded below */ }; - unsigned char *ptr = NULL; - uint32_t checksum = 0; - bool api_ctx_pushed = false; /* Whether API context pushed */ + unsigned char *ptr = NULL; + uint32_t checksum = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Finish populating expected header bytes */ ptr = hdr_exp_bytes + 8; /* WARNING: must match format */ @@ -1969,8 +1969,8 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) H5FD_t *vfile_rw = NULL; /* Onion virtual file for read/write */ H5FD_t *vfile_ro = NULL; /* Onion virtual file for read-only */ struct expected_history filter; - char *buf = NULL; - bool api_ctx_pushed = false; /* Whether API context pushed */ + char *buf = NULL; + bool api_ctx_pushed = false; /* Whether API context pushed */ if (true == truncate_canonical && true == with_initial_data) TESTING("onion creation; truncate extant canonical; w/ initial data"); @@ -2257,7 +2257,6 @@ test_create_oniontarget(bool truncate_canonical, bool with_initial_data) if (api_ctx_pushed) H5CX_pop(false); - if (paths != NULL) { HDremove(paths->canon); HDremove(paths->onion); @@ -2327,7 +2326,7 @@ test_several_revisions_with_logical_gaps(void) uint64_t a_off = ONION_TEST_PAGE_SIZE_5 + 7; /* 39 */ uint64_t b_off = (((a_off + a_list_size_s + ONION_TEST_PAGE_SIZE_5 - 1) >> 5) << 5) + ONION_TEST_PAGE_SIZE_5 + 7; /* full page between */ - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ TESTING("multiple revisions with gaps and overlap"); @@ -2637,7 +2636,6 @@ test_several_revisions_with_logical_gaps(void) if (api_ctx_pushed) H5CX_pop(false); - if (paths != NULL) { HDremove(paths->canon); HDremove(paths->onion); @@ -2678,11 +2676,11 @@ static int do_onion_open_and_writes(const char *filename, H5FD_onion_fapl_info_t *onion_info_p, size_t n_ops, struct revise_revision *about) { - hid_t fapl_id = H5I_INVALID_HID; - H5FD_t *file = NULL; /* Onion virtual file for read/write */ - unsigned char *buf_vfy = NULL; - size_t i = 0; - bool api_ctx_pushed = false; /* Whether API context pushed */ + hid_t fapl_id = H5I_INVALID_HID; + H5FD_t *file = NULL; /* Onion virtual file for read/write */ + unsigned char *buf_vfy = NULL; + size_t i = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Push API context */ if (H5CX_push() < 0) @@ -2807,9 +2805,9 @@ test_page_aligned_history_create(void) struct revise_revision about[2]; H5FD_onion_header_t hdr_out; H5FD_onion_history_t history_out; - size_t i = 0; - uint64_t a_off = b_list_size_s - a_list_size_s; - bool api_ctx_pushed = false; /* Whether API context pushed */ + size_t i = 0; + uint64_t a_off = b_list_size_s - a_list_size_s; + bool api_ctx_pushed = false; /* Whether API context pushed */ TESTING("page-aligned history on onion-created file"); diff --git a/test/ttsafe.c b/test/ttsafe.c index de0f211dcda..98250b35c2e 100644 --- a/test/ttsafe.c +++ b/test/ttsafe.c @@ -114,10 +114,14 @@ main(int argc, char *argv[]) AddTest("attr_vlen", tts_attr_vlen, cleanup_attr_vlen, "multi-file-attribute-vlen read", NULL); /* Recursive R/W locks */ - AddTest("rec_rwlock_1", tts_rec_rw_lock_smoke_check_1, NULL, "recursive R/W lock smoke check 1 -- basic", NULL); - AddTest("rec_rwlock_2", tts_rec_rw_lock_smoke_check_2, NULL, "recursive R/W lock smoke check 2 -- mob of readers", NULL); - AddTest("rec_rwlock_3", tts_rec_rw_lock_smoke_check_3, NULL, "recursive R/W lock smoke check 3 -- mob of writers", NULL); - AddTest("rec_rwlock_4", tts_rec_rw_lock_smoke_check_4, NULL, "recursive R/W lock smoke check 4 -- mixed mob", NULL); + AddTest("rec_rwlock_1", tts_rec_rw_lock_smoke_check_1, NULL, "recursive R/W lock smoke check 1 -- basic", + NULL); + AddTest("rec_rwlock_2", tts_rec_rw_lock_smoke_check_2, NULL, + "recursive R/W lock smoke check 2 -- mob of readers", NULL); + AddTest("rec_rwlock_3", tts_rec_rw_lock_smoke_check_3, NULL, + "recursive R/W lock smoke check 3 -- mob of writers", NULL); + AddTest("rec_rwlock_4", tts_rec_rw_lock_smoke_check_4, NULL, + "recursive R/W lock smoke check 4 -- mixed mob", NULL); /* Developer API routine tests */ AddTest("developer", tts_develop_api, NULL, "developer API routines", NULL); diff --git a/test/ttsafe_develop.c b/test/ttsafe_develop.c index 95188747471..fe1832e0abe 100644 --- a/test/ttsafe_develop.c +++ b/test/ttsafe_develop.c @@ -33,10 +33,10 @@ typedef struct { static void * tts_develop_api_thr_1(void *_udata) { - tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata; - unsigned lock_count = UINT_MAX; - bool acquired = false; - herr_t result; + tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata; + unsigned lock_count = UINT_MAX; + bool acquired = false; + herr_t result; /* Acquire the API lock - should acquire it */ result = H5TSmutex_acquire(1, &acquired); @@ -66,9 +66,9 @@ tts_develop_api_thr_1(void *_udata) static void * tts_develop_api_thr_2(void *_udata) { - tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata; - bool acquired = false; - herr_t result; + tts_develop_api_udata_t *udata = (tts_develop_api_udata_t *)_udata; + bool acquired = false; + herr_t result; /* Thread #1 will acquire the API lock */ @@ -95,13 +95,13 @@ tts_develop_api_thr_2(void *_udata) void tts_develop_api(void) { - H5TS_thread_t thread_1, thread_2; - H5TS_barrier_t barrier; - unsigned lock_count = UINT_MAX; - bool acquired = false; + H5TS_thread_t thread_1, thread_2; + H5TS_barrier_t barrier; + unsigned lock_count = UINT_MAX; + bool acquired = false; tts_develop_api_udata_t udata; - unsigned api_count_1 = 0, api_count_2 = 0; - herr_t result; + unsigned api_count_1 = 0, api_count_2 = 0; + herr_t result; /* Check that API count increases with each API call */ result = H5TSmutex_get_attempt_count(&api_count_1); @@ -116,7 +116,6 @@ tts_develop_api(void) VERIFY(api_count_2, (api_count_1 + 1), "H5TSmutex_get_attempt_count"); - /* Check H5TSmutex_acquire & H5TSmutex_release in thread callbacks */ /* Create the thread barrier for the two threads */ @@ -125,8 +124,8 @@ tts_develop_api(void) /* Create the threads */ udata.barrier = &barrier; - thread_1 = H5TS__create_thread(tts_develop_api_thr_1, NULL, &udata); - thread_2 = H5TS__create_thread(tts_develop_api_thr_2, NULL, &udata); + thread_1 = H5TS__create_thread(tts_develop_api_thr_1, NULL, &udata); + thread_2 = H5TS__create_thread(tts_develop_api_thr_2, NULL, &udata); /* Wait for threads to complete. */ H5TS__wait_for_thread(thread_1); @@ -135,7 +134,6 @@ tts_develop_api(void) result = H5TS__barrier_destroy(&barrier); CHECK_I(result, "H5TS__barrier_destroy"); - /* Test multiple / recursive acquisition of the API lock */ /* Acquire the API lock - should acquire it */ @@ -145,7 +143,7 @@ tts_develop_api(void) /* Acquire the API lock again - should acquire it, since it's the same thread */ acquired = false; - result = H5TSmutex_acquire(1, &acquired); + result = H5TSmutex_acquire(1, &acquired); CHECK_I(result, "H5TSmutex_acquire"); VERIFY(acquired, true, "H5TSmutex_acquire"); @@ -157,4 +155,3 @@ tts_develop_api(void) } /* end tts_develop_api() */ #endif /*H5_HAVE_THREADSAFE*/ - diff --git a/test/ttsafe_error.c b/test/ttsafe_error.c index 6e5261d146e..7b39af38a30 100644 --- a/test/ttsafe_error.c +++ b/test/ttsafe_error.c @@ -44,10 +44,10 @@ typedef struct err_num_struct { } err_num_t; /* Global variables */ -hid_t error_file_g = H5I_INVALID_HID; -int error_flag_g = 0; -int error_count_g = 0; -err_num_t expected_g[EXPECTED_ERROR_DEPTH]; +hid_t error_file_g = H5I_INVALID_HID; +int error_flag_g = 0; +int error_count_g = 0; +err_num_t expected_g[EXPECTED_ERROR_DEPTH]; H5TS_mutex_t error_mutex_g; /* Prototypes */ diff --git a/test/ttsafe_rec_rw_lock.c b/test/ttsafe_rec_rw_lock.c index 330b403d0f3..b6da4b74ef6 100644 --- a/test/ttsafe_rec_rw_lock.c +++ b/test/ttsafe_rec_rw_lock.c @@ -33,7 +33,7 @@ #ifndef H5_HAVE_WIN_THREADS #define MAX_NUM_THREADS 64 -#define MAX_LOCK_CYCLES (10 * 1000 * 1000) +#define MAX_LOCK_CYCLES (10 * 1000 * 1000) /* structure used to configure test threads in the recurive * R/W/ lock tests. @@ -265,11 +265,11 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) void tts_rec_rw_lock_smoke_check_1(void) { - herr_t result; + herr_t result; #if H5TS_ENABLE_REC_RW_LOCK_STATS H5TS_rw_lock_stats_t stats; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rw_lock_t rec_rw_lock; /* 1) Initialize an instance of the recursive R/W lock. */ result = H5TS__rw_lock_init(&rec_rw_lock); @@ -551,18 +551,18 @@ tts_rec_rw_lock_smoke_check_2(void) herr_t result; int express_test; int i; - int num_threads = MAX_NUM_THREADS; - int lock_cycles = MAX_LOCK_CYCLES; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; H5TS_thread_t threads[MAX_NUM_THREADS]; rec_rw_lock_test_udata_t *udata = NULL; #if H5TS_ENABLE_REC_RW_LOCK_STATS - hbool_t verbose = FALSE; - int32_t total_target_rd_lock_cycles = 0; - int32_t total_target_wr_lock_cycles = 0; - H5TS_rw_lock_stats_t stats; - H5TS_rw_lock_stats_t expected; + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rw_lock_t rec_rw_lock; #if H5TS_ENABLE_REC_RW_LOCK_STATS /* Reset expected stats fields to zero -- we will construct the expected @@ -602,12 +602,12 @@ tts_rec_rw_lock_smoke_check_2(void) /* 2) Setup the user data to be passed to each reader test thread. */ for (i = 0; i < MAX_NUM_THREADS; i++) { memset(&udata[i], 0, sizeof(udata[i])); - udata[i].rw_lock = &rec_rw_lock; - udata[i].target_rd_lock_cycles = lock_cycles; - udata[i].max_recursive_lock_depth = 10; + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_rd_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; } -uint64_t start_time = H5_now_usec(); + uint64_t start_time = H5_now_usec(); /* 3) Create the reader threads, each with its own user data. */ for (i = 0; i < num_threads; i++) threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &udata[i]); @@ -615,9 +615,10 @@ uint64_t start_time = H5_now_usec(); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) H5TS__wait_for_thread(threads[i]); -uint64_t end_time = H5_now_usec(); -uint64_t elap_time = (unsigned long long)(end_time - start_time); -fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, (elap_time / (uint64_t)lock_cycles)); + uint64_t end_time = H5_now_usec(); + uint64_t elap_time = (unsigned long long)(end_time - start_time); + fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, + (elap_time / (uint64_t)lock_cycles)); /* 5) Examine the user data from the threads, to determine the * total number of real and recursive read locks and unlocks. @@ -656,9 +657,9 @@ fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, ( * and exited early. */ if (total_target_rd_lock_cycles != expected.real_read_locks_granted || - total_target_rd_lock_cycles != expected.real_read_locks_released || - total_target_wr_lock_cycles != expected.real_write_locks_granted || - total_target_wr_lock_cycles != expected.real_write_locks_released) + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); /* initialize remaining non-zero fields in the expected stats */ @@ -749,18 +750,18 @@ tts_rec_rw_lock_smoke_check_3(void) herr_t result; int i; int express_test; - int num_threads = MAX_NUM_THREADS; - int lock_cycles = MAX_LOCK_CYCLES; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; H5TS_thread_t threads[MAX_NUM_THREADS]; rec_rw_lock_test_udata_t *udata = NULL; #if H5TS_ENABLE_REC_RW_LOCK_STATS - hbool_t verbose = FALSE; - int32_t total_target_rd_lock_cycles = 0; - int32_t total_target_wr_lock_cycles = 0; - H5TS_rw_lock_stats_t stats; - H5TS_rw_lock_stats_t expected; + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rw_lock_t rec_rw_lock; #if H5TS_ENABLE_REC_RW_LOCK_STATS /* Reset expected stats fields to zero -- we will construct the expected @@ -800,12 +801,12 @@ tts_rec_rw_lock_smoke_check_3(void) /* 2) Setup the user data to be passed to each writer test thread. */ for (i = 0; i < MAX_NUM_THREADS; i++) { memset(&udata[i], 0, sizeof(udata[i])); - udata[i].rw_lock = &rec_rw_lock; - udata[i].target_wr_lock_cycles = lock_cycles; - udata[i].max_recursive_lock_depth = 10; + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_wr_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; } -uint64_t start_time = H5_now_usec(); + uint64_t start_time = H5_now_usec(); /* 3) Create the writer threads, each with its own user data. */ for (i = 0; i < num_threads; i++) threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &(udata[i])); @@ -813,9 +814,10 @@ uint64_t start_time = H5_now_usec(); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) H5TS__wait_for_thread(threads[i]); -uint64_t end_time = H5_now_usec(); -uint64_t elap_time = (unsigned long long)(end_time - start_time); -fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, (elap_time / (uint64_t)lock_cycles)); + uint64_t end_time = H5_now_usec(); + uint64_t elap_time = (unsigned long long)(end_time - start_time); + fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, + (elap_time / (uint64_t)lock_cycles)); /* 5) Examine the user data from the threads, to determine the * total number of real and recursive read locks and unlock. @@ -854,9 +856,9 @@ fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, ( * and exited early. */ if (total_target_rd_lock_cycles != expected.real_read_locks_granted || - total_target_rd_lock_cycles != expected.real_read_locks_released || - total_target_wr_lock_cycles != expected.real_write_locks_granted || - total_target_wr_lock_cycles != expected.real_write_locks_released) + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); /* initialize remaining non-zero fields in the expected stats */ @@ -947,18 +949,18 @@ tts_rec_rw_lock_smoke_check_4(void) herr_t result; int i; int express_test; - int num_threads = MAX_NUM_THREADS; - int lock_cycles = MAX_LOCK_CYCLES; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; H5TS_thread_t threads[MAX_NUM_THREADS]; rec_rw_lock_test_udata_t *udata = NULL; #if H5TS_ENABLE_REC_RW_LOCK_STATS - hbool_t verbose = FALSE; - int32_t total_target_rd_lock_cycles = 0; - int32_t total_target_wr_lock_cycles = 0; - H5TS_rw_lock_stats_t stats; - H5TS_rw_lock_stats_t expected; + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rw_lock_t rec_rw_lock; #if H5TS_ENABLE_REC_RW_LOCK_STATS /* Reset expected stats fields to zero -- we will construct the expected @@ -998,13 +1000,13 @@ tts_rec_rw_lock_smoke_check_4(void) /* 2) Setup the user data to be passed to each writer test thread. */ for (i = 0; i < MAX_NUM_THREADS; i++) { memset(&udata[i], 0, sizeof(udata[i])); - udata[i].rw_lock = &rec_rw_lock; - udata[i].target_rd_lock_cycles = lock_cycles; - udata[i].target_wr_lock_cycles = lock_cycles; - udata[i].max_recursive_lock_depth = 10; + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_rd_lock_cycles = lock_cycles; + udata[i].target_wr_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; } -uint64_t start_time = H5_now_usec(); + uint64_t start_time = H5_now_usec(); /* 3) Create the reader threads, each with its own user data. */ for (i = 0; i < num_threads; i++) threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &(udata[i])); @@ -1012,9 +1014,10 @@ uint64_t start_time = H5_now_usec(); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) H5TS__wait_for_thread(threads[i]); -uint64_t end_time = H5_now_usec(); -uint64_t elap_time = (unsigned long long)(end_time - start_time); -fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, (elap_time / (uint64_t)lock_cycles)); + uint64_t end_time = H5_now_usec(); + uint64_t elap_time = (unsigned long long)(end_time - start_time); + fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, + (elap_time / (uint64_t)lock_cycles)); /* 5) Examine the user data from the threads, to determine the * total number of real and recursive read locks and unlock. @@ -1053,9 +1056,9 @@ fprintf(stdout, "elapsed usec: %llu, usec per lock_cycle = %llu\n", elap_time, ( * and exited early. */ if (total_target_rd_lock_cycles != expected.real_read_locks_granted || - total_target_rd_lock_cycles != expected.real_read_locks_released || - total_target_wr_lock_cycles != expected.real_write_locks_granted || - total_target_wr_lock_cycles != expected.real_write_locks_released) + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); /* initialize remaining non-zero fields in the expected stats */ diff --git a/test/ttsafe_thread_id.c b/test/ttsafe_thread_id.c index aa77499eb4b..1d48da58915 100644 --- a/test/ttsafe_thread_id.c +++ b/test/ttsafe_thread_id.c @@ -21,13 +21,13 @@ #ifdef H5_HAVE_THREADSAFE #define CYCLE_COUNT 2 -#define NTHREADS 5 +#define NTHREADS 5 -static volatile bool failed = false; -static H5TS_barrier_t barrier; -static int times; -static bool used[NTHREADS * CYCLE_COUNT]; -static H5TS_mutex_t used_lock = PTHREAD_MUTEX_INITIALIZER; +static volatile bool failed = false; +static H5TS_barrier_t barrier; +static int times; +static bool used[NTHREADS * CYCLE_COUNT]; +static H5TS_mutex_t used_lock = PTHREAD_MUTEX_INITIALIZER; /* Each thread runs this routine. The routine fetches the current * thread's ID, makes sure that it is in the expected range, makes @@ -48,7 +48,7 @@ static H5TS_mutex_t used_lock = PTHREAD_MUTEX_INITIALIZER; static void * thread_main(void H5_ATTR_UNUSED *arg) { - int min_id, max_id; + int min_id, max_id; uint64_t ntid, tid; tid = H5TS_thread_id(); @@ -97,9 +97,9 @@ void tts_thread_id(void) { H5TS_thread_t threads[NTHREADS]; - uint64_t tid; - int i; - herr_t result; + uint64_t tid; + int i; + herr_t result; result = H5TS__barrier_init(&barrier, NTHREADS); CHECK_I(result, "H5TS__barrier_init"); @@ -123,7 +123,7 @@ tts_thread_id(void) /* Access synchronized by thread create/join */ for (i = 0; i < NTHREADS; i++) { - if(!used[(times * NTHREADS) + i]) + if (!used[(times * NTHREADS) + i]) TestErrPrintf("thread ID %d did not run.", i + 1); } } @@ -133,5 +133,3 @@ tts_thread_id(void) } /* end tts_thread_id() */ #endif /*H5_HAVE_THREADSAFE*/ - - diff --git a/test/vfd.c b/test/vfd.c index 8ce87e82d02..94ad10af4fa 100644 --- a/test/vfd.c +++ b/test/vfd.c @@ -4239,9 +4239,9 @@ test_vector_io__read_v_indiv(H5FD_t *lf, uint32_t count, H5FD_mem_t types[], had bool result = true; /* will set to false on failure */ bool verbose = false; uint32_t i; - size_t size = SIZE_MAX; - H5FD_mem_t type = H5FD_MEM_NTYPES; - bool api_ctx_pushed = false; /* Whether API context pushed */ + size_t size = SIZE_MAX; + H5FD_mem_t type = H5FD_MEM_NTYPES; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Push API context */ if (H5CX_push() < 0) @@ -4295,9 +4295,9 @@ test_vector_io__write_v_indiv(H5FD_t *lf, uint32_t count, H5FD_mem_t types[], ha bool result = true; /* will set to false on failure */ bool verbose = false; uint32_t i; - size_t size = SIZE_MAX; - H5FD_mem_t type = H5FD_MEM_NTYPES; - bool api_ctx_pushed = false; /* Whether API context pushed */ + size_t size = SIZE_MAX; + H5FD_mem_t type = H5FD_MEM_NTYPES; + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Push API context */ if (H5CX_push() < 0) @@ -4479,12 +4479,12 @@ static herr_t test_vector_io(const char *vfd_name) { char test_title[80]; - bool size_fixed_0 = false; /* whether remaining entry */ - bool size_fixed_1 = false; /* sizes in vector are fixed. */ - bool size_fixed_2 = false; /* */ - bool type_fixed_0 = false; /* whether remaining entry */ - bool type_fixed_1 = false; /* types in vector are fixed. */ - bool type_fixed_2 = false; /* */ + bool size_fixed_0 = false; /* whether remaining entry */ + bool size_fixed_1 = false; /* sizes in vector are fixed. */ + bool size_fixed_2 = false; /* */ + bool type_fixed_0 = false; /* whether remaining entry */ + bool type_fixed_1 = false; /* types in vector are fixed. */ + bool type_fixed_2 = false; /* */ bool verbose = false; hid_t fapl_id = H5I_INVALID_HID; /* file access property list ID */ haddr_t eoa; /* file eoa */ @@ -4995,7 +4995,7 @@ test_selection_io_write(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t mem_s const void **bufs; /* Avoids cast/const warnings */ int i; int j; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ if (NULL == (bufs = calloc(count, sizeof(void *)))) TEST_ERROR; @@ -5058,7 +5058,7 @@ test_selection_io_read_verify(H5FD_t *lf, H5FD_mem_t type, uint32_t count, hid_t int *rbufs[2] = {rbuf1, rbuf2}; int i; int j; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ /* Initialize read buffer */ for (i = 0; i < (int)rbufcount; i++) @@ -5165,8 +5165,8 @@ test_selection_io(const char *vfd_name) int erbuf1[SEL_IO_DIM0 * SEL_IO_DIM1]; /* 1D expected read buffer */ int erbuf2[SEL_IO_DIM0][SEL_IO_DIM1]; /* 2D expected read buffer */ int *erbufs[2] = {erbuf1, erbuf2[0]}; /* Array of expected read buffers */ - int shorten_element_sizes; /* Whether to shorten the element sizes array */ - bool api_ctx_pushed = false; /* Whether API context pushed */ + int shorten_element_sizes; /* Whether to shorten the element sizes array */ + bool api_ctx_pushed = false; /* Whether API context pushed */ snprintf(test_title, sizeof(test_title), "selection I/O with %s VFD", vfd_name); diff --git a/testpar/t_vfd.c b/testpar/t_vfd.c index 07c44a93929..383d0bd6c2f 100644 --- a/testpar/t_vfd.c +++ b/testpar/t_vfd.c @@ -350,13 +350,13 @@ setup_vfd_test_file(int file_name_id, char *file_name, int mpi_size, H5FD_mpio_x { const char *fcn_name = "setup_vfd_test_file()"; char filename[512]; - int cp = 0; - bool show_progress = false; - hid_t fapl_id = H5I_INVALID_HID; /* file access property list ID */ - hid_t dxpl_id = H5I_INVALID_HID; /* data access property list ID */ - unsigned flags = 0; /* file open flags */ - H5FD_t *lf = NULL; /* VFD struct ptr */ - bool api_ctx_pushed = false; /* Whether API context pushed */ + int cp = 0; + bool show_progress = false; + hid_t fapl_id = H5I_INVALID_HID; /* file access property list ID */ + hid_t dxpl_id = H5I_INVALID_HID; /* data access property list ID */ + unsigned flags = 0; /* file open flags */ + H5FD_t *lf = NULL; /* VFD struct ptr */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(vfd_name); assert(lf_ptr); @@ -624,10 +624,10 @@ setup_vfd_test_file(int file_name_id, char *file_name, int mpi_size, H5FD_mpio_x static void takedown_vfd_test_file(int mpi_rank, char *filename, H5FD_t **lf_ptr, hid_t *fapl_id_ptr, hid_t *dxpl_id_ptr) { - const char *fcn_name = "takedown_vfd_test_file()"; - int cp = 0; - bool show_progress = false; - bool api_ctx_pushed = false; /* Whether API context pushed */ + const char *fcn_name = "takedown_vfd_test_file()"; + int cp = 0; + bool show_progress = false; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(lf_ptr); assert(fapl_id_ptr); @@ -768,7 +768,7 @@ vector_read_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[1]; size_t sizes[1]; void *bufs[1]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -1021,7 +1021,7 @@ vector_read_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[1]; size_t sizes[1]; void *bufs[1]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -1345,7 +1345,7 @@ vector_read_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[4]; size_t sizes[4]; void *bufs[4]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -1721,7 +1721,7 @@ vector_read_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[4]; size_t sizes[4]; void *bufs[4]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2171,7 +2171,7 @@ vector_read_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_ haddr_t addrs[(INTS_PER_RANK / 16) + 1]; size_t sizes[2]; void *bufs[(INTS_PER_RANK / 16) + 1]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2430,7 +2430,7 @@ vector_write_test_1(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[1]; size_t sizes[1]; const void *bufs[1]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2640,7 +2640,7 @@ vector_write_test_2(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[1]; size_t sizes[1]; const void *bufs[1]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -2916,7 +2916,7 @@ vector_write_test_3(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[4]; size_t sizes[4]; const void *bufs[4]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -3199,7 +3199,7 @@ vector_write_test_4(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[4]; size_t sizes[4]; const void *bufs[4]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -3519,7 +3519,7 @@ vector_write_test_5(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[4]; size_t sizes[4]; const void *bufs[4]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -3987,7 +3987,7 @@ vector_write_test_6(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[(INTS_PER_RANK / 16) + 1]; size_t sizes[2]; const void *bufs[(INTS_PER_RANK / 16) + 1]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -4278,7 +4278,7 @@ vector_write_test_7(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer haddr_t addrs[8]; size_t sizes[8]; const void *bufs[8]; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -4548,24 +4548,24 @@ static unsigned vector_write_test_8(int file_name_id, int mpi_rank, int mpi_size, H5FD_mpio_xfer_t xfer_mode, H5FD_mpio_collective_opt_t coll_opt_mode, const char *vfd_name) { - const char *fcn_name = "vector_write_test_8()"; - char test_title[120]; - char filename[512]; - haddr_t eoa; - haddr_t base_addr; - bool show_progress = false; - hid_t fapl_id = H5I_INVALID_HID; /* file access property list ID */ - hid_t dxpl_id = H5I_INVALID_HID; /* data access property list ID */ - H5FD_t *lf = NULL; /* VFD struct ptr */ - int cp = 0; - int i; - int base_index; - uint32_t count = 0; - size_t sizes[4]; - H5FD_mem_t types[2]; - haddr_t *tt_addrs = NULL; /* For storing addrs */ - const void **tt_bufs = NULL; /* For storing buf pointers */ - bool api_ctx_pushed = false; /* Whether API context pushed */ + const char *fcn_name = "vector_write_test_8()"; + char test_title[120]; + char filename[512]; + haddr_t eoa; + haddr_t base_addr; + bool show_progress = false; + hid_t fapl_id = H5I_INVALID_HID; /* file access property list ID */ + hid_t dxpl_id = H5I_INVALID_HID; /* data access property list ID */ + H5FD_t *lf = NULL; /* VFD struct ptr */ + int cp = 0; + int i; + int base_index; + uint32_t count = 0; + size_t sizes[4]; + H5FD_mem_t types[2]; + haddr_t *tt_addrs = NULL; /* For storing addrs */ + const void **tt_bufs = NULL; /* For storing buf pointers */ + bool api_ctx_pushed = false; /* Whether API context pushed */ pass = true; @@ -5015,7 +5015,7 @@ test_selection_io_read_verify(hid_t dxpl, int mpi_rank, hsize_t start[], hsize_t size_t bufsize; int i; int j; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ bufsize = (hsize_t)(sel_dim0 * sel_dim1) * sizeof(int); if ((rbuf1 = malloc(bufsize)) == NULL) @@ -5104,7 +5104,7 @@ test_selection_io_write(hid_t dxpl, H5FD_t *lf, H5FD_mem_t type, uint32_t count, const void **bufs = NULL; /* Avoids cast/const warnings */ int i; int j; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ if (NULL == (bufs = calloc(count, sizeof(void *)))) goto error; @@ -6344,17 +6344,17 @@ test_selection_io_types_1d(int mpi_rank, int mpi_size, H5FD_t *lf, hid_t dxpl, H static void test_selection_io_real(int mpi_rank, int mpi_size, H5FD_t *lf, hid_t dxpl) { - hid_t mem_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* memory dataspaces vector */ - hid_t file_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* file dataspaces vector */ - hsize_t dims1[1]; /* 1d dimension sizes */ - hsize_t dims2[2]; /* 2d dimension sizes */ - H5FD_mem_t type; /* File type */ - haddr_t addrs[2]; /* File allocation address */ - size_t element_sizes[2] = {sizeof(int), sizeof(int)}; /* Element size */ - size_t bufsize; /* Buffer size */ + hid_t mem_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* memory dataspaces vector */ + hid_t file_spaces[2] = {H5I_INVALID_HID, H5I_INVALID_HID}; /* file dataspaces vector */ + hsize_t dims1[1]; /* 1d dimension sizes */ + hsize_t dims2[2]; /* 2d dimension sizes */ + H5FD_mem_t type; /* File type */ + haddr_t addrs[2]; /* File allocation address */ + size_t element_sizes[2] = {sizeof(int), sizeof(int)}; /* Element size */ + size_t bufsize; /* Buffer size */ int i; int j; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ curr_nerrors = nerrors; @@ -6485,16 +6485,16 @@ test_selection_io_real(int mpi_rank, int mpi_size, H5FD_t *lf, hid_t dxpl) static void test_selection_io(int mpi_rank, int mpi_size) { - H5FD_t *lf = NULL; /* VFD struct ptr */ - hid_t fapl = H5I_INVALID_HID; /* File access property list */ - char filename[1024]; /* Test file name */ - unsigned flags = 0; /* File access flags */ - unsigned collective; /* Types of I/O for testing */ - hid_t dxpl = H5I_INVALID_HID; /* Dataset transfer property list */ - hid_t def_dxpl = H5I_INVALID_HID; /* dxpl: independent access */ - hid_t col_xfer_dxpl = H5I_INVALID_HID; /* dxpl: collective access with collective I/O */ - hid_t ind_io_dxpl = H5I_INVALID_HID; /* dxpl: collective access with individual I/O */ - bool api_ctx_pushed = false; /* Whether API context pushed */ + H5FD_t *lf = NULL; /* VFD struct ptr */ + hid_t fapl = H5I_INVALID_HID; /* File access property list */ + char filename[1024]; /* Test file name */ + unsigned flags = 0; /* File access flags */ + unsigned collective; /* Types of I/O for testing */ + hid_t dxpl = H5I_INVALID_HID; /* Dataset transfer property list */ + hid_t def_dxpl = H5I_INVALID_HID; /* dxpl: independent access */ + hid_t col_xfer_dxpl = H5I_INVALID_HID; /* dxpl: collective access with collective I/O */ + hid_t ind_io_dxpl = H5I_INVALID_HID; /* dxpl: collective access with individual I/O */ + bool api_ctx_pushed = false; /* Whether API context pushed */ /* If I use fapl in this call, I got an environment printout */ h5_fixname(SELECT_FNAME, H5P_DEFAULT, filename, sizeof(filename)); diff --git a/utils/mirror_vfd/mirror_writer.c b/utils/mirror_vfd/mirror_writer.c index f91b00c8f5d..3ef75d5aa28 100644 --- a/utils/mirror_vfd/mirror_writer.c +++ b/utils/mirror_vfd/mirror_writer.c @@ -220,8 +220,8 @@ session_init(struct mirror_writer_opts *opts) static int session_stop(struct mirror_session *session) { - bool api_ctx_pushed = false; /* Whether API context pushed */ - int ret_value = 0; + bool api_ctx_pushed = false; /* Whether API context pushed */ + int ret_value = 0; assert(session && (session->magic == MW_SESSION_MAGIC)); @@ -406,7 +406,7 @@ reply_error(struct mirror_session *session, const char *msg) static int do_close(struct mirror_session *session) { - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC)); @@ -456,7 +456,7 @@ do_lock(struct mirror_session *session, const unsigned char *xmit_buf) { size_t decode_ret = 0; H5FD_mirror_xmit_lock_t xmit_lock; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf); @@ -511,10 +511,10 @@ do_lock(struct mirror_session *session, const unsigned char *xmit_buf) static int do_open(struct mirror_session *session, const H5FD_mirror_xmit_open_t *xmit_open) { - hid_t fapl_id = H5I_INVALID_HID; - unsigned _flags = 0; - haddr_t _maxaddr = HADDR_UNDEF; - bool api_ctx_pushed = false; /* Whether API context pushed */ + hid_t fapl_id = H5I_INVALID_HID; + unsigned _flags = 0; + haddr_t _maxaddr = HADDR_UNDEF; + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_open && true == H5FD_mirror_xmit_is_open(xmit_open)); @@ -566,7 +566,7 @@ do_open(struct mirror_session *session, const H5FD_mirror_xmit_open_t *xmit_open /* Push API context */ if (H5CX_push() < 0) - goto error; + goto error; else api_ctx_pushed = true; @@ -622,7 +622,7 @@ do_set_eoa(struct mirror_session *session, const unsigned char *xmit_buf) { size_t decode_ret = 0; H5FD_mirror_xmit_eoa_t xmit_seoa; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf); @@ -678,7 +678,7 @@ do_set_eoa(struct mirror_session *session, const unsigned char *xmit_buf) static int do_truncate(struct mirror_session *session) { - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC)); @@ -720,7 +720,7 @@ do_truncate(struct mirror_session *session) static int do_unlock(struct mirror_session *session) { - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC)); @@ -774,7 +774,7 @@ do_write(struct mirror_session *session, const unsigned char *xmit_buf) char *buf = NULL; ssize_t nbytes_in_packet = 0; H5FD_mirror_xmit_write_t xmit_write; - bool api_ctx_pushed = false; /* Whether API context pushed */ + bool api_ctx_pushed = false; /* Whether API context pushed */ assert(session && (session->magic == MW_SESSION_MAGIC) && xmit_buf); From c04c31aca61a88810bb931dc4c8b4eab30875520 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 15 Mar 2024 14:54:21 -0500 Subject: [PATCH 003/522] Finish creating wrappers for thread-local keys and switch previous use in the library to use the new wrappers. Signed-off-by: Quincey Koziol --- src/H5TSint.c | 26 ++--- src/H5TSkey.c | 265 ++++++++++++++++++++-------------------------- src/H5TSpkg.h | 6 -- src/H5TSprivate.h | 2 + src/H5TSpthread.c | 15 +-- src/H5TSwin.c | 34 +++--- 6 files changed, 160 insertions(+), 188 deletions(-) diff --git a/src/H5TSint.c b/src/H5TSint.c index fd02ff3b4cd..04535e4abf6 100644 --- a/src/H5TSint.c +++ b/src/H5TSint.c @@ -275,10 +275,10 @@ H5TS__tinfo_init(void) /* Initialize key for thread-specific API contexts */ #ifdef H5_HAVE_WIN_THREADS - if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (H5TS_thrd_info_key_g = TlsAlloc()))) + if (H5_UNLIKELY(H5TS_key_create(&H5TS_thrd_info_key_g, NULL) < 0)) ret_value = FAIL; #else - if (H5_UNLIKELY(pthread_key_create(&H5TS_thrd_info_key_g, H5TS__tinfo_destroy))) + if (H5_UNLIKELY(H5TS_key_create(&H5TS_thrd_info_key_g, H5TS__tinfo_destroy) < 0)) ret_value = FAIL; #endif @@ -338,7 +338,7 @@ H5TS__tinfo_create(void) H5E__set_default_auto(&tinfo_node->info.err_stack); /* Error stack */ /* Set a thread-local pointer to the thread's info record */ - if (H5_UNLIKELY(H5TS__set_thread_local_value(H5TS_thrd_info_key_g, tinfo_node))) { + if (H5_UNLIKELY(H5TS_key_set_value(H5TS_thrd_info_key_g, tinfo_node))) { H5TS__tinfo_destroy(tinfo_node); HGOTO_DONE(NULL); } @@ -377,7 +377,9 @@ H5TS_thread_id(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ - if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &tinfo_node) < 0)) + HGOTO_DONE(0); + if (NULL == tinfo_node) /* Create thread info for this thread */ if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) HGOTO_DONE(0); @@ -409,7 +411,9 @@ H5TS_get_api_ctx_ptr(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ - if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &tinfo_node) < 0)) + HGOTO_DONE(NULL); + if (NULL == tinfo_node) /* Create thread info for this thread */ if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) HGOTO_DONE(NULL); @@ -441,7 +445,9 @@ H5TS_get_err_stack(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ - if (NULL == (tinfo_node = H5TS__get_thread_local_value(H5TS_thrd_info_key_g))) + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &tinfo_node) < 0)) + HGOTO_DONE(NULL); + if (NULL == tinfo_node) /* Create thread info for this thread */ if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) HGOTO_DONE(NULL); @@ -513,14 +519,8 @@ H5TS__tinfo_term(void) H5TS_mutex_destroy(&H5TS_tinfo_mtx_s); /* Release key for thread-specific API contexts */ -#ifdef H5_HAVE_WIN_THREADS - if (H5TS_thrd_info_key_g != TLS_OUT_OF_INDEXES) - if (H5_UNLIKELY(H5TS__key_delete(H5TS_thrd_info_key_g) == 0)) - ret_value = FAIL; -#else - if (H5_UNLIKELY(H5TS__key_delete(H5TS_thrd_info_key_g))) + if (H5_UNLIKELY(H5TS_key_delete(H5TS_thrd_info_key_g) < 0)) ret_value = FAIL; -#endif FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS__tinfo_term() */ diff --git a/src/H5TSkey.c b/src/H5TSkey.c index 0a611356b53..20a5070cd5b 100644 --- a/src/H5TSkey.c +++ b/src/H5TSkey.c @@ -85,189 +85,116 @@ static herr_t H5TS__set_kwd(H5TS_key_t key, const void *value); /* Local Variables */ /*******************/ -#ifdef H5_HAVE_WIN_THREADS -/* Per-thread "key with destructor" ("kwd") info */ -static H5TS_key_t H5TS_win_kwd_info_key_s; - -/* Pointer to global list of thread-specific kwd's */ -static H5TS_win_kwd_node_t *H5TS_win_kwd_list_head_s = NULL; - -/* Mutices for access to H5TS_win_kwd_list_head_s & its sub-lists */ -static H5TS_mutex_t H5TS_win_kwd_list_mtx_s; -static H5TS_mutex_t H5TS_win_kwd_sublist_mtx_s; -#endif #ifdef H5_HAVE_WIN_THREADS -/*-------------------------------------------------------------------------- - * Function: H5TS__win_kwd_init +/*------------------------------------------------------------------------- + * Function: H5TS_key_create * - * Purpose: Initialize thread-local "key with destructors" infrastructure + * Purpose: Thread-local key creation * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__win_kwd_init(void) +H5TS_key_create(H5TS_key_t *key, H5TS_key_destructor_func_t dtor) { herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Initialize the mutices for modifying the kwd list & sub-list */ - H5TS_mutex_init(&H5TS_win_kwd_list_mtx_s); - H5TS_mutex_init(&H5TS_win_kwd_sublist_mtx_s); + /* Sanity check */ + if (H5_UNLIKELY(NULL == key)) + HGOTO_DONE(FAIL); - /* Initialize "base" key for all the thread-specific "keys w/dtors" lists */ - if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (H5TS_win_kwd_info_key_s = TlsAlloc()))) - ret_value = FAIL; + /* Fail if the key has a destructor callback, this is not supported by Windows */ + if (NULL != dtor) + HGOTO_DONE(FAIL); + /* Create the key */ + if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (*key = TlsAlloc()))) + HGOTO_DONE(FAIL); + +done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__win_kwd_init() */ +} /* end H5TS_key_create() */ -/*-------------------------------------------------------------------------- - * Function: H5TS__add_kwd +/*------------------------------------------------------------------------- + * Function: H5TS_key_set_value * - * Purpose: Add a newly created key w/dtor to the global list of keys + * Purpose: Set a thread-specific value for a thread-local key * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ -static herr_t -H5TS__add_kwd(H5TS_key_t key, H5TS_key_destructor_func_t dtor) +herr_t +H5TS_key_set_value(H5TS_key_t key, const void *value) { - H5TS_win_kwd_node_t *kwd_node; - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Sanity checks */ - assert(dtor); - - /* Create the kwd node for the key */ - if (H5_UNLIKELY(NULL == (kwd_node = H5MM_malloc(sizeof(*kwd_node))))) + /* Set the value for this thread */ + if (H5_UNLIKELY(0 != TlsSetValue(key, (LPVOID)value))) HGOTO_DONE(FAIL); - kwd_node->key = key; - kwd_node->dtor = dtor; - - /* Acquire the lock for accessing the kwd list */ - H5TS_mutex_lock(&H5TS_win_kwd_list_mtx_s); - -#ifdef H5TS_DEBUG - { - H5TS_win_kwd_node_t *tmp_kwd_node; - - /* Sanity check that the key isn't already in the list */ - tmp_kwd_node = H5TS_win_kwd_list_head_s; - while (NULL != tmp_kwd_node) { - if (H5_UNLIKELY(key == tmp_kwd_node->key)) - HGOTO_DONE(FAIL); - tmp_kwd_node = tmp_kwd_node->next; - } - } -#endif - - /* Add the kwd node to the list */ - kwd_node->next = H5TS_win_kwd_list_head_s; - H5TS_win_kwd_list_head_s = kwd_node; - - /* Release the lock for accessing the kwd list */ - H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS__add_kwd() */ +} /* end H5TS_key_set_value() */ -/*-------------------------------------------------------------------------- - * Function: H5TS__set_kwd +/*------------------------------------------------------------------------- + * Function: H5TS_key_get_value * - * Purpose: Add a newly set key to the list of keys w/dtors for a thread - * (if the key has a dtor) + * Purpose: Get a thread-specific value for a thread-local key * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ -static herr_t -H5TS__set_kwd(H5TS_key_t key, const void *value) +herr_t +H5TS_key_get_value(H5TS_key_t key, void **value) { - H5TS_win_kwd_node_t *kwd_node; - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Sanity checks */ - assert(value); - - /* Acquire the lock for accessing the kwd list */ - H5TS_mutex_lock(&H5TS_win_kwd_list_mtx_s); + /* Get the value for this thread */ + if (H5_UNLIKELY(NULL == (*value = TlsGetValue(key)))) + /* Check for possible error, when NULL value is returned */ + if (H5_UNLIKELY(ERROR_SUCCESS != GetLastError())) + HGOTO_DONE(FAIL); - /* Search the kwd list for the key */ - kwd_node = H5TS_win_kwd_list_head_s; - while (NULL != kwd_node) { - if (key == kwd_node->key) - break; - kwd_node = kwd_node->next; - } +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_key_get_value() */ - /* Release the lock for accessing the kwd list */ - H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); +/*------------------------------------------------------------------------- + * Function: H5TS_key_delete + * + * Purpose: Thread-local key deletion + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_key_delete(H5TS_key_t key) +{ + herr_t ret_value = SUCCEED; - /* Check if this thread has been inserted already */ - if (NULL != kwd_node) { - H5TS_win_kwd_tid_node_t *kwd_tid_node; - uint64_t thread_id; + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Get the ID for this thread */ - if (H5_UNLIKELY(0 == (thread_id = H5TS_thread_id()))) + /* Delete the key */ + if (TLS_OUT_OF_INDEXES != key) + if (H5_UNLIKELY(0 == TlsFree(key))) HGOTO_DONE(FAIL); - /* Acquire the lock for accessing the kwd sub-list */ - H5TS_mutex_lock(&H5TS_win_kwd_sublist_mtx_s); - - kwd_tid_node = kwd_node->head_tid_node; - while (NULL != kwd_tid_node) { - if (thread_id == kwd_tid_node->tid) - break; - kwd_tid_node = kwd_tid_node->next; - } - - /* Release the lock for accessing the kwd sub-list */ - H5TS_mutex_unlock(&H5TS_win_kwd_sublist_mtx_s); - - /* If this thread isn't in the kwd tid sub-list, add it */ - if (NULL == kwd_tid_node) { - /* Create the kwd tid node for the thread */ - if (H5_UNLIKELY(NULL == (kwd_tid_node = H5MM_calloc(sizeof(*kwd_tid_node))))) - HGOTO_DONE(FAIL); - kwd_tid_node->tid = thread_id; - kwd_tid_node->kwd_node = kwd_node; - - /* Acquire both locks for accessing the kwd list & sub-lists */ - H5TS_mutex_lock(&H5TS_win_kwd_list_mtx_s); - H5TS_mutex_lock(&H5TS_win_kwd_sublist_mtx_s); - - /* Insert the new kwd tid node in the sub-list */ - kwd_tid_node->next = kwd_node->head_tid_node; - if (NULL != kwd_node->head_tid_node) - kwd_node->head_tid_node->prev = kwd_tid_node; - kwd_node->head_tid_node = kwd_tid_node; - - /* Release both locks for accessing the kwd list & sub-lists */ - H5TS_mutex_unlock(&H5TS_win_kwd_sublist_mtx_s); - H5TS_mutex_unlock(&H5TS_win_kwd_list_mtx_s); - } - } - - /* Add the kwd node to the list */ - kwd_node->next = H5TS_win_kwd_list_head_s; - H5TS_win_kwd_list_head_s = kwd_node; - done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* H5TS__add_kwd() */ +} /* end H5TS_key_delete() */ +#else /*------------------------------------------------------------------------- * Function: H5TS_key_create * @@ -284,18 +211,14 @@ H5TS_key_create(H5TS_key_t *key, H5TS_key_destructor_func_t dtor) FUNC_ENTER_NOAPI_NAMECHECK_ONLY + /* Sanity check */ if (H5_UNLIKELY(NULL == key)) HGOTO_DONE(FAIL); /* Create the key */ - if (H5_UNLIKELY(TLS_OUT_OF_INDEXES == (*key = TlsAlloc()))) + if (H5_UNLIKELY(pthread_key_create(key, dtor))) HGOTO_DONE(FAIL); - /* If the key has a destructor callback, add it to the list of keys w/dtors */ - if (NULL != dtor) - if (H5TS__add_kwd(*key, dtor) < 0) - HGOTO_DONE(FAIL); - done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS_key_create() */ @@ -303,7 +226,7 @@ H5TS_key_create(H5TS_key_t *key, H5TS_key_destructor_func_t dtor) /*------------------------------------------------------------------------- * Function: H5TS_key_set_value * - * Purpose: Set a thread-specific value for a key + * Purpose: Set a thread-specific value for a thread-local key * * Return: Non-negative on success / Negative on failure * @@ -317,17 +240,57 @@ H5TS_key_set_value(H5TS_key_t key, const void *value) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Set the value for this thread */ - if (H5_UNLIKELY(0 != TlsSetValue(key, (LPVOID)value))) + if (H5_UNLIKELY(pthread_setspecific(key, value))) HGOTO_DONE(FAIL); - /* Add the key to the kwd list for this thread, if non-NULL */ - if (NULL != value) - if (H5_UNLIKELY(H5TS_set_kwd(key, value))) - HGOTO_DONE(FAIL); +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_key_set_value() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_key_get_value + * + * Purpose: Get a thread-specific value for a thread-local key + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_key_get_value(H5TS_key_t key, void **value) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Get the value for this thread */ + /* NOTE: pthread_getspecific() can't fail */ + *value = pthread_getspecific(key); + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +} /* end H5TS_key_get_value() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_key_delete + * + * Purpose: Thread-local key deletion + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_key_delete(H5TS_key_t key) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Delete the key */ + if (H5_UNLIKELY(pthread_key_delete(key))) + HGOTO_DONE(FAIL); done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS_key_create() */ +} /* end H5TS_key_delete() */ #endif diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index 9f5612e0d60..72c6a9cc8a9 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -39,9 +39,6 @@ #define H5TS_SCOPE_PROCESS 0 /* Portability function aliases */ -#define H5TS__get_thread_local_value(key) TlsGetValue(key) -#define H5TS__set_thread_local_value(key, value) TlsSetValue(key, value) -#define H5TS__key_delete(key) TlsFree(key) #define H5TS__attr_init(attr) 0 #define H5TS__attr_setscope(attr, scope) 0 #define H5TS__attr_destroy(attr) 0 @@ -54,9 +51,6 @@ #define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS /* Portability function aliases */ -#define H5TS__get_thread_local_value(key) pthread_getspecific(key) -#define H5TS__set_thread_local_value(key, value) pthread_setspecific(key, value) -#define H5TS__key_delete(key) pthread_key_delete(key) #define H5TS__attr_init(attr) pthread_attr_init(attr) #define H5TS__attr_setscope(attr, scope) pthread_attr_setscope(attr, scope) #define H5TS__attr_destroy(attr) pthread_attr_destroy(attr) diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index 2072fd90fd4..62244ca2c2c 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -125,6 +125,8 @@ H5_DLL herr_t H5TS_cond_destroy(H5TS_cond_t *cond); /* Thread-specific keys */ H5_DLL herr_t H5TS_key_create(H5TS_key_t *key, H5TS_key_destructor_func_t dtor); H5_DLL herr_t H5TS_key_set_value(H5TS_key_t key, const void *value); +H5_DLL herr_t H5TS_key_get_value(H5TS_key_t key, void **value); +H5_DLL herr_t H5TS_key_delete(H5TS_key_t key); #else /* H5_HAVE_THREADSAFE */ diff --git a/src/H5TSpthread.c b/src/H5TSpthread.c index be7213269a7..08fda499742 100644 --- a/src/H5TSpthread.c +++ b/src/H5TSpthread.c @@ -517,7 +517,7 @@ H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock) if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->writers_cv))) ret_value = FAIL; if (rw_lock->is_key_registered) - if (H5_UNLIKELY(H5TS__key_delete(rw_lock->rec_read_lock_count_key))) + if (H5_UNLIKELY(H5TS_key_delete(rw_lock->rec_read_lock_count_key) < 0)) ret_value = FAIL; done: @@ -560,18 +560,19 @@ H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) /* If there is no thread-specific data for this thread, set it up */ if (!rw_lock->is_key_registered) { - if (H5_UNLIKELY(pthread_key_create(&rw_lock->rec_read_lock_count_key, H5TS__key_destructor))) + if (H5_UNLIKELY(H5TS_key_create(&rw_lock->rec_read_lock_count_key, H5TS__key_destructor))) HGOTO_DONE(FAIL); rw_lock->is_key_registered = true; count = NULL; } else - count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, &count) < 0)) + HGOTO_DONE(FAIL); if (NULL == count) { if (H5_UNLIKELY(NULL == (count = calloc(1, sizeof(*count))))) HGOTO_DONE(FAIL); - if (H5_UNLIKELY(H5TS__set_thread_local_value(rw_lock->rec_read_lock_count_key, (void *)count))) + if (H5_UNLIKELY(H5TS_key_set_value(rw_lock->rec_read_lock_count_key, (void *)count))) HGOTO_DONE(FAIL); } @@ -651,7 +652,8 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) assert(rw_lock->is_key_registered); /* Fail if read lock count for this thread is > 0 */ - count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, &count) < 0)) + HGOTO_DONE(FAIL); if (H5_UNLIKELY(NULL != count && count->rec_lock_count > 0)) HGOTO_DONE(FAIL); } @@ -743,7 +745,8 @@ H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) assert(rw_lock->is_key_registered); assert(rw_lock->active_reader_threads > 0); assert(0 == rw_lock->rec_write_lock_count); - count = (H5TS_rec_entry_count_t *)H5TS__get_thread_local_value(rw_lock->rec_read_lock_count_key); + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, &count) < 0)) + HGOTO_DONE(FAIL); if (H5_UNLIKELY(NULL == count)) HGOTO_DONE(FAIL); assert(count->rec_lock_count > 0); diff --git a/src/H5TSwin.c b/src/H5TSwin.c index 71b182ed1eb..445b5e4c59e 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 @@ -125,8 +128,11 @@ H5TS_win32_thread_enter(void){FUNC_ENTER_NOAPI_NAMECHECK_ONLY * *-------------------------------------------------------------------------- */ -herr_t H5TS_win32_thread_exit(void) +herr_t +H5TS_win32_thread_exit(void) { + herr_t ret_value = SUCCEED; + FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Windows uses a different thread local storage mechanism which does @@ -139,12 +145,16 @@ herr_t H5TS_win32_thread_exit(void) /* Clean up per-thread thread local storage */ if (H5TS_thrd_info_key_g != TLS_OUT_OF_INDEXES) { - LPVOID lpvData = H5TS__get_thread_local_value(H5TS_thrd_info_key_g); + LPVOID lpvData; + + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &lpvData) < 0)) + HGOTO_DONE(FAIL); if (lpvData) H5TS__tinfo_destroy(lpvData); } - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(SUCCEED) +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS_win32_thread_exit() */ #endif /* H5_HAVE_WIN_THREADS */ From 909397788f24d2d0a5ad49637f0951d2561ee6e7 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 15 Mar 2024 18:35:02 -0500 Subject: [PATCH 004/522] Remove thread-local keys from Mercury code, misc. other minor cleanups. Signed-off-by: Quincey Koziol --- .../mercury/src/util/mercury_thread.c | 47 -------- .../mercury/src/util/mercury_thread.h | 111 ------------------ src/H5TSint.c | 6 +- src/H5TSpkg.h | 5 - src/H5TSpthread.c | 26 ++-- 5 files changed, 16 insertions(+), 179 deletions(-) diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c index cfbac49b984..abae1a42282 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c @@ -64,50 +64,3 @@ hg_thread_join(hg_thread_t thread) return HG_UTIL_SUCCESS; } -/*---------------------------------------------------------------------------*/ -int -hg_thread_cancel(hg_thread_t thread) -{ -#ifdef _WIN32 - WaitForSingleObject(thread, 0); - CloseHandle(thread); -#else - if (pthread_cancel(thread)) - return HG_UTIL_FAIL; -#endif - - return HG_UTIL_SUCCESS; -} - -/*---------------------------------------------------------------------------*/ -int -hg_thread_key_create(hg_thread_key_t *key) -{ - if (!key) - return HG_UTIL_FAIL; - -#ifdef _WIN32 - if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES) - return HG_UTIL_FAIL; -#else - if (pthread_key_create(key, NULL)) - return HG_UTIL_FAIL; -#endif - - return HG_UTIL_SUCCESS; -} - -/*---------------------------------------------------------------------------*/ -int -hg_thread_key_delete(hg_thread_key_t key) -{ -#ifdef _WIN32 - if (!TlsFree(key)) - return HG_UTIL_FAIL; -#else - if (pthread_key_delete(key)) - return HG_UTIL_FAIL; -#endif - - return HG_UTIL_SUCCESS; -} diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h index 165ba483804..17bddd0cd5e 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h @@ -20,14 +20,12 @@ typedef HANDLE hg_thread_t; typedef LPTHREAD_START_ROUTINE hg_thread_func_t; typedef DWORD hg_thread_ret_t; #define HG_THREAD_RETURN_TYPE hg_thread_ret_t WINAPI -typedef DWORD hg_thread_key_t; #else #include typedef pthread_t hg_thread_t; typedef void *(*hg_thread_func_t)(void *); typedef void *hg_thread_ret_t; #define HG_THREAD_RETURN_TYPE hg_thread_ret_t -typedef pthread_key_t hg_thread_key_t; #endif #ifdef __cplusplus @@ -70,115 +68,6 @@ void hg_thread_exit(hg_thread_ret_t ret); */ int hg_thread_join(hg_thread_t thread); -/** - * Terminate the thread. - * - * \param thread [IN] thread object - * - * \return Non-negative on success or negative on failure - */ -int hg_thread_cancel(hg_thread_t thread); - -/** - * Obtain handle of the calling thread. - * - * \return - */ -static inline hg_thread_t hg_thread_self(void); - -/** - * Compare thread IDs. - * - * \return Non-zero if equal, zero if not equal - */ -static inline int hg_thread_equal(hg_thread_t t1, hg_thread_t t2); - -/** - * Create a thread-specific data key visible to all threads in the process. - * - * \param key [OUT] pointer to thread key object - * - * \return Non-negative on success or negative on failure - */ -int hg_thread_key_create(hg_thread_key_t *key); - -/** - * Delete a thread-specific data key previously returned by - * hg_thread_key_create(). - * - * \param key [IN] thread key object - * - * \return Non-negative on success or negative on failure - */ -int hg_thread_key_delete(hg_thread_key_t key); - -/** - * Get value from specified key. - * - * \param key [IN] thread key object - * - * \return Pointer to data associated to the key - */ -static inline void *hg_thread_getspecific(hg_thread_key_t key); - -/** - * Set value to specified key. - * - * \param key [IN] thread key object - * \param value [IN] pointer to data that will be associated - * - * \return Non-negative on success or negative on failure - */ -static inline int hg_thread_setspecific(hg_thread_key_t key, const void *value); - -/*---------------------------------------------------------------------------*/ -static inline hg_thread_t -hg_thread_self(void) -{ -#ifdef _WIN32 - return GetCurrentThread(); -#else - return pthread_self(); -#endif -} - -/*---------------------------------------------------------------------------*/ -static inline int -hg_thread_equal(hg_thread_t t1, hg_thread_t t2) -{ -#ifdef _WIN32 - return GetThreadId(t1) == GetThreadId(t2); -#else - return pthread_equal(t1, t2); -#endif -} - -/*---------------------------------------------------------------------------*/ -static inline void * -hg_thread_getspecific(hg_thread_key_t key) -{ -#ifdef _WIN32 - return TlsGetValue(key); -#else - return pthread_getspecific(key); -#endif -} - -/*---------------------------------------------------------------------------*/ -static inline int -hg_thread_setspecific(hg_thread_key_t key, const void *value) -{ -#ifdef _WIN32 - if (!TlsSetValue(key, (LPVOID)value)) - return HG_UTIL_FAIL; -#else - if (pthread_setspecific(key, value)) - return HG_UTIL_FAIL; -#endif - - return HG_UTIL_SUCCESS; -} - #ifdef __cplusplus } #endif diff --git a/src/H5TSint.c b/src/H5TSint.c index 04535e4abf6..dfceea2e905 100644 --- a/src/H5TSint.c +++ b/src/H5TSint.c @@ -377,7 +377,7 @@ H5TS_thread_id(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ - if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &tinfo_node) < 0)) + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) HGOTO_DONE(0); if (NULL == tinfo_node) /* Create thread info for this thread */ @@ -411,7 +411,7 @@ H5TS_get_api_ctx_ptr(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ - if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &tinfo_node) < 0)) + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) HGOTO_DONE(NULL); if (NULL == tinfo_node) /* Create thread info for this thread */ @@ -445,7 +445,7 @@ H5TS_get_err_stack(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY /* Check if info for thread has been created */ - if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, &tinfo_node) < 0)) + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) HGOTO_DONE(NULL); if (NULL == tinfo_node) /* Create thread info for this thread */ diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index 72c6a9cc8a9..9fe428e006a 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -320,11 +320,6 @@ H5_DLL void H5TS__pthread_first_thread_init(void); #endif /* H5_HAVE_WIN_THREADS */ -/* Thread-specific key routines */ -#ifdef H5_HAVE_WIN_THREADS -H5_DLL herr_t H5TS__win_kwd_init(void); -#endif - /* 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); diff --git a/src/H5TSpthread.c b/src/H5TSpthread.c index 08fda499742..900c9017b00 100644 --- a/src/H5TSpthread.c +++ b/src/H5TSpthread.c @@ -506,7 +506,7 @@ H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock) if (H5_UNLIKELY(NULL == rw_lock)) HGOTO_DONE(FAIL); - /* Call the appropriate pthread destroy routines. We are committed + /* Call the appropriate destroy routines. We are committed * to the destroy at this point, so call them all, even if one fails * along the way. */ @@ -538,9 +538,9 @@ herr_t H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) { H5TS_rec_entry_count_t *count; - H5TS_thread_t my_thread_id = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; + H5TS_thread_t my_thread = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY @@ -555,7 +555,7 @@ H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) /* Fail if attempting to acquire a read lock on a thread that holds * a write lock */ - if (H5_UNLIKELY(WRITE == rw_lock->lock_type && pthread_equal(my_thread_id, rw_lock->write_thread))) + if (H5_UNLIKELY(WRITE == rw_lock->lock_type && H5TS_thread_equal(my_thread, rw_lock->write_thread))) HGOTO_DONE(FAIL); /* If there is no thread-specific data for this thread, set it up */ @@ -566,7 +566,7 @@ H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) count = NULL; } else - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, &count) < 0)) + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) HGOTO_DONE(FAIL); if (NULL == count) { if (H5_UNLIKELY(NULL == (count = calloc(1, sizeof(*count))))) @@ -626,9 +626,9 @@ H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) herr_t H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) { - H5TS_thread_t my_thread_id = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; + H5TS_thread_t my_thread = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY @@ -641,7 +641,7 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) have_mutex = true; /* Check for initial write lock request on this thread */ - if (WRITE != rw_lock->lock_type || !pthread_equal(my_thread_id, rw_lock->write_thread)) { + if (WRITE != rw_lock->lock_type || !H5TS_thread_equal(my_thread, rw_lock->write_thread)) { /* Fail if attempting to acquire a write lock on a thread that holds * a read lock */ @@ -652,7 +652,7 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) assert(rw_lock->is_key_registered); /* Fail if read lock count for this thread is > 0 */ - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, &count) < 0)) + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) HGOTO_DONE(FAIL); if (H5_UNLIKELY(NULL != count && count->rec_lock_count > 0)) HGOTO_DONE(FAIL); @@ -677,7 +677,7 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) /* Set lock type & owner thread */ rw_lock->lock_type = WRITE; - rw_lock->write_thread = my_thread_id; + rw_lock->write_thread = my_thread; } /* Increment write lock count for this thread */ @@ -745,7 +745,7 @@ H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) assert(rw_lock->is_key_registered); assert(rw_lock->active_reader_threads > 0); assert(0 == rw_lock->rec_write_lock_count); - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, &count) < 0)) + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) HGOTO_DONE(FAIL); if (H5_UNLIKELY(NULL == count)) HGOTO_DONE(FAIL); From 00450bab674e81091d33050610523aea2d499510 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 23:37:57 +0000 Subject: [PATCH 005/522] Committing clang-format changes --- .../mercury/src/util/mercury_thread.c | 1 - .../mercury/src/util/mercury_thread.h | 2 +- src/H5TSkey.c | 1 - src/H5TSpkg.h | 20 ++++++++-------- src/H5TSpthread.c | 13 +++++----- src/H5TSwin.c | 24 ++++++++----------- 6 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c index abae1a42282..1a1ba740b4a 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.c +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c @@ -63,4 +63,3 @@ hg_thread_join(hg_thread_t thread) return HG_UTIL_SUCCESS; } - diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h index 17bddd0cd5e..91807276ec8 100644 --- a/src/H5FDsubfiling/mercury/src/util/mercury_thread.h +++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h @@ -24,7 +24,7 @@ typedef DWORD hg_thread_ret_t; #include typedef pthread_t hg_thread_t; typedef void *(*hg_thread_func_t)(void *); -typedef void *hg_thread_ret_t; +typedef void *hg_thread_ret_t; #define HG_THREAD_RETURN_TYPE hg_thread_ret_t #endif diff --git a/src/H5TSkey.c b/src/H5TSkey.c index 20a5070cd5b..b8dbc0051a2 100644 --- a/src/H5TSkey.c +++ b/src/H5TSkey.c @@ -85,7 +85,6 @@ static herr_t H5TS__set_kwd(H5TS_key_t key, const void *value); /* Local Variables */ /*******************/ - #ifdef H5_HAVE_WIN_THREADS /*------------------------------------------------------------------------- * Function: H5TS_key_create diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index 9fe428e006a..e64ae3990e5 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -39,22 +39,22 @@ #define H5TS_SCOPE_PROCESS 0 /* Portability function aliases */ -#define H5TS__attr_init(attr) 0 -#define H5TS__attr_setscope(attr, scope) 0 -#define H5TS__attr_destroy(attr) 0 -#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) +#define H5TS__attr_init(attr) 0 +#define H5TS__attr_setscope(attr, scope) 0 +#define H5TS__attr_destroy(attr) 0 +#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) #else /* H5_HAVE_WIN_THREADS */ /* Scope Definitions (Pthreads only) */ -#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM -#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS +#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM +#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS /* Portability function aliases */ -#define H5TS__attr_init(attr) pthread_attr_init(attr) -#define H5TS__attr_setscope(attr, scope) pthread_attr_setscope(attr, scope) -#define H5TS__attr_destroy(attr) pthread_attr_destroy(attr) -#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) +#define H5TS__attr_init(attr) pthread_attr_init(attr) +#define H5TS__attr_setscope(attr, scope) pthread_attr_setscope(attr, scope) +#define H5TS__attr_destroy(attr) pthread_attr_destroy(attr) +#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) #endif /* H5_HAVE_WIN_THREADS */ diff --git a/src/H5TSpthread.c b/src/H5TSpthread.c index 900c9017b00..3c492fbc502 100644 --- a/src/H5TSpthread.c +++ b/src/H5TSpthread.c @@ -565,9 +565,8 @@ H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) rw_lock->is_key_registered = true; count = NULL; } - else - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) - HGOTO_DONE(FAIL); + else if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) + HGOTO_DONE(FAIL); if (NULL == count) { if (H5_UNLIKELY(NULL == (count = calloc(1, sizeof(*count))))) HGOTO_DONE(FAIL); @@ -652,8 +651,8 @@ H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) assert(rw_lock->is_key_registered); /* Fail if read lock count for this thread is > 0 */ - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) - HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) + HGOTO_DONE(FAIL); if (H5_UNLIKELY(NULL != count && count->rec_lock_count > 0)) HGOTO_DONE(FAIL); } @@ -745,8 +744,8 @@ H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) assert(rw_lock->is_key_registered); assert(rw_lock->active_reader_threads > 0); assert(0 == rw_lock->rec_write_lock_count); - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) - HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) + HGOTO_DONE(FAIL); if (H5_UNLIKELY(NULL == count)) HGOTO_DONE(FAIL); assert(count->rec_lock_count > 0); diff --git a/src/H5TSwin.c b/src/H5TSwin.c index 445b5e4c59e..6a879c7fdaa 100644 --- a/src/H5TSwin.c +++ b/src/H5TSwin.c @@ -104,20 +104,17 @@ 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 @@ -128,8 +125,7 @@ H5TS_win32_thread_enter(void) * *-------------------------------------------------------------------------- */ -herr_t -H5TS_win32_thread_exit(void) +herr_t H5TS_win32_thread_exit(void) { herr_t ret_value = SUCCEED; From 047f69e53ce276f0adef0699aa70cab71e759da2 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 17 Mar 2024 09:57:15 -0500 Subject: [PATCH 006/522] Remove PTHREAD_SCOPE_* detection and phtread_attr_*, they date back to Chee-Wai's original checkin and are only used in the test code, and are unnecessary. Signed-off-by: Quincey Koziol --- config/cmake/H5pubconf.h.in | 4 ---- config/cmake/HDFTests.c | 18 ------------------ configure.ac | 36 ------------------------------------ src/H5TSpkg.h | 22 +++------------------- src/H5TStest.c | 4 ++-- test/ttsafe_acreate.c | 2 +- test/ttsafe_attr_vlen.c | 5 ++--- test/ttsafe_cancel.c | 15 +-------------- test/ttsafe_dcreate.c | 14 +------------- test/ttsafe_develop.c | 4 ++-- test/ttsafe_error.c | 12 +----------- test/ttsafe_rec_rw_lock.c | 6 +++--- test/ttsafe_thread_id.c | 2 +- 13 files changed, 17 insertions(+), 127 deletions(-) diff --git a/config/cmake/H5pubconf.h.in b/config/cmake/H5pubconf.h.in index 267781a6d85..5b45817b24a 100644 --- a/config/cmake/H5pubconf.h.in +++ b/config/cmake/H5pubconf.h.in @@ -595,10 +595,6 @@ /* Define if strict file format checks are enabled */ #cmakedefine H5_STRICT_FORMAT_CHECKS @H5_STRICT_FORMAT_CHECKS@ -/* Define if your system supports pthread_attr_setscope(&attribute, - PTHREAD_SCOPE_SYSTEM) call. */ -#cmakedefine H5_SYSTEM_SCOPE_THREADS @H5_SYSTEM_SCOPE_THREADS@ - /* Define using v1.6 public API symbols by default */ #cmakedefine H5_USE_16_API_DEFAULT @H5_USE_16_API_DEFAULT@ diff --git a/config/cmake/HDFTests.c b/config/cmake/HDFTests.c index 90c03a3992d..7b388768932 100644 --- a/config/cmake/HDFTests.c +++ b/config/cmake/HDFTests.c @@ -68,24 +68,6 @@ int main(void) #endif /* PTHREAD_BARRIER */ -#ifdef SYSTEM_SCOPE_THREADS -#include -#include - -int main(void) -{ - pthread_attr_t attribute; - int ret; - - pthread_attr_init(&attribute); - ret = pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM); - if (ret == 0) - return 0; - return 1; -} - -#endif /* SYSTEM_SCOPE_THREADS */ - #ifdef HAVE_SOCKLEN_T #include diff --git a/configure.ac b/configure.ac index 1e49b6fe363..34733360cf2 100644 --- a/configure.ac +++ b/configure.ac @@ -1995,42 +1995,6 @@ if test "X$THREADSAFE" = "Xyes"; then [], [[#include ]]) fi - - ## ---------------------------------------------------------------------- - ## Check if pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM) - ## is supported on this system - ## - ## Unfortunately, this probably needs to be an AC_RUN_IFELSE since - ## it's impossible to determine if PTHREAD_SCOPE_SYSTEM is - ## supported a priori. POSIX.1-2001 requires that a conformant - ## system need only support one of SYSTEM or PROCESS scopes. - ## - ## CROSS-COMPILING: Use a pessimistic 'no'. You can hand-hack the config - ## file if you know otherwise. - AC_MSG_CHECKING([Pthreads supports system scope]) - AC_CACHE_VAL([hdf5_cv_system_scope_threads], - [AC_RUN_IFELSE( - [AC_LANG_PROGRAM([ - #include - #include - ],[ - pthread_attr_t attribute; - int ret; - - pthread_attr_init(&attribute); - ret=pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM); - exit(ret==0 ? 0 : 1); - ])] - , [hdf5_cv_system_scope_threads=yes], [hdf5_cv_system_scope_threads=no], [hdf5_cv_system_scope_threads=no])]) - - if test ${hdf5_cv_system_scope_threads} = "yes"; then - AC_DEFINE([SYSTEM_SCOPE_THREADS], [1], - [Define if your system supports pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM) call.]) - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - AC_MSG_NOTICE([Always 'no' if cross-compiling. Edit the config file if your platform supports pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM).]) - fi fi ## ---------------------------------------------------------------------- diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index e64ae3990e5..ec75b7d6e9c 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -34,27 +34,13 @@ #ifdef H5_HAVE_WIN_THREADS -/* Scope Definitions (Pthreads only) */ -#define H5TS_SCOPE_SYSTEM 0 -#define H5TS_SCOPE_PROCESS 0 - /* Portability function aliases */ -#define H5TS__attr_init(attr) 0 -#define H5TS__attr_setscope(attr, scope) 0 -#define H5TS__attr_destroy(attr) 0 -#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) +#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) #else /* H5_HAVE_WIN_THREADS */ -/* Scope Definitions (Pthreads only) */ -#define H5TS_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM -#define H5TS_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS - /* Portability function aliases */ -#define H5TS__attr_init(attr) pthread_attr_init(attr) -#define H5TS__attr_setscope(attr, scope) pthread_attr_setscope(attr, scope) -#define H5TS__attr_destroy(attr) pthread_attr_destroy(attr) -#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) +#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) #endif /* H5_HAVE_WIN_THREADS */ @@ -65,12 +51,10 @@ /* Portability wrappers */ #ifdef H5_HAVE_WIN_THREADS -typedef HANDLE H5TS_attr_t; typedef INIT_ONCE H5TS_once_t; #else -typedef pthread_attr_t H5TS_attr_t; typedef pthread_once_t H5TS_once_t; #endif /* H5_HAVE_WIN_THREADS */ @@ -348,7 +332,7 @@ H5_DLL herr_t H5TS__rw_lock_print_stats(const char *header_str, H5TS_rw_lock_sta #endif /* Testing routines */ -H5_DLL H5TS_thread_t H5TS__create_thread(void *(*func)(void *), H5TS_attr_t *attr, void *udata); +H5_DLL H5TS_thread_t H5TS__create_thread(void *(*func)(void *), void *udata); #endif /* H5TS_TESTING */ diff --git a/src/H5TStest.c b/src/H5TStest.c index caea665bf51..6a2e346d456 100644 --- a/src/H5TStest.c +++ b/src/H5TStest.c @@ -74,7 +74,7 @@ typedef void *(*H5TS_thread_cb_t)(void *); *-------------------------------------------------------------------------- */ H5TS_thread_t -H5TS__create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata) +H5TS__create_thread(H5TS_thread_cb_t func, void *udata) { H5TS_thread_t ret_value; @@ -95,7 +95,7 @@ H5TS__create_thread(H5TS_thread_cb_t func, H5TS_attr_t *attr, void *udata) #else /* H5_HAVE_WIN_THREADS */ - pthread_create(&ret_value, attr, (void *(*)(void *))func, udata); + pthread_create(&ret_value, NULL, (void *(*)(void *))func, udata); #endif /* H5_HAVE_WIN_THREADS */ diff --git a/test/ttsafe_acreate.c b/test/ttsafe_acreate.c index 83b94923b6e..44cfc6c688a 100644 --- a/test/ttsafe_acreate.c +++ b/test/ttsafe_acreate.c @@ -102,7 +102,7 @@ tts_acreate(void) attrib_data->datatype = datatype; attrib_data->dataspace = dataspace; attrib_data->current_index = i; - threads[i] = H5TS__create_thread(tts_acreate_thread, NULL, attrib_data); + threads[i] = H5TS__create_thread(tts_acreate_thread, attrib_data); } for (i = 0; i < NUM_THREADS; i++) diff --git a/test/ttsafe_attr_vlen.c b/test/ttsafe_attr_vlen.c index 2c577a5e13d..a8fd0d6df6e 100644 --- a/test/ttsafe_attr_vlen.c +++ b/test/ttsafe_attr_vlen.c @@ -105,9 +105,8 @@ tts_attr_vlen(void) CHECK(ret, H5I_INVALID_HID, "H5Tclose"); /* Start multiple threads and execute tts_attr_vlen_thread() for each thread */ - for (i = 0; i < NUM_THREADS; i++) { - threads[i] = H5TS__create_thread(tts_attr_vlen_thread, NULL, NULL); - } + for (i = 0; i < NUM_THREADS; i++) + threads[i] = H5TS__create_thread(tts_attr_vlen_thread, NULL); /* Wait for the threads to end */ for (i = 0; i < NUM_THREADS; i++) diff --git a/test/ttsafe_cancel.c b/test/ttsafe_cancel.c index 755df305edc..dad019270ba 100644 --- a/test/ttsafe_cancel.c +++ b/test/ttsafe_cancel.c @@ -54,19 +54,10 @@ pthread_cond_t cond; void tts_cancel(void) { - pthread_attr_t attribute; hid_t dataset; int buffer; int H5_ATTR_NDEBUG_UNUSED ret; - /* make thread scheduling global */ - ret = pthread_attr_init(&attribute); - assert(ret == 0); -#ifdef H5_HAVE_SYSTEM_SCOPE_THREADS - ret = pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM); - assert(ret == 0); -#endif /* H5_HAVE_SYSTEM_SCOPE_THREADS */ - /* Initialize mutex & condition variables */ ret = pthread_mutex_init(&mutex, NULL); assert(ret == 0); @@ -79,7 +70,7 @@ tts_cancel(void) */ cancel_file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); assert(cancel_file >= 0); - ret = pthread_create(&childthread, &attribute, tts_cancel_thread, NULL); + ret = pthread_create(&childthread, NULL, tts_cancel_thread, NULL); assert(ret == 0); tts_cancel_barrier(); ret = pthread_cancel(childthread); @@ -97,10 +88,6 @@ tts_cancel(void) assert(ret >= 0); ret = H5Fclose(cancel_file); assert(ret >= 0); - - /* Destroy the thread attribute */ - ret = pthread_attr_destroy(&attribute); - assert(ret == 0); } /* end tts_cancel() */ void * diff --git a/test/ttsafe_dcreate.c b/test/ttsafe_dcreate.c index a4dfda81283..cab07ccfde6 100644 --- a/test/ttsafe_dcreate.c +++ b/test/ttsafe_dcreate.c @@ -63,17 +63,8 @@ tts_dcreate(void) hid_t file = H5I_INVALID_HID; hid_t dataset = H5I_INVALID_HID; int datavalue, i; - H5TS_attr_t attribute; herr_t status; - /* set pthread attribute to perform global scheduling */ - H5TS__attr_init(&attribute); - - /* set thread scope to system */ -#ifdef H5_HAVE_SYSTEM_SCOPE_THREADS - H5TS__attr_setscope(&attribute, H5TS_SCOPE_SYSTEM); -#endif /* H5_HAVE_SYSTEM_SCOPE_THREADS */ - /* * Create a hdf5 file using H5F_ACC_TRUNC access, default file * creation plist and default file access plist @@ -86,7 +77,7 @@ tts_dcreate(void) thread_out[i].id = i; thread_out[i].file = file; thread_out[i].dsetname = dsetname[i]; - threads[i] = H5TS__create_thread(tts_dcreate_creator, NULL, &thread_out[i]); + threads[i] = H5TS__create_thread(tts_dcreate_creator, &thread_out[i]); } for (i = 0; i < NUM_THREAD; i++) @@ -122,9 +113,6 @@ tts_dcreate(void) /* close remaining resources */ status = H5Fclose(file); CHECK(status, FAIL, "H5Fclose"); - - /* Destroy the thread attribute */ - H5TS__attr_destroy(&attribute); } /* end tts_dcreate() */ void * diff --git a/test/ttsafe_develop.c b/test/ttsafe_develop.c index fe1832e0abe..a86219df5b9 100644 --- a/test/ttsafe_develop.c +++ b/test/ttsafe_develop.c @@ -124,8 +124,8 @@ tts_develop_api(void) /* Create the threads */ udata.barrier = &barrier; - thread_1 = H5TS__create_thread(tts_develop_api_thr_1, NULL, &udata); - thread_2 = H5TS__create_thread(tts_develop_api_thr_2, NULL, &udata); + thread_1 = H5TS__create_thread(tts_develop_api_thr_1, &udata); + thread_2 = H5TS__create_thread(tts_develop_api_thr_2, &udata); /* Wait for threads to complete. */ H5TS__wait_for_thread(thread_1); diff --git a/test/ttsafe_error.c b/test/ttsafe_error.c index 7b39af38a30..1ea89bd1c64 100644 --- a/test/ttsafe_error.c +++ b/test/ttsafe_error.c @@ -62,7 +62,6 @@ tts_error(void) hid_t vol_id = H5I_INVALID_HID; hid_t dataset = H5I_INVALID_HID; H5TS_thread_t threads[NUM_THREAD]; - H5TS_attr_t attribute; int value, i; herr_t status; @@ -103,14 +102,6 @@ tts_error(void) /* set up mutex for global count of errors */ H5TS_mutex_init(&error_mutex_g); - /* make thread scheduling global */ - H5TS__attr_init(&attribute); - -#ifdef H5_HAVE_SYSTEM_SCOPE_THREADS - /* set thread scope to system */ - H5TS__attr_setscope(&attribute, H5TS_SCOPE_SYSTEM); -#endif /* H5_HAVE_SYSTEM_SCOPE_THREADS */ - def_fapl = H5Pcreate(H5P_FILE_ACCESS); CHECK(def_fapl, H5I_INVALID_HID, "H5Pcreate"); @@ -125,7 +116,7 @@ tts_error(void) CHECK(error_file_g, H5I_INVALID_HID, "H5Fcreate"); for (i = 0; i < NUM_THREAD; i++) - threads[i] = H5TS__create_thread(tts_error_thread, &attribute, NULL); + threads[i] = H5TS__create_thread(tts_error_thread, NULL); for (i = 0; i < NUM_THREAD; i++) H5TS__wait_for_thread(threads[i]); @@ -160,7 +151,6 @@ tts_error(void) status = H5Idec_ref(vol_id); CHECK(status, FAIL, "H5Idec_ref"); - H5TS__attr_destroy(&attribute); H5TS_mutex_destroy(&error_mutex_g); } /* end tts_error() */ diff --git a/test/ttsafe_rec_rw_lock.c b/test/ttsafe_rec_rw_lock.c index b6da4b74ef6..5af75d241da 100644 --- a/test/ttsafe_rec_rw_lock.c +++ b/test/ttsafe_rec_rw_lock.c @@ -610,7 +610,7 @@ tts_rec_rw_lock_smoke_check_2(void) uint64_t start_time = H5_now_usec(); /* 3) Create the reader threads, each with its own user data. */ for (i = 0; i < num_threads; i++) - threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &udata[i]); + threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, &udata[i]); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) @@ -809,7 +809,7 @@ tts_rec_rw_lock_smoke_check_3(void) uint64_t start_time = H5_now_usec(); /* 3) Create the writer threads, each with its own user data. */ for (i = 0; i < num_threads; i++) - threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &(udata[i])); + threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, &udata[i]); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) @@ -1009,7 +1009,7 @@ tts_rec_rw_lock_smoke_check_4(void) uint64_t start_time = H5_now_usec(); /* 3) Create the reader threads, each with its own user data. */ for (i = 0; i < num_threads; i++) - threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, NULL, &(udata[i])); + threads[i] = H5TS__create_thread(tts_rw_lock_smoke_check_test_thread, &udata[i]); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) diff --git a/test/ttsafe_thread_id.c b/test/ttsafe_thread_id.c index 1d48da58915..73f81552c97 100644 --- a/test/ttsafe_thread_id.c +++ b/test/ttsafe_thread_id.c @@ -116,7 +116,7 @@ tts_thread_id(void) memset(used, 0, sizeof(used)); for (times = 0; times < CYCLE_COUNT; times++) { for (i = 0; i < NTHREADS; i++) - threads[i] = H5TS__create_thread(thread_main, NULL, NULL); + threads[i] = H5TS__create_thread(thread_main, NULL); for (i = 0; i < NTHREADS; i++) H5TS__wait_for_thread(threads[i]); From 52b12ba8cfd9555341e31bcc7faa53485a516a2b Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 17 Mar 2024 14:59:08 +0000 Subject: [PATCH 007/522] Committing clang-format changes --- src/H5TSpkg.h | 4 ++-- test/ttsafe_dcreate.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index ec75b7d6e9c..6130daa76be 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -35,12 +35,12 @@ #ifdef H5_HAVE_WIN_THREADS /* Portability function aliases */ -#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) +#define H5TS__wait_for_thread(thread) WaitForSingleObject(thread, INFINITE) #else /* H5_HAVE_WIN_THREADS */ /* Portability function aliases */ -#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) +#define H5TS__wait_for_thread(thread) pthread_join(thread, NULL) #endif /* H5_HAVE_WIN_THREADS */ diff --git a/test/ttsafe_dcreate.c b/test/ttsafe_dcreate.c index cab07ccfde6..9056988a333 100644 --- a/test/ttsafe_dcreate.c +++ b/test/ttsafe_dcreate.c @@ -60,10 +60,10 @@ tts_dcreate(void) H5TS_thread_t threads[NUM_THREAD]; /* HDF5 data definitions */ - hid_t file = H5I_INVALID_HID; - hid_t dataset = H5I_INVALID_HID; - int datavalue, i; - herr_t status; + hid_t file = H5I_INVALID_HID; + hid_t dataset = H5I_INVALID_HID; + int datavalue, i; + herr_t status; /* * Create a hdf5 file using H5F_ACC_TRUNC access, default file From f5b174a132055b5c9e02b158823b668933e2ea26 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Mon, 18 Mar 2024 23:36:46 -0500 Subject: [PATCH 008/522] Add support for _Float16 16-bit floating point type (#4065) Fixed some conversion issues with Clang due to problematic undefined behavior when casting a negative floating-point value to an integer Fixed a bug in the library's software integer to floating-point conversion function where a user's conversion exception function returning H5T_CONV_UNHANDLED in the case of overflows would result in incorrect data after conversion Added configure checks for functions and macros related to _Float16 usage since some compilers expose the datatype but not the functions or macros Fixed a dt_arith test failure when H5_WANT_DCONV_EXCEPTION isn't defined Fixed a few warnings from not explicitly casting some _Float16 variables upwards --- config/cmake/ConfigureChecks.cmake | 83 +- config/cmake/ConversionTests.c | 122 ++ config/cmake/H5pubconf.h.in | 12 + configure.ac | 103 ++ doxygen/dox/DDLBNF112.dox | 2 +- doxygen/dox/DDLBNF114.dox | 654 ++++++++++ doxygen/dox/IntroHDF5.dox | 2 +- doxygen/dox/LearnBasics1.dox | 4 +- doxygen/dox/LearnBasics2.dox | 5 + doxygen/dox/Specifications.dox | 1 + .../examples/tables/predefinedDatatypes.dox | 12 + hl/src/H5LT.c | 13 +- hl/src/H5LTanalyze.c | 456 +++---- hl/src/H5LTanalyze.l | 3 + hl/src/H5LTparse.c | 789 ++++++------ hl/src/H5LTparse.h | 63 +- hl/src/H5LTparse.y | 8 +- java/src/hdf/hdf5lib/HDF5Constants.java | 12 + java/src/jni/h5Constants.c | 15 + java/src/jni/h5util.c | 8 +- release_docs/RELEASE.txt | 119 ++ src/H5Fmodule.h | 2 +- src/H5Gmodule.h | 2 +- src/H5T.c | 570 ++++++--- src/H5Tconv.c | 435 ++++++- src/H5Tinit_float.c | 48 +- src/H5Tmodule.h | 19 +- src/H5Tnative.c | 28 +- src/H5Tpkg.h | 96 ++ src/H5Tpublic.h | 19 + src/H5private.h | 38 +- src/H5trace.c | 8 + test/API/H5_api_dataset_test.c | 10 +- test/API/H5_api_test_util.c | 14 +- test/dt_arith.c | 1062 +++++++++++++++-- test/dtypes.c | 425 ++++++- test/ntypes.c | 121 ++ tools/lib/h5diff_array.c | 265 +++- tools/lib/h5diff_util.c | 10 +- tools/lib/h5tools_dump.c | 10 +- tools/lib/h5tools_str.c | 12 +- tools/lib/h5tools_type.c | 8 +- tools/src/h5import/h5import.c | 108 ++ tools/src/h5ls/h5ls.c | 13 +- tools/test/h5dump/CMakeTests.cmake | 8 + tools/test/h5dump/CMakeTestsXML.cmake | 8 + tools/test/h5dump/expected/tfloat16.ddl | 46 + tools/test/h5dump/expected/tfloat16_be.ddl | 46 + .../test/h5dump/expected/xml/tfloat16.h5.xml | 302 +++++ .../h5dump/expected/xml/tfloat16_be.h5.xml | 302 +++++ tools/test/h5dump/h5dumpgentest.c | 163 +++ tools/test/h5dump/testfiles/tfloat16.h5 | Bin 0 -> 2304 bytes tools/test/h5dump/testfiles/tfloat16_be.h5 | Bin 0 -> 2304 bytes tools/test/h5dump/testh5dump.sh.in | 8 + tools/test/h5dump/testh5dumpxml.sh.in | 8 + tools/test/h5ls/CMakeTests.cmake | 33 + tools/test/h5ls/expected/tfloat16.ls | 8 + tools/test/h5ls/expected/tfloat16_be.ls | 8 + .../h5ls/expected/tfloat16_be_nosupport.ls | 8 + .../test/h5ls/expected/tfloat16_nosupport.ls | 8 + tools/test/h5ls/testh5ls.sh.in | 22 +- 61 files changed, 5765 insertions(+), 1022 deletions(-) create mode 100644 doxygen/dox/DDLBNF114.dox create mode 100644 tools/test/h5dump/expected/tfloat16.ddl create mode 100644 tools/test/h5dump/expected/tfloat16_be.ddl create mode 100644 tools/test/h5dump/expected/xml/tfloat16.h5.xml create mode 100644 tools/test/h5dump/expected/xml/tfloat16_be.h5.xml create mode 100644 tools/test/h5dump/testfiles/tfloat16.h5 create mode 100644 tools/test/h5dump/testfiles/tfloat16_be.h5 create mode 100644 tools/test/h5ls/expected/tfloat16.ls create mode 100644 tools/test/h5ls/expected/tfloat16_be.ls create mode 100644 tools/test/h5ls/expected/tfloat16_be_nosupport.ls create mode 100644 tools/test/h5ls/expected/tfloat16_nosupport.ls diff --git a/config/cmake/ConfigureChecks.cmake b/config/cmake/ConfigureChecks.cmake index 07a358f169e..003ecdbd234 100644 --- a/config/cmake/ConfigureChecks.cmake +++ b/config/cmake/ConfigureChecks.cmake @@ -804,7 +804,8 @@ macro (H5ConversionTests TEST def msg) ${CMAKE_BINARY_DIR} ${HDF_RESOURCES_DIR}/ConversionTests.c CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=-D${TEST}_TEST - OUTPUT_VARIABLE OUTPUT + COMPILE_OUTPUT_VARIABLE ${TEST}_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE ${TEST}_RUN_OUTPUT ) if (${TEST}_COMPILE) if (${TEST}_RUN EQUAL "0") @@ -814,14 +815,17 @@ macro (H5ConversionTests TEST def msg) set (${TEST} "" CACHE INTERNAL ${msg}) message (VERBOSE "${msg}... no") file (APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log - "Test ${TEST} Run failed with the following output and exit code:\n ${OUTPUT}\n" + "Test ${TEST} Compile succeeded with the following output:\n ${${TEST}_COMPILE_OUTPUT}\n" + ) + file (APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log + "Test ${TEST} Run failed with exit code ${${TEST}_RUN} and with the following output:\n ${${TEST}_RUN_OUTPUT}\n" ) endif () else () set (${TEST} "" CACHE INTERNAL ${msg}) message (VERBOSE "${msg}... no") file (APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log - "Test ${TEST} Compile failed with the following output:\n ${OUTPUT}\n" + "Test ${TEST} Compile failed with the following output:\n ${${TEST}_COMPILE_OUTPUT}\n" ) endif () else () @@ -883,3 +887,76 @@ H5ConversionTests (${HDF_PREFIX}_LLONG_TO_LDOUBLE_CORRECT TRUE "Checking IF corr # some long double values #----------------------------------------------------------------------------- H5ConversionTests (${HDF_PREFIX}_DISABLE_SOME_LDOUBLE_CONV FALSE "Checking IF the cpu is power9 and cannot correctly converting long double values") + +#----------------------------------------------------------------------------- +# Check if _Float16 type is available +#----------------------------------------------------------------------------- +message (STATUS "Checking if _Float16 support is available") +set (${HDF_PREFIX}_HAVE__FLOAT16 0) +HDF_CHECK_TYPE_SIZE (_Float16 ${HDF_PREFIX}_SIZEOF__FLOAT16) +if (${HDF_PREFIX}_SIZEOF__FLOAT16) + # Request _Float16 support + set (CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} "-D__STDC_WANT_IEC_60559_TYPES_EXT__") + + # Some compilers expose the _Float16 datatype, but not the macros and + # functions used with the datatype. We need the macros for proper + # datatype conversion support. Check for these here. + CHECK_SYMBOL_EXISTS (FLT16_EPSILON "float.h" h5_have_flt16_epsilon) + CHECK_SYMBOL_EXISTS (FLT16_MIN "float.h" h5_have_flt16_min) + CHECK_SYMBOL_EXISTS (FLT16_MAX "float.h" h5_have_flt16_max) + CHECK_SYMBOL_EXISTS (FLT16_MIN_10_EXP "float.h" h5_have_flt16_min_10_exp) + CHECK_SYMBOL_EXISTS (FLT16_MAX_10_EXP "float.h" h5_have_flt16_max_10_exp) + CHECK_SYMBOL_EXISTS (FLT16_MANT_DIG "float.h" h5_have_flt16_mant_dig) + + if (h5_have_flt16_epsilon AND h5_have_flt16_min AND + h5_have_flt16_max AND h5_have_flt16_min_10_exp AND + h5_have_flt16_max_10_exp AND h5_have_flt16_mant_dig) + # Some compilers like OneAPI on Windows appear to detect _Float16 support + # properly up to this point, and, in the absence of any architecture-specific + # tuning compiler flags, will generate code for H5Tconv.c that performs + # software conversions on _Float16 variables with compiler-internal functions + # such as __extendhfsf2, __truncsfhf2, or __truncdfhf2. However, these + # compilers will fail to link these functions into the build for currently + # unknown reasons and cause the build to fail. Since these are compiler-internal + # functions that we don't appear to have much control over, let's try to + # compile a program that will generate these functions to check for _Float16 + # support. If we fail to compile this program, we will simply disable + # _Float16 support for the time being. + H5ConversionTests ( + ${HDF_PREFIX}_FLOAT16_CONVERSION_FUNCS_LINK + FALSE + "Checking if compiler can convert _Float16 type with casts" + ) + + if (${${HDF_PREFIX}_FLOAT16_CONVERSION_FUNCS_LINK}) + # Finally, MacOS 13 appears to have a bug specifically when converting + # long double values to _Float16. Release builds of the dt_arith test + # would cause any assignments to a _Float16 variable to be elided, + # whereas Debug builds would perform incorrect hardware conversions by + # simply chopping off all the bytes of the value except for the first 2. + # These tests pass on MacOS 14, so let's perform a quick test to check + # if the hardware conversion is done correctly. + H5ConversionTests ( + ${HDF_PREFIX}_LDOUBLE_TO_FLOAT16_CORRECT + TRUE + "Checking if correctly converting long double to _Float16 values" + ) + + if (NOT ${${HDF_PREFIX}_LDOUBLE_TO_FLOAT16_CORRECT}) + message (VERBOSE "Conversions from long double to _Float16 appear to be incorrect. These will be emulated through a soft conversion function.") + endif () + + set (${HDF_PREFIX}_HAVE__FLOAT16 1) + + # Check if we can use fabsf16 + CHECK_FUNCTION_EXISTS (fabsf16 ${HDF_PREFIX}_HAVE_FABSF16) + else () + message (STATUS "_Float16 support has been disabled because the compiler couldn't compile and run a test program for _Float16 conversions") + message (STATUS "Check ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log for information on why the test program couldn't be compiled/run") + endif () + else () + message (STATUS "_Float16 support has been disabled since the required macros (FLT16_MAX, FLT16_EPSILON, etc. were not found)") + endif () +else () + message (STATUS "_Float16 support has been disabled since the _Float16 type was not found") +endif () diff --git a/config/cmake/ConversionTests.c b/config/cmake/ConversionTests.c index 725f0496f01..8e103bd3e97 100644 --- a/config/cmake/ConversionTests.c +++ b/config/cmake/ConversionTests.c @@ -285,3 +285,125 @@ int HDF_NO_UBSAN main(void) } #endif + +#ifdef H5_FLOAT16_CONVERSION_FUNCS_LINK_TEST + +#define __STDC_WANT_IEC_60559_TYPES_EXT__ + +#include +#include + +int HDF_NO_UBSAN main(void) +{ + _Float16 fl16_var; + signed char sc; + unsigned char usc; + short s; + unsigned short us; + int i; + unsigned int ui; + long l; + unsigned long ul; + long long ll; + unsigned long long ull; + float f; + double d; + long double ld; + int ret = 0; + + /* + * Cast the _Float16 type between all the different C datatypes + * we support conversions for in H5Tconv.c to check if the compiler + * properly links any software conversion functions it may generate + * for the casts, such as __extendhfsf2 or __truncdfhf2. + */ + + fl16_var = 3.0f16; + + sc = (signed char)fl16_var; + usc = (unsigned char)fl16_var; + s = (short)fl16_var; + us = (unsigned short)fl16_var; + i = (int)fl16_var; + ui = (unsigned int)fl16_var; + l = (long)fl16_var; + ul = (unsigned long)fl16_var; + ll = (long long)fl16_var; + ull = (unsigned long long)fl16_var; + f = (float)fl16_var; + d = (double)fl16_var; + ld = (long double)fl16_var; + + sc = (signed char)3; + fl16_var = (_Float16)sc; + + usc = (unsigned char)3; + fl16_var = (_Float16)usc; + + s = (short)3; + fl16_var = (_Float16)s; + + us = (unsigned short)3; + fl16_var = (_Float16)us; + + i = (int)3; + fl16_var = (_Float16)i; + + ui = (unsigned int)3; + fl16_var = (_Float16)ui; + + l = (long)3; + fl16_var = (_Float16)l; + + ul = (unsigned long)3; + fl16_var = (_Float16)ul; + + ll = (long long)3; + fl16_var = (_Float16)ll; + + ull = (unsigned long long)3; + fl16_var = (_Float16)ull; + + f = (float)3.0f; + fl16_var = (_Float16)f; + + d = (double)3.0; + fl16_var = (_Float16)d; + + ld = (long double)3.0l; + fl16_var = (_Float16)ld; + +done: + exit(ret); +} + +#endif + +#ifdef H5_LDOUBLE_TO_FLOAT16_CORRECT_TEST + +#define __STDC_WANT_IEC_60559_TYPES_EXT__ + +#include +#include +#include +#include + +int HDF_NO_UBSAN main(void) +{ + long double ld; + _Float16 half; + int ret = 1; + + ld = 32.0L; + half = 64.0f16; + + half = (_Float16)ld; + + if (fabsl(ld - (long double)half) < LDBL_EPSILON) + ret = 0; + +done: + exit(ret); +} + +#endif diff --git a/config/cmake/H5pubconf.h.in b/config/cmake/H5pubconf.h.in index 5a962e05afd..af36c014d11 100644 --- a/config/cmake/H5pubconf.h.in +++ b/config/cmake/H5pubconf.h.in @@ -128,6 +128,9 @@ /* Define if library information should be embedded in the executables */ #cmakedefine H5_HAVE_EMBEDDED_LIBINFO @H5_HAVE_EMBEDDED_LIBINFO@ +/* Define to 1 if you have the `fabsf16' function. */ +#cmakedefine H5_HAVE_FABSF16 @H5_HAVE_FABSF16@ + /* Define to 1 if you have the `fcntl' function. */ #cmakedefine H5_HAVE_FCNTL @H5_HAVE_FCNTL@ @@ -140,6 +143,9 @@ /* Define if support for szip filter is enabled */ #cmakedefine H5_HAVE_FILTER_SZIP @H5_HAVE_FILTER_SZIP@ +/* Determine if _Float16 is available */ +#cmakedefine H5_HAVE__FLOAT16 @H5_HAVE__FLOAT16@ + /* Determine if __float128 is available */ #cmakedefine H5_HAVE_FLOAT128 @H5_HAVE_FLOAT128@ @@ -381,6 +387,9 @@ /* Define if new-style references should be used with dimension scales */ #cmakedefine H5_DIMENSION_SCALES_WITH_NEW_REF @H5_DIMENSION_SCALES_WITH_NEW_REF@ +/* Define if your system can convert long double to _Float16 values correctly. */ +#cmakedefine H5_LDOUBLE_TO_FLOAT16_CORRECT @H5_LDOUBLE_TO_FLOAT16_CORRECT@ + /* Define if your system can convert long double to (unsigned) long long values correctly. */ #cmakedefine H5_LDOUBLE_TO_LLONG_ACCURATE @H5_LDOUBLE_TO_LLONG_ACCURATE@ @@ -583,6 +592,9 @@ /* The size of `_Quad', as computed by sizeof. */ #define H5_SIZEOF__QUAD @H5_SIZEOF__QUAD@ +/* The size of `_Float16', as computed by sizeof. */ +#define H5_SIZEOF__FLOAT16 @H5_SIZEOF__FLOAT16@ + /* The size of `__float128', as computed by sizeof. */ #define H5_SIZEOF___FLOAT128 @H5_SIZEOF___FLOAT128@ diff --git a/configure.ac b/configure.ac index 34733360cf2..71037ea5c06 100644 --- a/configure.ac +++ b/configure.ac @@ -559,6 +559,109 @@ AC_CHECK_SIZEOF([float]) AC_CHECK_SIZEOF([double]) AC_CHECK_SIZEOF([long double]) +## ---------------------------------------------------------------------- +## Check if _Float16 support is available +## +AC_MSG_NOTICE([checking if _Float16 support is available]) +HAVE__FLOAT16="no" +AC_CHECK_SIZEOF([_Float16]) +if test "$ac_cv_sizeof__Float16" != 0; then + # Some compilers expose the _Float16 datatype, but not the macros and + # functions used with the datatype. We need the macros for proper + # datatype conversion support. Check for these here. + AC_CHECK_DECL([FLT16_EPSILON], [], [], [[ + #define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include ]]) + AC_CHECK_DECL([FLT16_MIN], [], [], [[ + #define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include ]]) + AC_CHECK_DECL([FLT16_MAX], [], [], [[ + #define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include ]]) + AC_CHECK_DECL([FLT16_MIN_10_EXP], [], [], [[ + #define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include ]]) + AC_CHECK_DECL([FLT16_MAX_10_EXP], [], [], [[ + #define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include ]]) + AC_CHECK_DECL([FLT16_MANT_DIG], [], [], [[ + #define __STDC_WANT_IEC_60559_TYPES_EXT__ + #include ]]) + + if test "X$ac_cv_have_decl_FLT16_EPSILON" = "Xyes" && + test "X$ac_cv_have_decl_FLT16_MIN" = "Xyes" && + test "X$ac_cv_have_decl_FLT16_MAX" = "Xyes" && + test "X$ac_cv_have_decl_FLT16_MIN_10_EXP" = "Xyes" && + test "X$ac_cv_have_decl_FLT16_MAX_10_EXP" = "Xyes" && + test "X$ac_cv_have_decl_FLT16_MANT_DIG" = "Xyes" ; then + # Some compilers like OneAPI on Windows appear to detect _Float16 support + # properly up to this point, and, in the absence of any architecture-specific + # tuning compiler flags, will generate code for H5Tconv.c that performs + # software conversions on _Float16 variables with compiler-internal functions + # such as __extendhfsf2, __truncsfhf2, or __truncdfhf2. However, these + # compilers will fail to link these functions into the build for currently + # unknown reasons and cause the build to fail. Since these are compiler-internal + # functions that we don't appear to have much control over, let's try to + # compile a program that will generate these functions to check for _Float16 + # support. If we fail to compile this program, we will simply disable + # _Float16 support for the time being. + AC_MSG_CHECKING([if compiler can correctly compile and run a test program which converts _Float16 to other types with casts]) + TEST_SRC="`(echo \"#define H5_FLOAT16_CONVERSION_FUNCS_LINK_TEST 1\"; cat $srcdir/config/cmake/ConversionTests.c)`" + AC_CACHE_VAL([hdf5_cv_float16_conversion_funcs_link], + [AC_RUN_IFELSE( + [AC_LANG_SOURCE([$TEST_SRC])], + [hdf5_cv_float16_conversion_funcs_link=yes], [hdf5_cv_float16_conversion_funcs_link=no], [hdf5_cv_float16_conversion_funcs_link=no])]) + + if test ${hdf5_cv_float16_conversion_funcs_link} = "yes"; then + AC_MSG_RESULT([yes]) + + # Finally, MacOS 13 appears to have a bug specifically when converting + # long double values to _Float16. Release builds of the dt_arith test + # would cause any assignments to a _Float16 variable to be elided, + # whereas Debug builds would perform incorrect hardware conversions by + # simply chopping off all the bytes of the value except for the first 2. + # These tests pass on MacOS 14, so let's perform a quick test to check + # if the hardware conversion is done correctly. + AC_MSG_CHECKING([if compiler can correctly convert long double values to _Float16]) + TEST_SRC="`(echo \"#define H5_LDOUBLE_TO_FLOAT16_CORRECT_TEST 1\"; cat $srcdir/config/cmake/ConversionTests.c)`" + if test ${ac_cv_sizeof_long_double} = 0; then + hdf5_cv_ldouble_to_float16_correct=${hdf5_cv_ldouble_to_float16_correct=no} + else + AC_CACHE_VAL([hdf5_cv_ldouble_to_float16_correct], + [AC_RUN_IFELSE( + [AC_LANG_SOURCE([$TEST_SRC])], + [hdf5_cv_ldouble_to_float16_correct=yes], [hdf5_cv_ldouble_to_float16_correct=no], [hdf5_cv_ldouble_to_float16_correct=yes])]) + fi + + if test ${hdf5_cv_ldouble_to_float16_correct} = "yes"; then + AC_DEFINE([LDOUBLE_TO_FLOAT16_CORRECT], [1], + [Define if your system can convert long double to _Float16 values correctly.]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_NOTICE([Conversions from long double to _Float16 appear to be incorrect. These will be emulated through a soft conversion function.]) + fi + + HAVE__FLOAT16="yes" + + # Check if we can use fabsf16 + AC_CHECK_FUNC([fabsf16], [AC_DEFINE([HAVE_FABSF16], [1], + [Define if has fabsf16 function])], []) + + # Define HAVE__FLOAT16 macro for H5pubconf.h if _Float16 is available. + AC_DEFINE([HAVE__FLOAT16], [1], [Determine if _Float16 is available]) + else + AC_MSG_RESULT([no]) + fi + fi + + AC_MSG_CHECKING([if _Float16 support is enabled]) + AC_MSG_RESULT([$HAVE__FLOAT16]) +fi + +# Define HAVE__FLOAT16 value to substitute into other files for conditional testing +AC_SUBST([HAVE__FLOAT16]) + ## ---------------------------------------------------------------------- ## Check if the Fortran interface should be enabled ## diff --git a/doxygen/dox/DDLBNF112.dox b/doxygen/dox/DDLBNF112.dox index 6809a0632ff..cfe34c321f9 100644 --- a/doxygen/dox/DDLBNF112.dox +++ b/doxygen/dox/DDLBNF112.dox @@ -1,4 +1,4 @@ -/** \page DDLBNF112 DDL in BNF for HDF5 1.12 and above +/** \page DDLBNF112 DDL in BNF for HDF5 1.12 through HDF5 1.14.3 \todo Revise this & break it up! diff --git a/doxygen/dox/DDLBNF114.dox b/doxygen/dox/DDLBNF114.dox new file mode 100644 index 00000000000..61e9157e560 --- /dev/null +++ b/doxygen/dox/DDLBNF114.dox @@ -0,0 +1,654 @@ +/** \page DDLBNF114 DDL in BNF for HDF5 1.14.4 and above + +\todo Revise this & break it up! + +\section intro114 Introduction + +This document contains the data description language (DDL) for an HDF5 file. The +description is in Backus-Naur Form (BNF). + +\section expo114 Explanation of Symbols + +This section contains a brief explanation of the symbols used in the DDL. + +\code{.unparsed} +::= defined as + a token with the name tname + | one of or + opt zero or one occurrence of + * zero or more occurrence of + + one or more occurrence of + [0-9] an element in the range between 0 and 9 + '[' the token within the quotes (used for special characters) + TBD To Be Decided +\endcode + +\section ddl114 The DDL + +\code{.unparsed} + ::= HDF5 { opt } + + ::= + + ::= SUPER_BLOCK { + SUPERBLOCK_VERSION + FREELIST_VERSION + SYMBOLTABLE_VERSION + OBJECTHEADER_VERSION + OFFSET_SIZE + LENGTH_SIZE + BTREE_RANK + BTREE_LEAF + ISTORE_K + + USER_BLOCK { + USERBLOCK_SIZE + } + } + + ::= FILE_SPACE_STRATEGY + FREE_SPACE_PERSIST + FREE_SPACE_SECTION_THRESHOLD + FILE_SPACE_PAGE_SIZE + + ::= H5F_FSPACE_STRATEGY_FSM_AGGR | H5F_FSPACE_STRATEGY_PAGE | + H5F_FSPACE_STRATEGY_AGGR | H5F_FSPACE_STRATEGY_NONE | + Unknown strategy + + ::= GROUP "/" { + * + opt + opt + * + * + } + + ::= | | | + + ::= DATATYPE { + + } + + ::= the assigned name for anonymous named type is + in the form of #oid, where oid is the object id + of the type + + ::= | | * Libraries and Tools Reference. - * The HDF5 DDL grammar is described in the document \ref DDLBNF110. + * The HDF5 DDL grammar is described in the document \ref DDLBNF114. * * \subsection subsec_file_summary File Function Summaries * General library (\ref H5 functions and macros), (\ref H5F functions), file related diff --git a/src/H5Gmodule.h b/src/H5Gmodule.h index c330fcdb400..fb9cf732c09 100644 --- a/src/H5Gmodule.h +++ b/src/H5Gmodule.h @@ -343,7 +343,7 @@ * * h5dump is described on the “HDF5 Tools” page of the \ref RM. * - * The HDF5 DDL grammar is described in the @ref DDLBNF110. + * The HDF5 DDL grammar is described in the @ref DDLBNF114. * * \subsection subsec_group_function Group Function Summaries * Functions that can be used with groups (\ref H5G functions) and property list functions that can used diff --git a/src/H5T.c b/src/H5T.c index 7d3db702a84..1fb4b214833 100644 --- a/src/H5T.c +++ b/src/H5T.c @@ -100,6 +100,30 @@ dt->shared->u.atomic.msb_pad = H5T_PAD_ZERO; \ } +/* Define the code templates for standard 16-bit floats for the "GUTS" in the H5T_INIT_TYPE macro */ +#define H5T_INIT_TYPE_FLOAT16_COMMON(ENDIANNESS) \ + { \ + H5T_INIT_TYPE_NUM_COMMON(ENDIANNESS) \ + dt->shared->u.atomic.u.f.sign = 15; \ + dt->shared->u.atomic.u.f.epos = 10; \ + dt->shared->u.atomic.u.f.esize = 5; \ + dt->shared->u.atomic.u.f.ebias = 0xf; \ + dt->shared->u.atomic.u.f.mpos = 0; \ + dt->shared->u.atomic.u.f.msize = 10; \ + dt->shared->u.atomic.u.f.norm = H5T_NORM_IMPLIED; \ + dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO; \ + } + +#define H5T_INIT_TYPE_FLOAT16LE_CORE \ + { \ + H5T_INIT_TYPE_FLOAT16_COMMON(H5T_ORDER_LE) \ + } + +#define H5T_INIT_TYPE_FLOAT16BE_CORE \ + { \ + H5T_INIT_TYPE_FLOAT16_COMMON(H5T_ORDER_BE) \ + } + /* Define the code templates for standard floats for the "GUTS" in the H5T_INIT_TYPE macro */ #define H5T_INIT_TYPE_FLOAT_COMMON(ENDIANNESS) \ { \ @@ -375,102 +399,105 @@ H5T_order_t H5T_native_order_g = H5T_ORDER_ERROR; * If more of these are added, the new ones must be added to the list of * types to reset in H5T_term_package(). */ -hid_t H5T_IEEE_F32BE_g = FAIL; -hid_t H5T_IEEE_F32LE_g = FAIL; -hid_t H5T_IEEE_F64BE_g = FAIL; -hid_t H5T_IEEE_F64LE_g = FAIL; - -hid_t H5T_VAX_F32_g = FAIL; -hid_t H5T_VAX_F64_g = FAIL; - -hid_t H5T_STD_I8BE_g = FAIL; -hid_t H5T_STD_I8LE_g = FAIL; -hid_t H5T_STD_I16BE_g = FAIL; -hid_t H5T_STD_I16LE_g = FAIL; -hid_t H5T_STD_I32BE_g = FAIL; -hid_t H5T_STD_I32LE_g = FAIL; -hid_t H5T_STD_I64BE_g = FAIL; -hid_t H5T_STD_I64LE_g = FAIL; -hid_t H5T_STD_U8BE_g = FAIL; -hid_t H5T_STD_U8LE_g = FAIL; -hid_t H5T_STD_U16BE_g = FAIL; -hid_t H5T_STD_U16LE_g = FAIL; -hid_t H5T_STD_U32BE_g = FAIL; -hid_t H5T_STD_U32LE_g = FAIL; -hid_t H5T_STD_U64BE_g = FAIL; -hid_t H5T_STD_U64LE_g = FAIL; -hid_t H5T_STD_B8BE_g = FAIL; -hid_t H5T_STD_B8LE_g = FAIL; -hid_t H5T_STD_B16BE_g = FAIL; -hid_t H5T_STD_B16LE_g = FAIL; -hid_t H5T_STD_B32BE_g = FAIL; -hid_t H5T_STD_B32LE_g = FAIL; -hid_t H5T_STD_B64BE_g = FAIL; -hid_t H5T_STD_B64LE_g = FAIL; -hid_t H5T_STD_REF_OBJ_g = FAIL; -hid_t H5T_STD_REF_DSETREG_g = FAIL; -hid_t H5T_STD_REF_g = FAIL; - -hid_t H5T_UNIX_D32BE_g = FAIL; -hid_t H5T_UNIX_D32LE_g = FAIL; -hid_t H5T_UNIX_D64BE_g = FAIL; -hid_t H5T_UNIX_D64LE_g = FAIL; - -hid_t H5T_C_S1_g = FAIL; - -hid_t H5T_FORTRAN_S1_g = FAIL; - -hid_t H5T_NATIVE_SCHAR_g = FAIL; -hid_t H5T_NATIVE_UCHAR_g = FAIL; -hid_t H5T_NATIVE_SHORT_g = FAIL; -hid_t H5T_NATIVE_USHORT_g = FAIL; -hid_t H5T_NATIVE_INT_g = FAIL; -hid_t H5T_NATIVE_UINT_g = FAIL; -hid_t H5T_NATIVE_LONG_g = FAIL; -hid_t H5T_NATIVE_ULONG_g = FAIL; -hid_t H5T_NATIVE_LLONG_g = FAIL; -hid_t H5T_NATIVE_ULLONG_g = FAIL; -hid_t H5T_NATIVE_FLOAT_g = FAIL; -hid_t H5T_NATIVE_DOUBLE_g = FAIL; -hid_t H5T_NATIVE_LDOUBLE_g = FAIL; -hid_t H5T_NATIVE_B8_g = FAIL; -hid_t H5T_NATIVE_B16_g = FAIL; -hid_t H5T_NATIVE_B32_g = FAIL; -hid_t H5T_NATIVE_B64_g = FAIL; -hid_t H5T_NATIVE_OPAQUE_g = FAIL; -hid_t H5T_NATIVE_HADDR_g = FAIL; -hid_t H5T_NATIVE_HSIZE_g = FAIL; -hid_t H5T_NATIVE_HSSIZE_g = FAIL; -hid_t H5T_NATIVE_HERR_g = FAIL; -hid_t H5T_NATIVE_HBOOL_g = FAIL; - -hid_t H5T_NATIVE_INT8_g = FAIL; -hid_t H5T_NATIVE_UINT8_g = FAIL; -hid_t H5T_NATIVE_INT_LEAST8_g = FAIL; -hid_t H5T_NATIVE_UINT_LEAST8_g = FAIL; -hid_t H5T_NATIVE_INT_FAST8_g = FAIL; -hid_t H5T_NATIVE_UINT_FAST8_g = FAIL; - -hid_t H5T_NATIVE_INT16_g = FAIL; -hid_t H5T_NATIVE_UINT16_g = FAIL; -hid_t H5T_NATIVE_INT_LEAST16_g = FAIL; -hid_t H5T_NATIVE_UINT_LEAST16_g = FAIL; -hid_t H5T_NATIVE_INT_FAST16_g = FAIL; -hid_t H5T_NATIVE_UINT_FAST16_g = FAIL; - -hid_t H5T_NATIVE_INT32_g = FAIL; -hid_t H5T_NATIVE_UINT32_g = FAIL; -hid_t H5T_NATIVE_INT_LEAST32_g = FAIL; -hid_t H5T_NATIVE_UINT_LEAST32_g = FAIL; -hid_t H5T_NATIVE_INT_FAST32_g = FAIL; -hid_t H5T_NATIVE_UINT_FAST32_g = FAIL; - -hid_t H5T_NATIVE_INT64_g = FAIL; -hid_t H5T_NATIVE_UINT64_g = FAIL; -hid_t H5T_NATIVE_INT_LEAST64_g = FAIL; -hid_t H5T_NATIVE_UINT_LEAST64_g = FAIL; -hid_t H5T_NATIVE_INT_FAST64_g = FAIL; -hid_t H5T_NATIVE_UINT_FAST64_g = FAIL; +hid_t H5T_IEEE_F16BE_g = H5I_INVALID_HID; +hid_t H5T_IEEE_F16LE_g = H5I_INVALID_HID; +hid_t H5T_IEEE_F32BE_g = H5I_INVALID_HID; +hid_t H5T_IEEE_F32LE_g = H5I_INVALID_HID; +hid_t H5T_IEEE_F64BE_g = H5I_INVALID_HID; +hid_t H5T_IEEE_F64LE_g = H5I_INVALID_HID; + +hid_t H5T_VAX_F32_g = H5I_INVALID_HID; +hid_t H5T_VAX_F64_g = H5I_INVALID_HID; + +hid_t H5T_STD_I8BE_g = H5I_INVALID_HID; +hid_t H5T_STD_I8LE_g = H5I_INVALID_HID; +hid_t H5T_STD_I16BE_g = H5I_INVALID_HID; +hid_t H5T_STD_I16LE_g = H5I_INVALID_HID; +hid_t H5T_STD_I32BE_g = H5I_INVALID_HID; +hid_t H5T_STD_I32LE_g = H5I_INVALID_HID; +hid_t H5T_STD_I64BE_g = H5I_INVALID_HID; +hid_t H5T_STD_I64LE_g = H5I_INVALID_HID; +hid_t H5T_STD_U8BE_g = H5I_INVALID_HID; +hid_t H5T_STD_U8LE_g = H5I_INVALID_HID; +hid_t H5T_STD_U16BE_g = H5I_INVALID_HID; +hid_t H5T_STD_U16LE_g = H5I_INVALID_HID; +hid_t H5T_STD_U32BE_g = H5I_INVALID_HID; +hid_t H5T_STD_U32LE_g = H5I_INVALID_HID; +hid_t H5T_STD_U64BE_g = H5I_INVALID_HID; +hid_t H5T_STD_U64LE_g = H5I_INVALID_HID; +hid_t H5T_STD_B8BE_g = H5I_INVALID_HID; +hid_t H5T_STD_B8LE_g = H5I_INVALID_HID; +hid_t H5T_STD_B16BE_g = H5I_INVALID_HID; +hid_t H5T_STD_B16LE_g = H5I_INVALID_HID; +hid_t H5T_STD_B32BE_g = H5I_INVALID_HID; +hid_t H5T_STD_B32LE_g = H5I_INVALID_HID; +hid_t H5T_STD_B64BE_g = H5I_INVALID_HID; +hid_t H5T_STD_B64LE_g = H5I_INVALID_HID; +hid_t H5T_STD_REF_OBJ_g = H5I_INVALID_HID; +hid_t H5T_STD_REF_DSETREG_g = H5I_INVALID_HID; +hid_t H5T_STD_REF_g = H5I_INVALID_HID; + +hid_t H5T_UNIX_D32BE_g = H5I_INVALID_HID; +hid_t H5T_UNIX_D32LE_g = H5I_INVALID_HID; +hid_t H5T_UNIX_D64BE_g = H5I_INVALID_HID; +hid_t H5T_UNIX_D64LE_g = H5I_INVALID_HID; + +hid_t H5T_C_S1_g = H5I_INVALID_HID; + +hid_t H5T_FORTRAN_S1_g = H5I_INVALID_HID; + +hid_t H5T_NATIVE_SCHAR_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UCHAR_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_SHORT_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_USHORT_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_LONG_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_ULONG_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_LLONG_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_ULLONG_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_FLOAT16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_FLOAT_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_DOUBLE_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_LDOUBLE_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_B8_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_B16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_B32_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_B64_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_OPAQUE_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_HADDR_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_HSIZE_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_HSSIZE_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_HERR_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_HBOOL_g = H5I_INVALID_HID; + +hid_t H5T_NATIVE_INT8_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT8_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_LEAST8_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_LEAST8_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_FAST8_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_FAST8_g = H5I_INVALID_HID; + +hid_t H5T_NATIVE_INT16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_LEAST16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_LEAST16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_FAST16_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_FAST16_g = H5I_INVALID_HID; + +hid_t H5T_NATIVE_INT32_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT32_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_LEAST32_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_LEAST32_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_FAST32_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_FAST32_g = H5I_INVALID_HID; + +hid_t H5T_NATIVE_INT64_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT64_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_LEAST64_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_LEAST64_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_INT_FAST64_g = H5I_INVALID_HID; +hid_t H5T_NATIVE_UINT_FAST64_g = H5I_INVALID_HID; /* * Alignment constraints for HDF5 types. Accessing objects of these @@ -498,6 +525,7 @@ size_t H5T_NATIVE_LONG_ALIGN_g = 0; size_t H5T_NATIVE_ULONG_ALIGN_g = 0; size_t H5T_NATIVE_LLONG_ALIGN_g = 0; size_t H5T_NATIVE_ULLONG_ALIGN_g = 0; +size_t H5T_NATIVE_FLOAT16_ALIGN_g = 0; size_t H5T_NATIVE_FLOAT_ALIGN_g = 0; size_t H5T_NATIVE_DOUBLE_ALIGN_g = 0; size_t H5T_NATIVE_LDOUBLE_ALIGN_g = 0; @@ -533,6 +561,15 @@ size_t H5T_NATIVE_UINT_FAST64_ALIGN_g = 0; /* Useful floating-point values for conversion routines */ /* (+/- Inf for all floating-point types) */ +#ifdef H5_HAVE__FLOAT16 +/* Initialize these with a float literal since the f16 suffix + * is non-standard C and gives warnings when compiling the + * library with the -pedantic flag. These values will be + * overwritten anyway. + */ +H5__Float16 H5T_NATIVE_FLOAT16_POS_INF_g = 0.0f; +H5__Float16 H5T_NATIVE_FLOAT16_NEG_INF_g = 0.0f; +#endif float H5T_NATIVE_FLOAT_POS_INF_g = 0.0F; float H5T_NATIVE_FLOAT_NEG_INF_g = 0.0F; double H5T_NATIVE_DOUBLE_POS_INF_g = 0.0; @@ -685,6 +722,49 @@ H5T__init_inf(void) } /* end for */ } /* end if */ +#ifdef H5_HAVE__FLOAT16 + /* Get the _Float16 datatype */ + if (NULL == (dst_p = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT16_g))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); + dst = &dst_p->shared->u.atomic; + + /* Check that we can re-order the bytes correctly */ + if (H5T_ORDER_LE != H5T_native_order_g && H5T_ORDER_BE != H5T_native_order_g) + HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order"); + + /* +Inf */ + d = (uint8_t *)&H5T_NATIVE_FLOAT16_POS_INF_g; + H5T__bit_set(d, dst->u.f.sign, (size_t)1, false); + H5T__bit_set(d, dst->u.f.epos, dst->u.f.esize, true); + H5T__bit_set(d, dst->u.f.mpos, dst->u.f.msize, false); + + /* Swap the bytes if the machine architecture is big-endian */ + if (H5T_ORDER_BE == H5T_native_order_g) { + half_size = dst_p->shared->size / 2; + for (u = 0; u < half_size; u++) { + uint8_t tmp = d[dst_p->shared->size - (u + 1)]; + d[dst_p->shared->size - (u + 1)] = d[u]; + d[u] = tmp; + } /* end for */ + } /* end if */ + + /* -Inf */ + d = (uint8_t *)&H5T_NATIVE_FLOAT16_NEG_INF_g; + H5T__bit_set(d, dst->u.f.sign, (size_t)1, true); + H5T__bit_set(d, dst->u.f.epos, dst->u.f.esize, true); + H5T__bit_set(d, dst->u.f.mpos, dst->u.f.msize, false); + + /* Swap the bytes if the machine architecture is big-endian */ + if (H5T_ORDER_BE == H5T_native_order_g) { + half_size = dst_p->shared->size / 2; + for (u = 0; u < half_size; u++) { + uint8_t tmp = d[dst_p->shared->size - (u + 1)]; + d[dst_p->shared->size - (u + 1)] = d[u]; + d[u] = tmp; + } /* end for */ + } /* end if */ +#endif + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5T__init_inf() */ @@ -738,6 +818,9 @@ H5T_init(void) herr_t status; bool copied_dtype = true; /* Flag to indicate whether datatype was copied or allocated (for error cleanup) */ +#ifdef H5_HAVE__FLOAT16 + H5T_t *native_float16 = NULL; /* Datatype structure for native _Float16 type */ +#endif herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -779,6 +862,10 @@ H5T_init(void) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object"); if (NULL == (native_ullong = (H5T_t *)H5I_object(H5T_NATIVE_ULLONG_g))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object"); +#ifdef H5_HAVE__FLOAT16 + if (NULL == (native_float16 = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT16_g))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object"); +#endif if (NULL == (native_float = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT_g))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype object"); if (NULL == (native_double = (H5T_t *)H5I_object(H5T_NATIVE_DOUBLE_g))) @@ -823,6 +910,12 @@ H5T_init(void) *------------------------------------------------------------ */ + /* IEEE 2-byte little-endian float */ + H5T_INIT_TYPE(FLOAT16LE, H5T_IEEE_F16LE_g, COPY, native_double, SET, 2) + + /* IEEE 2-byte big-endian float */ + H5T_INIT_TYPE(FLOAT16BE, H5T_IEEE_F16BE_g, COPY, native_double, SET, 2) + /* IEEE 4-byte little-endian float */ H5T_INIT_TYPE(FLOATLE, H5T_IEEE_F32LE_g, COPY, native_double, SET, 4) @@ -1062,6 +1155,22 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "ldbl_flt", native_ldouble, native_float, H5T__conv_ldouble_float); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_dbl", native_ldouble, native_double, H5T__conv_ldouble_double); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "flt16_flt", native_float16, native_float, H5T__conv__Float16_float); + status |= H5T__register_int(H5T_PERS_HARD, "flt16_dbl", native_float16, native_double, + H5T__conv__Float16_double); + status |= H5T__register_int(H5T_PERS_HARD, "flt16_ldbl", native_float16, native_ldouble, + H5T__conv__Float16_ldouble); + status |= + H5T__register_int(H5T_PERS_HARD, "flt_flt16", native_float, native_float16, H5T__conv_float__Float16); + status |= H5T__register_int(H5T_PERS_HARD, "dbl_flt16", native_double, native_float16, + H5T__conv_double__Float16); +#ifdef H5T_CONV_INTERNAL_LDOUBLE_FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "ldbl_flt16", native_ldouble, native_float16, + H5T__conv_ldouble__Float16); +#endif +#endif /* from long long */ status |= @@ -1220,6 +1329,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "schar_dbl", native_schar, native_double, H5T__conv_schar_double); status |= H5T__register_int(H5T_PERS_HARD, "schar_ldbl", native_schar, native_ldouble, H5T__conv_schar_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "schar_flt16", native_schar, native_float16, + H5T__conv_schar__Float16); +#endif /* From unsigned char to floats */ status |= @@ -1228,6 +1341,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "uchar_dbl", native_uchar, native_double, H5T__conv_uchar_double); status |= H5T__register_int(H5T_PERS_HARD, "uchar_ldbl", native_uchar, native_ldouble, H5T__conv_uchar_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "uchar_flt16", native_uchar, native_float16, + H5T__conv_uchar__Float16); +#endif /* From short to floats */ status |= @@ -1236,6 +1353,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "short_dbl", native_short, native_double, H5T__conv_short_double); status |= H5T__register_int(H5T_PERS_HARD, "short_ldbl", native_short, native_ldouble, H5T__conv_short_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "short_flt16", native_short, native_float16, + H5T__conv_short__Float16); +#endif /* From unsigned short to floats */ status |= @@ -1244,23 +1365,39 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "ushort_dbl", native_ushort, native_double, H5T__conv_ushort_double); status |= H5T__register_int(H5T_PERS_HARD, "ushort_ldbl", native_ushort, native_ldouble, H5T__conv_ushort_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "ushort_flt16", native_ushort, native_float16, + H5T__conv_ushort__Float16); +#endif /* From int to floats */ status |= H5T__register_int(H5T_PERS_HARD, "int_flt", native_int, native_float, H5T__conv_int_float); status |= H5T__register_int(H5T_PERS_HARD, "int_dbl", native_int, native_double, H5T__conv_int_double); status |= H5T__register_int(H5T_PERS_HARD, "int_ldbl", native_int, native_ldouble, H5T__conv_int_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "int_flt16", native_int, native_float16, H5T__conv_int__Float16); +#endif /* From unsigned int to floats */ status |= H5T__register_int(H5T_PERS_HARD, "uint_flt", native_uint, native_float, H5T__conv_uint_float); status |= H5T__register_int(H5T_PERS_HARD, "uint_dbl", native_uint, native_double, H5T__conv_uint_double); status |= H5T__register_int(H5T_PERS_HARD, "uint_ldbl", native_uint, native_ldouble, H5T__conv_uint_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "uint_flt16", native_uint, native_float16, H5T__conv_uint__Float16); +#endif /* From long to floats */ status |= H5T__register_int(H5T_PERS_HARD, "long_flt", native_long, native_float, H5T__conv_long_float); status |= H5T__register_int(H5T_PERS_HARD, "long_dbl", native_long, native_double, H5T__conv_long_double); status |= H5T__register_int(H5T_PERS_HARD, "long_ldbl", native_long, native_ldouble, H5T__conv_long_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "long_flt16", native_long, native_float16, H5T__conv_long__Float16); +#endif /* From unsigned long to floats */ status |= @@ -1269,6 +1406,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "ulong_dbl", native_ulong, native_double, H5T__conv_ulong_double); status |= H5T__register_int(H5T_PERS_HARD, "ulong_ldbl", native_ulong, native_ldouble, H5T__conv_ulong_ldouble); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "ulong_flt16", native_ulong, native_float16, + H5T__conv_ulong__Float16); +#endif /* From long long to floats */ status |= @@ -1279,6 +1420,10 @@ H5T_init(void) status |= H5T__register_int(H5T_PERS_HARD, "llong_ldbl", native_llong, native_ldouble, H5T__conv_llong_ldouble); #endif /* H5T_CONV_INTERNAL_LLONG_LDOUBLE */ +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "llong_flt16", native_llong, native_float16, + H5T__conv_llong__Float16); +#endif /* From unsigned long long to floats */ status |= @@ -1289,6 +1434,10 @@ H5T_init(void) status |= H5T__register_int(H5T_PERS_HARD, "ullong_ldbl", native_ullong, native_ldouble, H5T__conv_ullong_ldouble); #endif /* H5T_CONV_INTERNAL_ULLONG_LDOUBLE */ +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "ullong_flt16", native_ullong, native_float16, + H5T__conv_ullong__Float16); +#endif /* From floats to char */ status |= @@ -1297,6 +1446,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "dbl_schar", native_double, native_schar, H5T__conv_double_schar); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_schar", native_ldouble, native_schar, H5T__conv_ldouble_schar); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_schar", native_float16, native_schar, + H5T__conv__Float16_schar); +#endif /* From floats to unsigned char */ status |= @@ -1305,6 +1458,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "dbl_uchar", native_double, native_uchar, H5T__conv_double_uchar); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_uchar", native_ldouble, native_uchar, H5T__conv_ldouble_uchar); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_uchar", native_float16, native_uchar, + H5T__conv__Float16_uchar); +#endif /* From floats to short */ status |= @@ -1313,6 +1470,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "dbl_short", native_double, native_short, H5T__conv_double_short); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_short", native_ldouble, native_short, H5T__conv_ldouble_short); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_short", native_float16, native_short, + H5T__conv__Float16_short); +#endif /* From floats to unsigned short */ status |= @@ -1321,23 +1482,39 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "dbl_ushort", native_double, native_ushort, H5T__conv_double_ushort); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_ushort", native_ldouble, native_ushort, H5T__conv_ldouble_ushort); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_ushort", native_float16, native_ushort, + H5T__conv__Float16_ushort); +#endif /* From floats to int */ status |= H5T__register_int(H5T_PERS_HARD, "flt_int", native_float, native_int, H5T__conv_float_int); status |= H5T__register_int(H5T_PERS_HARD, "dbl_int", native_double, native_int, H5T__conv_double_int); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_int", native_ldouble, native_int, H5T__conv_ldouble_int); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "flt16_int", native_float16, native_int, H5T__conv__Float16_int); +#endif /* From floats to unsigned int */ status |= H5T__register_int(H5T_PERS_HARD, "flt_uint", native_float, native_uint, H5T__conv_float_uint); status |= H5T__register_int(H5T_PERS_HARD, "dbl_uint", native_double, native_uint, H5T__conv_double_uint); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_uint", native_ldouble, native_uint, H5T__conv_ldouble_uint); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "flt16_uint", native_float16, native_uint, H5T__conv__Float16_uint); +#endif /* From floats to long */ status |= H5T__register_int(H5T_PERS_HARD, "flt_long", native_float, native_long, H5T__conv_float_long); status |= H5T__register_int(H5T_PERS_HARD, "dbl_long", native_double, native_long, H5T__conv_double_long); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_long", native_ldouble, native_long, H5T__conv_ldouble_long); +#ifdef H5_HAVE__FLOAT16 + status |= + H5T__register_int(H5T_PERS_HARD, "flt16_long", native_float16, native_long, H5T__conv__Float16_long); +#endif /* From floats to unsigned long */ status |= @@ -1346,6 +1523,10 @@ H5T_init(void) H5T__register_int(H5T_PERS_HARD, "dbl_ulong", native_double, native_ulong, H5T__conv_double_ulong); status |= H5T__register_int(H5T_PERS_HARD, "ldbl_ulong", native_ldouble, native_ulong, H5T__conv_ldouble_ulong); +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_ulong", native_float16, native_ulong, + H5T__conv__Float16_ulong); +#endif /* From floats to long long */ status |= @@ -1356,6 +1537,10 @@ H5T_init(void) status |= H5T__register_int(H5T_PERS_HARD, "ldbl_llong", native_ldouble, native_llong, H5T__conv_ldouble_llong); #endif /* H5T_CONV_INTERNAL_LDOUBLE_LLONG */ +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_llong", native_float16, native_llong, + H5T__conv__Float16_llong); +#endif /* From floats to unsigned long long */ status |= @@ -1366,6 +1551,10 @@ H5T_init(void) status |= H5T__register_int(H5T_PERS_HARD, "ldbl_ullong", native_ldouble, native_ullong, H5T__conv_ldouble_ullong); #endif /* H5T_CONV_INTERNAL_LDOUBLE_ULLONG */ +#ifdef H5_HAVE__FLOAT16 + status |= H5T__register_int(H5T_PERS_HARD, "flt16_ullong", native_float16, native_ullong, + H5T__conv__Float16_ullong); +#endif /* * The special no-op conversion is the fastest, so we list it last. The @@ -1546,99 +1735,102 @@ H5T_top_term_package(void) /* Reset all the datatype IDs */ if (H5T_IEEE_F32BE_g > 0) { - H5T_IEEE_F32BE_g = FAIL; - H5T_IEEE_F32LE_g = FAIL; - H5T_IEEE_F64BE_g = FAIL; - H5T_IEEE_F64LE_g = FAIL; - - H5T_STD_I8BE_g = FAIL; - H5T_STD_I8LE_g = FAIL; - H5T_STD_I16BE_g = FAIL; - H5T_STD_I16LE_g = FAIL; - H5T_STD_I32BE_g = FAIL; - H5T_STD_I32LE_g = FAIL; - H5T_STD_I64BE_g = FAIL; - H5T_STD_I64LE_g = FAIL; - H5T_STD_U8BE_g = FAIL; - H5T_STD_U8LE_g = FAIL; - H5T_STD_U16BE_g = FAIL; - H5T_STD_U16LE_g = FAIL; - H5T_STD_U32BE_g = FAIL; - H5T_STD_U32LE_g = FAIL; - H5T_STD_U64BE_g = FAIL; - H5T_STD_U64LE_g = FAIL; - H5T_STD_B8BE_g = FAIL; - H5T_STD_B8LE_g = FAIL; - H5T_STD_B16BE_g = FAIL; - H5T_STD_B16LE_g = FAIL; - H5T_STD_B32BE_g = FAIL; - H5T_STD_B32LE_g = FAIL; - H5T_STD_B64BE_g = FAIL; - H5T_STD_B64LE_g = FAIL; - H5T_STD_REF_OBJ_g = FAIL; - H5T_STD_REF_DSETREG_g = FAIL; - H5T_STD_REF_g = FAIL; - - H5T_UNIX_D32BE_g = FAIL; - H5T_UNIX_D32LE_g = FAIL; - H5T_UNIX_D64BE_g = FAIL; - H5T_UNIX_D64LE_g = FAIL; - - H5T_C_S1_g = FAIL; - - H5T_FORTRAN_S1_g = FAIL; - - H5T_NATIVE_SCHAR_g = FAIL; - H5T_NATIVE_UCHAR_g = FAIL; - H5T_NATIVE_SHORT_g = FAIL; - H5T_NATIVE_USHORT_g = FAIL; - H5T_NATIVE_INT_g = FAIL; - H5T_NATIVE_UINT_g = FAIL; - H5T_NATIVE_LONG_g = FAIL; - H5T_NATIVE_ULONG_g = FAIL; - H5T_NATIVE_LLONG_g = FAIL; - H5T_NATIVE_ULLONG_g = FAIL; - H5T_NATIVE_FLOAT_g = FAIL; - H5T_NATIVE_DOUBLE_g = FAIL; - H5T_NATIVE_LDOUBLE_g = FAIL; - H5T_NATIVE_B8_g = FAIL; - H5T_NATIVE_B16_g = FAIL; - H5T_NATIVE_B32_g = FAIL; - H5T_NATIVE_B64_g = FAIL; - H5T_NATIVE_OPAQUE_g = FAIL; - H5T_NATIVE_HADDR_g = FAIL; - H5T_NATIVE_HSIZE_g = FAIL; - H5T_NATIVE_HSSIZE_g = FAIL; - H5T_NATIVE_HERR_g = FAIL; - H5T_NATIVE_HBOOL_g = FAIL; - - H5T_NATIVE_INT8_g = FAIL; - H5T_NATIVE_UINT8_g = FAIL; - H5T_NATIVE_INT_LEAST8_g = FAIL; - H5T_NATIVE_UINT_LEAST8_g = FAIL; - H5T_NATIVE_INT_FAST8_g = FAIL; - H5T_NATIVE_UINT_FAST8_g = FAIL; - - H5T_NATIVE_INT16_g = FAIL; - H5T_NATIVE_UINT16_g = FAIL; - H5T_NATIVE_INT_LEAST16_g = FAIL; - H5T_NATIVE_UINT_LEAST16_g = FAIL; - H5T_NATIVE_INT_FAST16_g = FAIL; - H5T_NATIVE_UINT_FAST16_g = FAIL; - - H5T_NATIVE_INT32_g = FAIL; - H5T_NATIVE_UINT32_g = FAIL; - H5T_NATIVE_INT_LEAST32_g = FAIL; - H5T_NATIVE_UINT_LEAST32_g = FAIL; - H5T_NATIVE_INT_FAST32_g = FAIL; - H5T_NATIVE_UINT_FAST32_g = FAIL; - - H5T_NATIVE_INT64_g = FAIL; - H5T_NATIVE_UINT64_g = FAIL; - H5T_NATIVE_INT_LEAST64_g = FAIL; - H5T_NATIVE_UINT_LEAST64_g = FAIL; - H5T_NATIVE_INT_FAST64_g = FAIL; - H5T_NATIVE_UINT_FAST64_g = FAIL; + H5T_IEEE_F16BE_g = H5I_INVALID_HID; + H5T_IEEE_F16LE_g = H5I_INVALID_HID; + H5T_IEEE_F32BE_g = H5I_INVALID_HID; + H5T_IEEE_F32LE_g = H5I_INVALID_HID; + H5T_IEEE_F64BE_g = H5I_INVALID_HID; + H5T_IEEE_F64LE_g = H5I_INVALID_HID; + + H5T_STD_I8BE_g = H5I_INVALID_HID; + H5T_STD_I8LE_g = H5I_INVALID_HID; + H5T_STD_I16BE_g = H5I_INVALID_HID; + H5T_STD_I16LE_g = H5I_INVALID_HID; + H5T_STD_I32BE_g = H5I_INVALID_HID; + H5T_STD_I32LE_g = H5I_INVALID_HID; + H5T_STD_I64BE_g = H5I_INVALID_HID; + H5T_STD_I64LE_g = H5I_INVALID_HID; + H5T_STD_U8BE_g = H5I_INVALID_HID; + H5T_STD_U8LE_g = H5I_INVALID_HID; + H5T_STD_U16BE_g = H5I_INVALID_HID; + H5T_STD_U16LE_g = H5I_INVALID_HID; + H5T_STD_U32BE_g = H5I_INVALID_HID; + H5T_STD_U32LE_g = H5I_INVALID_HID; + H5T_STD_U64BE_g = H5I_INVALID_HID; + H5T_STD_U64LE_g = H5I_INVALID_HID; + H5T_STD_B8BE_g = H5I_INVALID_HID; + H5T_STD_B8LE_g = H5I_INVALID_HID; + H5T_STD_B16BE_g = H5I_INVALID_HID; + H5T_STD_B16LE_g = H5I_INVALID_HID; + H5T_STD_B32BE_g = H5I_INVALID_HID; + H5T_STD_B32LE_g = H5I_INVALID_HID; + H5T_STD_B64BE_g = H5I_INVALID_HID; + H5T_STD_B64LE_g = H5I_INVALID_HID; + H5T_STD_REF_OBJ_g = H5I_INVALID_HID; + H5T_STD_REF_DSETREG_g = H5I_INVALID_HID; + H5T_STD_REF_g = H5I_INVALID_HID; + + H5T_UNIX_D32BE_g = H5I_INVALID_HID; + H5T_UNIX_D32LE_g = H5I_INVALID_HID; + H5T_UNIX_D64BE_g = H5I_INVALID_HID; + H5T_UNIX_D64LE_g = H5I_INVALID_HID; + + H5T_C_S1_g = H5I_INVALID_HID; + + H5T_FORTRAN_S1_g = H5I_INVALID_HID; + + H5T_NATIVE_SCHAR_g = H5I_INVALID_HID; + H5T_NATIVE_UCHAR_g = H5I_INVALID_HID; + H5T_NATIVE_SHORT_g = H5I_INVALID_HID; + H5T_NATIVE_USHORT_g = H5I_INVALID_HID; + H5T_NATIVE_INT_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_g = H5I_INVALID_HID; + H5T_NATIVE_LONG_g = H5I_INVALID_HID; + H5T_NATIVE_ULONG_g = H5I_INVALID_HID; + H5T_NATIVE_LLONG_g = H5I_INVALID_HID; + H5T_NATIVE_ULLONG_g = H5I_INVALID_HID; + H5T_NATIVE_FLOAT16_g = H5I_INVALID_HID; + H5T_NATIVE_FLOAT_g = H5I_INVALID_HID; + H5T_NATIVE_DOUBLE_g = H5I_INVALID_HID; + H5T_NATIVE_LDOUBLE_g = H5I_INVALID_HID; + H5T_NATIVE_B8_g = H5I_INVALID_HID; + H5T_NATIVE_B16_g = H5I_INVALID_HID; + H5T_NATIVE_B32_g = H5I_INVALID_HID; + H5T_NATIVE_B64_g = H5I_INVALID_HID; + H5T_NATIVE_OPAQUE_g = H5I_INVALID_HID; + H5T_NATIVE_HADDR_g = H5I_INVALID_HID; + H5T_NATIVE_HSIZE_g = H5I_INVALID_HID; + H5T_NATIVE_HSSIZE_g = H5I_INVALID_HID; + H5T_NATIVE_HERR_g = H5I_INVALID_HID; + H5T_NATIVE_HBOOL_g = H5I_INVALID_HID; + + H5T_NATIVE_INT8_g = H5I_INVALID_HID; + H5T_NATIVE_UINT8_g = H5I_INVALID_HID; + H5T_NATIVE_INT_LEAST8_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_LEAST8_g = H5I_INVALID_HID; + H5T_NATIVE_INT_FAST8_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_FAST8_g = H5I_INVALID_HID; + + H5T_NATIVE_INT16_g = H5I_INVALID_HID; + H5T_NATIVE_UINT16_g = H5I_INVALID_HID; + H5T_NATIVE_INT_LEAST16_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_LEAST16_g = H5I_INVALID_HID; + H5T_NATIVE_INT_FAST16_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_FAST16_g = H5I_INVALID_HID; + + H5T_NATIVE_INT32_g = H5I_INVALID_HID; + H5T_NATIVE_UINT32_g = H5I_INVALID_HID; + H5T_NATIVE_INT_LEAST32_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_LEAST32_g = H5I_INVALID_HID; + H5T_NATIVE_INT_FAST32_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_FAST32_g = H5I_INVALID_HID; + + H5T_NATIVE_INT64_g = H5I_INVALID_HID; + H5T_NATIVE_UINT64_g = H5I_INVALID_HID; + H5T_NATIVE_INT_LEAST64_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_LEAST64_g = H5I_INVALID_HID; + H5T_NATIVE_INT_FAST64_g = H5I_INVALID_HID; + H5T_NATIVE_UINT_FAST64_g = H5I_INVALID_HID; n++; } /* end if */ diff --git a/src/H5Tconv.c b/src/H5Tconv.c index a37800bfed3..0e35fb5461b 100644 --- a/src/H5Tconv.c +++ b/src/H5Tconv.c @@ -112,6 +112,14 @@ * at least as wide as the destination. Overflow can occur * when the source magnitude is too large for the destination. * + * fX: Floating-point values to integers where the destination is at least + * as wide as the source. This case cannot generate overflows. + * + * Xf: Integers to floating-point values where the source is at least as + * wide as the destination. Overflows can occur when the destination is + * narrower than the source. + * + * * The macros take a subset of these arguments in the order listed here: * * CDATA: A pointer to the H5T_cdata_t structure that was passed to the @@ -704,6 +712,99 @@ H5T_CONV(H5T_CONV_Fx, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, Y) \ } while (0) +#define H5T_CONV_fX(STYPE, DTYPE, ST, DT, D_MIN, D_MAX) \ + do { \ + HDcompile_assert(sizeof(ST) <= sizeof(DT)); \ + H5T_CONV(H5T_CONV_xX, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, N) \ + } while (0) + +#define H5T_CONV_Xf_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ + { \ + if (*(S) > (ST)(D_MAX) || (sprec < dprec && *(S) == (ST)(D_MAX))) { \ + H5T_conv_ret_t except_ret = (conv_ctx->u.conv.cb_struct.func)( \ + H5T_CONV_EXCEPT_RANGE_HI, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, S, D, \ + conv_ctx->u.conv.cb_struct.user_data); \ + if (except_ret == H5T_CONV_UNHANDLED) \ + /* Let compiler convert if case is ignored by user handler*/ \ + *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _POS_INF_g); \ + else if (except_ret == H5T_CONV_ABORT) \ + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception"); \ + /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ + } \ + else if (*(S) < (ST)(D_MIN)) { \ + H5T_conv_ret_t except_ret = (conv_ctx->u.conv.cb_struct.func)( \ + H5T_CONV_EXCEPT_RANGE_LOW, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, S, D, \ + conv_ctx->u.conv.cb_struct.user_data); \ + if (except_ret == H5T_CONV_UNHANDLED) \ + /* Let compiler convert if case is ignored by user handler*/ \ + *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _NEG_INF_g); \ + else if (except_ret == H5T_CONV_ABORT) \ + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception"); \ + /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ + } \ + else if (sprec > dprec) { \ + unsigned low_bit_pos, high_bit_pos; \ + \ + /* Detect high & low bits set in source */ \ + H5T_HI_LO_BIT_SET(ST, *(S), low_bit_pos, high_bit_pos) \ + \ + /* Check for more bits of precision in src than available in dst */ \ + if ((high_bit_pos - low_bit_pos) >= dprec) { \ + H5T_conv_ret_t except_ret = (conv_ctx->u.conv.cb_struct.func)( \ + H5T_CONV_EXCEPT_PRECISION, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, \ + S, D, conv_ctx->u.conv.cb_struct.user_data); \ + if (except_ret == H5T_CONV_UNHANDLED) \ + /* Let compiler convert if case is ignored by user handler*/ \ + *(D) = (DT)(*(S)); \ + else if (except_ret == H5T_CONV_ABORT) \ + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception"); \ + /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ + } \ + else \ + *(D) = (DT)(*(S)); \ + } \ + else \ + *(D) = (DT)(*(S)); \ + } +#define H5T_CONV_Xf_NOEX_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ + { \ + if (*(S) > (ST)(D_MAX)) \ + *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _POS_INF_g); \ + else { \ + intmax_t s_cast = (intmax_t)(*(S)); \ + intmax_t d_cast = (intmax_t)(D_MAX); \ + \ + /* Check if source value would underflow destination. Do NOT do this \ + * by comparing against D_MIN casted to type ST here, as this will \ + * generally be undefined behavior (casting negative float value <= 1.0 \ + * to integer) for all floating point types and some compilers optimize \ + * this in a way that causes unexpected behavior. Instead, grab the \ + * absolute value of the source value first, then compare it to D_MAX. \ + */ \ + if (s_cast != INTMAX_MIN) \ + s_cast = imaxabs(s_cast); \ + else { \ + /* Handle two's complement integer representations where abs(INTMAX_MIN) \ + * can't be represented. Other representations will fall here as well, \ + * but this should be fine. \ + */ \ + s_cast = INTMAX_MAX; \ + d_cast -= 1; \ + } \ + \ + if (s_cast > d_cast) \ + *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _NEG_INF_g); \ + else \ + *(D) = (DT)(*(S)); \ + } \ + } + +#define H5T_CONV_Xf(STYPE, DTYPE, ST, DT, D_MIN, D_MAX) \ + do { \ + HDcompile_assert(sizeof(ST) >= sizeof(DT)); \ + H5T_CONV(H5T_CONV_Xf, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, Y) \ + } while (0) + /* Since all "no exception" cores do the same thing (assign the value in the * source location to the destination location, using casting), use one "core" * to do them all. @@ -8215,6 +8316,255 @@ H5T__conv_ldouble_ullong(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_con } #endif /*H5T_CONV_INTERNAL_LDOUBLE_ULLONG*/ +/* Conversions for _Float16 type */ +#ifdef H5_HAVE__FLOAT16 +herr_t +H5T__conv_schar__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_xF(SCHAR, FLOAT16, signed char, H5__Float16, -, -); +} + +herr_t +H5T__conv_uchar__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_xF(UCHAR, FLOAT16, unsigned char, H5__Float16, -, -); +} + +herr_t +H5T__conv_short__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_xF(SHORT, FLOAT16, short, H5__Float16, -, -); +} + +herr_t +H5T__conv_ushort__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(USHORT, FLOAT16, unsigned short, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_int__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(INT, FLOAT16, int, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_uint__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(UINT, FLOAT16, unsigned int, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_long__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(LONG, FLOAT16, long, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_ulong__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(ULONG, FLOAT16, unsigned long, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_llong__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(LLONG, FLOAT16, long long, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_ullong__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Xf(ULLONG, FLOAT16, unsigned long long, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_float__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Ff(FLOAT, FLOAT16, float, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +herr_t +H5T__conv_double__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Ff(DOUBLE, FLOAT16, double, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} + +#ifdef H5T_CONV_INTERNAL_LDOUBLE_FLOAT16 +herr_t +H5T__conv_ldouble__Float16(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + /* Suppress warning about non-standard floating-point literal suffix */ + H5_GCC_CLANG_DIAG_OFF("pedantic") + H5T_CONV_Ff(LDOUBLE, FLOAT16, long double, H5__Float16, -FLT16_MAX, FLT16_MAX); + H5_GCC_CLANG_DIAG_ON("pedantic") +} +#endif + +herr_t +H5T__conv__Float16_schar(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5_GCC_CLANG_DIAG_OFF("float-equal") + H5T_CONV_Fx(FLOAT16, SCHAR, H5__Float16, signed char, SCHAR_MIN, SCHAR_MAX); + H5_GCC_CLANG_DIAG_ON("float-equal") +} + +herr_t +H5T__conv__Float16_uchar(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5_GCC_CLANG_DIAG_OFF("float-equal") + H5T_CONV_Fx(FLOAT16, UCHAR, H5__Float16, unsigned char, 0, UCHAR_MAX); + H5_GCC_CLANG_DIAG_ON("float-equal") +} + +herr_t +H5T__conv__Float16_short(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5_GCC_CLANG_DIAG_OFF("float-equal") + H5T_CONV_Fx(FLOAT16, SHORT, H5__Float16, short, SHRT_MIN, SHRT_MAX); + H5_GCC_CLANG_DIAG_ON("float-equal") +} + +herr_t +H5T__conv__Float16_ushort(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, USHORT, H5__Float16, unsigned short, 0, USHRT_MAX); +} + +herr_t +H5T__conv__Float16_int(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, INT, H5__Float16, int, INT_MIN, INT_MAX); +} + +herr_t +H5T__conv__Float16_uint(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, UINT, H5__Float16, unsigned int, 0, UINT_MAX); +} + +herr_t +H5T__conv__Float16_long(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, LONG, H5__Float16, long, LONG_MIN, LONG_MAX); +} + +herr_t +H5T__conv__Float16_ulong(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, ULONG, H5__Float16, unsigned long, 0, ULONG_MAX); +} + +herr_t +H5T__conv__Float16_llong(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, LLONG, H5__Float16, long long, LLONG_MIN, LLONG_MAX); +} + +herr_t +H5T__conv__Float16_ullong(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fX(FLOAT16, ULLONG, H5__Float16, unsigned long long, 0, ULLONG_MAX); +} + +herr_t +H5T__conv__Float16_float(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fF(FLOAT16, FLOAT, H5__Float16, float, -, -); +} + +herr_t +H5T__conv__Float16_double(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fF(FLOAT16, DOUBLE, H5__Float16, double, -, -); +} + +herr_t +H5T__conv__Float16_ldouble(H5T_t *st, H5T_t *dt, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx, + size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *buf, + void H5_ATTR_UNUSED *bkg) +{ + H5T_CONV_fF(FLOAT16, LDOUBLE, H5__Float16, long double, -, -); +} +#endif + /*------------------------------------------------------------------------- * Function: H5T__conv_f_i * @@ -8249,8 +8599,9 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx uint8_t *int_buf = NULL; /*buffer for temporary value */ size_t buf_size; /*buffer size for temporary value */ size_t i; /*miscellaneous counters */ - size_t first; /*first bit(MSB) in an integer */ - ssize_t sfirst; /*a signed version of `first' */ + ssize_t msb_pos_s; /*first bit(MSB) in an integer */ + ssize_t new_msb_pos; /*MSB position after shifting mantissa by exponent */ + hssize_t shift_val; /*shift value when shifting mantissa by exponent */ bool truncated; /*if fraction value is dropped */ bool reverse; /*if reverse order of destination at the end */ H5T_conv_ret_t except_ret; /*return of callback function */ @@ -8314,8 +8665,11 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx /* Allocate enough space for the buffer holding temporary * converted value */ - buf_size = (size_t)(pow(2.0, (double)src.u.f.esize) / 8 + 1); - int_buf = (uint8_t *)H5MM_calloc(buf_size); + if (dst.prec / 8 > src_p->shared->size) + buf_size = (dst.prec + 7) / 8; + else + buf_size = src_p->shared->size; + int_buf = (uint8_t *)H5MM_calloc(buf_size); /* Allocate space for order-reversed source buffer */ src_rev = (uint8_t *)H5MM_calloc(src_p->shared->size); @@ -8580,36 +8934,47 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx if (H5T_NORM_IMPLIED == src.u.f.norm) H5T__bit_inc(int_buf, src.u.f.msize, 8 * buf_size - src.u.f.msize); + /* + * What is the bit position for the most significant bit(MSB) of S + * which is set? This is checked before shifting and before possibly + * converting to a negative integer. Note that later use of this value + * assumes that H5T__bit_shift will always shift in 0 during a right + * shift. + */ + msb_pos_s = H5T__bit_find(int_buf, (size_t)0, src.prec, H5T_BIT_MSB, true); + + /* + * The temporary buffer has no bits set and must therefore be + * zero; nothing to do. + */ + if (msb_pos_s < 0) + goto padding; + /* * Shift mantissa part by exponent minus mantissa size(right shift), * or by mantissa size minus exponent(left shift). Example: Sequence * 10...010111, expo=20, expo-msize=-3. Right-shift the sequence, we get * 00010...10. The last three bits were dropped. */ - H5T__bit_shift(int_buf, expo - (ssize_t)src.u.f.msize, (size_t)0, buf_size * 8); + shift_val = expo - (ssize_t)src.u.f.msize; + H5T__bit_shift(int_buf, shift_val, (size_t)0, buf_size * 8); + + /* Calculate the new position of the MSB after shifting and + * skip to the padding section if we shifted exactly to 0 + * (MSB position is -1) + */ + new_msb_pos = msb_pos_s + shift_val; + if (new_msb_pos == -1) + goto padding; /* - * If expo is less than mantissa size, the frantional value is dropped off + * If expo is less than mantissa size, the fractional value is dropped off * during conversion. Set exception type to be "truncate" */ if ((size_t)expo < src.u.f.msize && conv_ctx->u.conv.cb_struct.func) truncated = true; - /* - * What is the bit position for the most significant bit(MSB) of S - * which is set? This is checked before converted to negative - * integer. - */ - sfirst = H5T__bit_find(int_buf, (size_t)0, 8 * buf_size, H5T_BIT_MSB, true); - first = (size_t)sfirst; - - if (sfirst < 0) { - /* - * The source has no bits set and must therefore be zero. - * Set the destination to zero - nothing to do. - */ - } - else if (H5T_SGN_NONE == dst.u.i.sign) { /*destination is unsigned*/ + if (H5T_SGN_NONE == dst.u.i.sign) { /*destination is unsigned*/ /* * Destination is unsigned. Library's default way: If the source value * is greater than the maximal destination value then it overflows, the @@ -8639,7 +9004,7 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx } } else { /*source is positive*/ - if (first >= dst.prec) { + if (new_msb_pos >= (ssize_t)dst.prec) { /*overflow*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ @@ -8663,7 +9028,7 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception"); } - else if (first < dst.prec) { + else { if (truncated && conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ /*reverse order first*/ @@ -8675,9 +9040,11 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx conv_ctx->u.conv.cb_struct.user_data); } - if (except_ret == H5T_CONV_UNHANDLED) + if (except_ret == H5T_CONV_UNHANDLED) { /*copy source value into it if case is ignored by user handler*/ - H5T__bit_copy(d, dst.offset, int_buf, (size_t)0, first + 1); + if (new_msb_pos >= 0) + H5T__bit_copy(d, dst.offset, int_buf, (size_t)0, (size_t)new_msb_pos + 1); + } else if (except_ret == H5T_CONV_HANDLED) { /*No need to reverse the order of destination because user handles it*/ reverse = false; @@ -8691,7 +9058,7 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx } else if (H5T_SGN_2 == dst.u.i.sign) { /*Destination is signed*/ if (sign) { /*source is negative*/ - if (first < dst.prec - 1) { + if ((new_msb_pos >= 0) && ((size_t)new_msb_pos < dst.prec - 1)) { if (truncated && conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ /*reverse order first*/ @@ -8705,8 +9072,8 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx if (except_ret == H5T_CONV_UNHANDLED) { /*If this case ignored by user handler*/ /*Convert to integer representation. Equivalent to ~(value - 1).*/ - H5T__bit_dec(int_buf, (size_t)0, 8 * buf_size); - H5T__bit_neg(int_buf, (size_t)0, 8 * buf_size); + H5T__bit_dec(int_buf, (size_t)0, dst.prec); + H5T__bit_neg(int_buf, (size_t)0, dst.prec); /*copy source value into destination*/ H5T__bit_copy(d, dst.offset, int_buf, (size_t)0, dst.prec - 1); @@ -8749,7 +9116,7 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx } } else { /*source is positive*/ - if (first >= dst.prec - 1) { + if (new_msb_pos >= (ssize_t)dst.prec - 1) { /*overflow*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ @@ -8773,7 +9140,7 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx goto next; } } - else if (first < dst.prec - 1) { + else if (new_msb_pos < (ssize_t)dst.prec - 1) { if (truncated && conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ /*reverse order first*/ @@ -8787,7 +9154,8 @@ H5T__conv_f_i(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx if (except_ret == H5T_CONV_UNHANDLED) { /*copy source value into it if case is ignored by user handler*/ - H5T__bit_copy(d, dst.offset, int_buf, (size_t)0, first + 1); + if (new_msb_pos >= 0) + H5T__bit_copy(d, dst.offset, int_buf, (size_t)0, (size_t)new_msb_pos + 1); } else if (except_ret == H5T_CONV_ABORT) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, @@ -8963,7 +9331,7 @@ H5T__conv_i_f(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx /* Allocate enough space for the buffer holding temporary * converted value */ - buf_size = (src.prec > dst.u.f.msize ? src.prec : dst.u.f.msize) / 8 + 1; + buf_size = ((src.prec > dst.u.f.msize ? src.prec : dst.u.f.msize) + 7) / 8; int_buf = (uint8_t *)H5MM_calloc(buf_size); /* Allocate space for order-reversed source buffer */ @@ -9189,7 +9557,8 @@ H5T__conv_i_f(H5T_t *src_p, H5T_t *dst_p, H5T_cdata_t *cdata, const H5T_conv_ctx goto padding; } } - else { + + if (!conv_ctx->u.conv.cb_struct.func || (except_ret == H5T_CONV_UNHANDLED)) { /*make destination infinity by setting exponent to maximal number and *mantissa to zero.*/ expo = expo_max; diff --git a/src/H5Tinit_float.c b/src/H5Tinit_float.c index 8384c3161df..de959b49735 100644 --- a/src/H5Tinit_float.c +++ b/src/H5Tinit_float.c @@ -54,8 +54,8 @@ * Purpose: This macro takes a floating point type like `double' and * and detects byte order, mantissa location, exponent location, * sign bit location, presence or absence of implicit mantissa - * bit, and exponent bias and initializes a detected_t structure - * with those properties. + * bit, and exponent bias and initializes a H5T_fpoint_det_t + * structure with those properties. * * Note that these operations can raise floating-point * exceptions and building with some compiler options @@ -307,14 +307,17 @@ H5T__fix_order(int n, int last, int *perm, H5T_order_t *order) if (last <= 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "failed to detect byte order"); - /* We have at least three points to consider */ - if (perm[last] < perm[last - 1] && perm[last - 1] < perm[last - 2]) { + if (perm[last] < perm[last - 1] && + /* Only check perm[last - 2] if we have more than 2 points to consider */ + ((last < 2) || (perm[last - 1] < perm[last - 2]))) { /* Little endian */ *order = H5T_ORDER_LE; for (int i = 0; i < n; i++) perm[i] = i; } - else if (perm[last] > perm[last - 1] && perm[last - 1] > perm[last - 2]) { + else if (perm[last] > perm[last - 1] && + /* Only check perm[last - 2] if we have more than 2 points to consider */ + ((last < 2) || (perm[last - 1] > perm[last - 2]))) { /* Big endian */ *order = H5T_ORDER_BE; for (int i = 0; i < n; i++) @@ -359,7 +362,7 @@ H5T__fix_order(int n, int last, int *perm, H5T_order_t *order) * Return: imp_bit will be set to 1 if the most significant bit * of the mantissa is discarded (ie, the mantissa has an * implicit `one' as the most significant bit). Otherwise, - * imp_bit will be set to zero zero. + * imp_bit will be set to zero. * * SUCCEED/FAIL *------------------------------------------------------------------------- @@ -571,6 +574,39 @@ H5T__init_native_float_types(void) */ H5T_native_order_g = det.order; +#ifdef H5_HAVE__FLOAT16 + /* H5T_NATIVE_FLOAT16 */ + + /* Get the type's characteristics */ + memset(&det, 0, sizeof(H5T_fpoint_det_t)); + DETECT_F(H5__Float16, det); + + /* Allocate and fill type structure */ + if (NULL == (dt = H5T__alloc())) + HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, FAIL, "datatype allocation failed"); + dt->shared->state = H5T_STATE_IMMUTABLE; + dt->shared->type = H5T_FLOAT; + dt->shared->size = det.size; + dt->shared->u.atomic.order = det.order; + dt->shared->u.atomic.offset = det.offset; + dt->shared->u.atomic.prec = det.prec; + dt->shared->u.atomic.lsb_pad = H5T_PAD_ZERO; + dt->shared->u.atomic.msb_pad = H5T_PAD_ZERO; + dt->shared->u.atomic.u.f.sign = det.sign; + dt->shared->u.atomic.u.f.epos = det.epos; + dt->shared->u.atomic.u.f.esize = det.esize; + dt->shared->u.atomic.u.f.ebias = det.ebias; + dt->shared->u.atomic.u.f.mpos = det.mpos; + dt->shared->u.atomic.u.f.msize = det.msize; + dt->shared->u.atomic.u.f.norm = det.norm; + dt->shared->u.atomic.u.f.pad = H5T_PAD_ZERO; + + /* Register the type and set global variables */ + if ((H5T_NATIVE_FLOAT16_g = H5I_register(H5I_DATATYPE, dt, false)) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "can't register ID for built-in datatype"); + H5T_NATIVE_FLOAT16_ALIGN_g = det.comp_align; +#endif + done: /* Clear any FE_INVALID exceptions from NaN handling */ if (feclearexcept(FE_INVALID) != 0) diff --git a/src/H5Tmodule.h b/src/H5Tmodule.h index f1b7b175f2e..35e748bac3f 100644 --- a/src/H5Tmodule.h +++ b/src/H5Tmodule.h @@ -712,6 +712,14 @@ * * * + * #H5T_NATIVE_FLOAT16 + * + * + * _Float16 + * + * + * + * * #H5T_NATIVE_FLOAT * * @@ -3732,8 +3740,8 @@ filled according to the value of this property. The padding can be: * datatypes. * * The currently supported text format used by #H5LTtext_to_dtype and #H5LTdtype_to_text is the - * data description language (DDL) and conforms to the \ref DDLBNF110. The portion of the - * \ref DDLBNF110 that defines HDF5 datatypes appears below. + * data description language (DDL) and conforms to the \ref DDLBNF114. The portion of the + * \ref DDLBNF114 that defines HDF5 datatypes appears below. * The definition of HDF5 datatypes from the HDF5 DDL * \code * ::= | | | @@ -3753,10 +3761,11 @@ filled according to the value of this property. The padding can be: * H5T_NATIVE_INT | H5T_NATIVE_UINT | * H5T_NATIVE_LONG | H5T_NATIVE_ULONG | * H5T_NATIVE_LLONG | H5T_NATIVE_ULLONG - * ::= H5T_IEEE_F32BE | H5T_IEEE_F32LE | + * ::= H5T_IEEE_F16BE | H5T_IEEE_F16LE | + * H5T_IEEE_F32BE | H5T_IEEE_F32LE | * H5T_IEEE_F64BE | H5T_IEEE_F64LE | - * H5T_NATIVE_FLOAT | H5T_NATIVE_DOUBLE | - * H5T_NATIVE_LDOUBLE + * H5T_NATIVE_FLOAT16 | H5T_NATIVE_FLOAT | + * H5T_NATIVE_DOUBLE | H5T_NATIVE_LDOUBLE *