diff --git a/.clang-format b/.clang-format index 3c2dece7082..de4f8b8e95c 100644 --- a/.clang-format +++ b/.clang-format @@ -58,8 +58,8 @@ IndentCaseLabels: true IndentGotoLabels: false #llvm11: IndentExternBlock: AfterExternBlock #llvm11: InsertTrailingCommas: None -MacroBlockBegin: "^BEGIN_FUNC" -MacroBlockEnd: "^END_FUNC" +MacroBlockBegin: "^H5_BEFORE_USER_CB*|^H5E_PAUSE_ERRORS" +MacroBlockEnd: "^H5_AFTER_USER_CB*|^H5E_RESUME_ERRORS" ObjCBlockIndentWidth: 4 #llvm11: ObjCBreakBeforeNestedBlockParam: true ReflowComments: true @@ -81,9 +81,8 @@ StatementMacros: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY - FUNC_LEAVE_NOAPI_NOFS + - H5E_BEGIN_TRY - H5E_END_TRY - - H5E_PRINTF - - H5E_THROW - H5_BEGIN_TAG - H5_END_TAG - H5_GCC_DIAG_OFF diff --git a/.github/workflows/autotools.yml b/.github/workflows/autotools.yml index f32c4bce759..74d154c4f29 100644 --- a/.github/workflows/autotools.yml +++ b/.github/workflows/autotools.yml @@ -44,10 +44,27 @@ jobs: with: build_mode: "production" + call-debug-concurrent-autotools: + name: "Autotools Debug Concurrency Workflows" + uses: ./.github/workflows/main-auto.yml + with: + concurrent: enable + thread_safety: disable + build_mode: "debug" + + call-release-concurrent-autotools: + name: "Autotools Release Concurrency Workflows" + uses: ./.github/workflows/main-auto.yml + with: + concurrent: enable + thread_safety: disable + build_mode: "production" + call-debug-thread-autotools: name: "Autotools Debug Thread-Safety Workflows" uses: ./.github/workflows/main-auto.yml with: + concurrent: disable thread_safety: enable build_mode: "debug" @@ -55,6 +72,7 @@ jobs: name: "Autotools Release Thread-Safety Workflows" uses: ./.github/workflows/main-auto.yml with: + concurrent: disable thread_safety: enable build_mode: "production" @@ -62,6 +80,7 @@ jobs: name: "Autotools Debug Workflows" uses: ./.github/workflows/main-auto.yml with: + concurrent: disable thread_safety: disable build_mode: "debug" @@ -69,6 +88,7 @@ jobs: name: "Autotools Release Workflows" uses: ./.github/workflows/main-auto.yml with: + concurrent: disable thread_safety: disable build_mode: "production" diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 0305d10c530..a1f1b0b04be 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -28,10 +28,27 @@ jobs: name: "CMake Special Workflows" uses: ./.github/workflows/main-cmake-spc.yml + call-debug-concurrent-cmake: + name: "CMake Debug Concurrency Workflows" + uses: ./.github/workflows/main-cmake.yml + with: + concurrent: "CC" + thread_safety: "" + build_mode: "Debug" + + call-release-concurrent-cmake: + name: "CMake Release Concurrency Workflows" + uses: ./.github/workflows/main-cmake.yml + with: + concurrent: "CC" + thread_safety: "" + build_mode: "Release" + call-debug-thread-cmake: name: "CMake Debug Thread-Safety Workflows" uses: ./.github/workflows/main-cmake.yml with: + concurrent: "" thread_safety: "TS" build_mode: "Debug" @@ -39,6 +56,7 @@ jobs: name: "CMake Release Thread-Safety Workflows" uses: ./.github/workflows/main-cmake.yml with: + concurrent: "" thread_safety: "TS" build_mode: "Release" @@ -46,6 +64,7 @@ jobs: name: "CMake Debug Workflows" uses: ./.github/workflows/main-cmake.yml with: + concurrent: "" thread_safety: "" build_mode: "Debug" @@ -53,6 +72,7 @@ jobs: name: "CMake Release Workflows" uses: ./.github/workflows/main-cmake.yml with: + concurrent: "" thread_safety: "" build_mode: "Release" diff --git a/.github/workflows/main-auto.yml b/.github/workflows/main-auto.yml index 83bbfd2a0c8..d0b023f4a45 100644 --- a/.github/workflows/main-auto.yml +++ b/.github/workflows/main-auto.yml @@ -8,6 +8,10 @@ on: description: "thread-safety enable/disable" required: true type: string + concurrent: + description: "concurrency enable/disable" + required: true + type: string build_mode: description: "release vs. debug build" required: true @@ -22,7 +26,7 @@ jobs: # Linux (Ubuntu) w/ gcc + Autotools # Autotools_build_and_test: - name: "GCC-${{ inputs.build_mode }}-TS=${{ inputs.thread_safety }}d" + name: "GCC-${{ inputs.build_mode }}-TS=${{ inputs.thread_safety }}d-CC=${{ inputs.concurrent }}d" # Don't run the action if the commit message says to skip CI if: "!contains(github.event.head_commit.message, 'skip-ci')" @@ -60,6 +64,7 @@ jobs: --enable-shared \ --disable-parallel \ --${{ inputs.thread_safety }}-threadsafe \ + --${{ inputs.concurrent }}-concurrency \ --enable-cxx \ --enable-fortran \ --enable-java \ @@ -68,7 +73,7 @@ jobs: --enable-ros3-vfd \ --with-szlib=yes shell: bash - if: ${{ inputs.thread_safety == 'disable' }} + if: ${{ inputs.thread_safety == 'disable' && inputs.concurrent == 'disable'}} - name: Autotools Configure (Thread-Safe) run: | @@ -79,6 +84,7 @@ jobs: --enable-build-mode=${{ inputs.build_mode }} \ --enable-shared \ --${{ inputs.thread_safety }}-threadsafe \ + --${{ inputs.concurrent }}-concurrency \ --disable-hl \ --disable-parallel \ --enable-mirror-vfd \ @@ -86,7 +92,26 @@ jobs: --enable-ros3-vfd \ --with-szlib=yes shell: bash - if: ${{ inputs.thread_safety == 'enable' }} + if: ${{ inputs.thread_safety == 'enable' && inputs.concurrent == 'disable' }} + + - name: Autotools Configure (Concurrency) + run: | + sh ./autogen.sh + mkdir "${{ runner.workspace }}/build" + cd "${{ runner.workspace }}/build" + $GITHUB_WORKSPACE/configure \ + --enable-build-mode=${{ inputs.build_mode }} \ + --enable-shared \ + --${{ inputs.thread_safety }}-threadsafe \ + --${{ inputs.concurrent }}-concurrency \ + --disable-hl \ + --disable-parallel \ + --enable-mirror-vfd \ + --enable-direct-vfd \ + --enable-ros3-vfd \ + --with-szlib=yes + shell: bash + if: ${{ inputs.thread_safety == 'disable' && inputs.concurrent == 'enable' }} - name: Autotools Build run: make -j3 diff --git a/.github/workflows/main-cmake.yml b/.github/workflows/main-cmake.yml index c59167ea6ac..f054eae2048 100644 --- a/.github/workflows/main-cmake.yml +++ b/.github/workflows/main-cmake.yml @@ -8,6 +8,10 @@ on: description: "TS or empty" required: true type: string + concurrent: + description: "CC or empty" + required: true + type: string build_mode: description: "release vs. debug build" required: true @@ -103,7 +107,7 @@ jobs: run_tests: true # Sets the job's name from the properties - name: "${{ matrix.name }}-${{ inputs.build_mode }}-${{ inputs.thread_safety }}" + name: "${{ matrix.name }}-${{ inputs.build_mode }}-${{ inputs.thread_safety }}-${{ inputs.concurrent }}" # Don't run the action if the commit message says to skip CI if: "!contains(github.event.head_commit.message, 'skip-ci')" @@ -186,7 +190,7 @@ jobs: -DHDF5_PACK_MACOSX_DMG:BOOL=OFF \ $GITHUB_WORKSPACE shell: bash - if: ${{ inputs.thread_safety != 'TS' }} + if: ${{ inputs.thread_safety != 'TS' && inputs.concurrent != 'CC'}} - name: CMake Configure (Thread-Safe) run: | @@ -199,6 +203,7 @@ jobs: -DBUILD_STATIC_LIBS:BOOL=${{ (matrix.os != 'windows-latest') }} \ -DHDF5_ENABLE_ALL_WARNINGS:BOOL=ON \ -DHDF5_ENABLE_THREADSAFE:BOOL=ON \ + -DHDF5_ENABLE_CONCURRENCY:BOOL=OFF \ -DHDF5_ENABLE_PARALLEL:BOOL=${{ matrix.parallel }} \ -DHDF5_BUILD_CPP_LIB:BOOL=OFF \ -DHDF5_BUILD_FORTRAN:BOOL=OFF \ @@ -214,7 +219,35 @@ jobs: -DHDF5_PACK_MACOSX_DMG:BOOL=OFF \ $GITHUB_WORKSPACE shell: bash - if: ${{ inputs.thread_safety == 'TS' }} + if: ${{ inputs.thread_safety == 'TS' && inputs.concurrent != 'CC'}} + + - name: CMake Configure (Concurrency) + run: | + mkdir "${{ runner.workspace }}/build" + cd "${{ runner.workspace }}/build" + cmake -C $GITHUB_WORKSPACE/config/cmake/cacheinit.cmake \ + ${{ matrix.generator }} \ + -DCMAKE_BUILD_TYPE=${{ inputs.build_mode }} \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_STATIC_LIBS=${{ (matrix.os != 'windows-latest') }} \ + -DHDF5_ENABLE_ALL_WARNINGS=ON \ + -DHDF5_ENABLE_THREADSAFE:BOOL=OFF \ + -DHDF5_ENABLE_CONCURRENCY:BOOL=ON \ + -DHDF5_ENABLE_PARALLEL:BOOL=${{ matrix.parallel }} \ + -DHDF5_BUILD_CPP_LIB:BOOL=OFF \ + -DHDF5_BUILD_FORTRAN:BOOL=OFF \ + -DHDF5_BUILD_JAVA:BOOL=OFF \ + -DHDF5_BUILD_HL_LIB:BOOL=OFF \ + -DHDF5_BUILD_DOC=OFF \ + -DLIBAEC_USE_LOCALCONTENT=${{ matrix.localaec }} \ + -DZLIB_USE_LOCALCONTENT=${{ matrix.localzlib }} \ + -DHDF5_ENABLE_MIRROR_VFD:BOOL=${{ matrix.mirror_vfd }} \ + -DHDF5_ENABLE_DIRECT_VFD:BOOL=${{ matrix.direct_vfd }} \ + -DHDF5_ENABLE_ROS3_VFD:BOOL=${{ matrix.ros3_vfd }} \ + -DHDF5_PACK_EXAMPLES:BOOL=ON \ + $GITHUB_WORKSPACE + shell: bash + if: ${{ inputs.thread_safety != 'TS' && inputs.concurrent == 'CC'}} # BUILD - name: CMake Build @@ -225,13 +258,7 @@ jobs: - name: CMake Run Tests run: ctest . --parallel 2 -C ${{ inputs.build_mode }} -V working-directory: ${{ runner.workspace }}/build - if: ${{ matrix.run_tests && (inputs.thread_safety != 'TS') }} - - # THREAD-SAFE - - name: CMake Run Thread-Safe Tests - run: ctest . --parallel 2 -C ${{ inputs.build_mode }} -V -R ttsafe - working-directory: ${{ runner.workspace }}/build - if: ${{ matrix.run_tests && (inputs.thread_safety == 'TS') }} + if: ${{ matrix.run_tests }} - name: CMake Run Package run: cpack -C ${{ inputs.build_mode }} -V @@ -253,7 +280,7 @@ jobs: name: zip-vs2022_cl-${{ inputs.build_mode }}-binary path: ${{ runner.workspace }}/build/HDF5-*-win64.zip if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` - if: ${{ (matrix.os == 'windows-latest') && (inputs.thread_safety != 'TS') && ( inputs.build_mode != 'Debug') }} + if: ${{ (matrix.os == 'windows-latest') && (inputs.thread_safety != 'TS') && (inputs.concurrent != 'CC') && ( inputs.build_mode != 'Debug') }} - name: Save published binary (linux) uses: actions/upload-artifact@v4 @@ -261,7 +288,7 @@ jobs: name: tgz-ubuntu-2404_gcc-${{ inputs.build_mode }}-binary path: ${{ runner.workspace }}/build/HDF5-*-Linux.tar.gz if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` - if: ${{ (matrix.os == 'ubuntu-latest') && (inputs.thread_safety != 'TS') && ( inputs.build_mode != 'Debug') }} + if: ${{ (matrix.os == 'ubuntu-latest') && (inputs.thread_safety != 'TS') && (inputs.concurrent != 'CC') && ( inputs.build_mode != 'Debug') }} - name: Save published binary (Mac_latest) uses: actions/upload-artifact@v4 @@ -269,4 +296,4 @@ jobs: name: tgz-macos14_clang-${{ inputs.build_mode }}-binary path: ${{ runner.workspace }}/build/HDF5-*-Darwin.tar.gz if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` - if: ${{ (matrix.os == 'macos-latest') && (inputs.thread_safety != 'TS') && ( inputs.build_mode != 'Debug') }} + if: ${{ (matrix.os == 'macos-latest') && (inputs.thread_safety != 'TS') && (inputs.concurrent != 'CC') && ( inputs.build_mode != 'Debug') }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c8366d8393..73dc2d3ee28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -985,6 +985,59 @@ if (HDF5_ENABLE_THREADSAFE) set (H5_HAVE_THREADSAFE 1) endif () +#----------------------------------------------------------------------------- +# Option to use multi-threaded concurrency +#----------------------------------------------------------------------------- +option (HDF5_ENABLE_CONCURRENCY "Enable multi-threaded concurrency" OFF) +if (HDF5_ENABLE_CONCURRENCY) + # check for unsupported options + if (WIN32) + if (BUILD_STATIC_LIBS) + message (FATAL_ERROR " **** multi-threaded concurrency option not supported with static library **** ") + endif () + endif () + if (HDF_ENABLE_PARALLEL) + if (NOT ALLOW_UNSUPPORTED) + message (FATAL_ERROR " **** Parallel and multi-threaded concurrency options are not supported, override with ALLOW_UNSUPPORTED option **** ") + else () + message (VERBOSE " **** Allowing unsupported parallel and multi-threaded concurrency options **** ") + endif () + endif () + if (HDF5_BUILD_FORTRAN) + if (NOT ALLOW_UNSUPPORTED) + message (FATAL_ERROR " **** Fortran and multi-threaded concurrency options are not supported, override with ALLOW_UNSUPPORTED option **** ") + else () + message (VERBOSE " **** Allowing unsupported Fortran and multi-threaded concurrency options **** ") + endif () + endif () + if (HDF5_BUILD_CPP_LIB) + if (NOT ALLOW_UNSUPPORTED) + message (FATAL_ERROR " **** C++ and multi-threaded concurrency options are not supported, override with ALLOW_UNSUPPORTED option **** ") + else () + message (VERBOSE " **** Allowing unsupported C++ and multi-threaded concurrency options **** ") + endif () + endif () + if (HDF5_BUILD_HL_LIB) + if (NOT ALLOW_UNSUPPORTED) + message (FATAL_ERROR " **** HL and multi-threaded concurrency options are not supported, override with ALLOW_UNSUPPORTED option **** ") + else () + message (VERBOSE " **** Allowing unsupported HL and multi-threaded concurrency options **** ") + endif () + endif () + + # Check for threading package + if (NOT Threads_FOUND) + message (FATAL_ERROR " **** multi-threaded concurrency option requires a threading package and none was found **** ") + endif () + + # Multi-threaded concurrency and threadsafe options are mutually exclusive + if (HDF5_ENABLE_THREADSAFE) + message (FATAL_ERROR " **** multi-threaded concurrency and threadsafe options are mutually exclusive **** ") + endif () + + set (H5_HAVE_CONCURRENCY 1) +endif () + #----------------------------------------------------------------------------- # Option to build the map API #----------------------------------------------------------------------------- diff --git a/LICENSE b/LICENSE index 38061fb7854..a660f0c14ae 100644 --- a/LICENSE +++ b/LICENSE @@ -1,103 +1,103 @@ -Copyright Notice and License Terms for +Copyright Notice and License Terms for HDF5 (Hierarchical Data Format 5) Software Library and Utilities ----------------------------------------------------------------------------- HDF5 (Hierarchical Data Format 5) Software Library and Utilities -Copyright 2006 by The HDF Group. +Copyright 2006 by The HDF Group. NCSA HDF5 (Hierarchical Data Format 5) Software Library and Utilities -Copyright 1998-2006 by The Board of Trustees of the University of Illinois. +Copyright 1998-2006 by The Board of Trustees of the University of Illinois. All rights reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted for any purpose (including commercial purposes) +Redistribution and use in source and binary forms, with or without +modification, are permitted for any purpose (including commercial purposes) provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, +1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions, and the following disclaimer in the documentation +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation and/or materials provided with the distribution. -3. Neither the name of The HDF Group, the name of the University, nor the - name of any Contributor may be used to endorse or promote products derived - from this software without specific prior written permission from +3. Neither the name of The HDF Group, the name of the University, nor the + name of any Contributor may be used to endorse or promote products derived + from this software without specific prior written permission from The HDF Group, the University, or the Contributor, respectively. -DISCLAIMER: -THIS SOFTWARE IS PROVIDED BY THE HDF GROUP AND THE CONTRIBUTORS -"AS IS" WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED. IN NO -EVENT SHALL THE HDF GROUP OR THE CONTRIBUTORS BE LIABLE FOR ANY DAMAGES -SUFFERED BY THE USERS ARISING OUT OF THE USE OF THIS SOFTWARE, EVEN IF +DISCLAIMER: +THIS SOFTWARE IS PROVIDED BY THE HDF GROUP AND THE CONTRIBUTORS +"AS IS" WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED. IN NO +EVENT SHALL THE HDF GROUP OR THE CONTRIBUTORS BE LIABLE FOR ANY DAMAGES +SUFFERED BY THE USERS ARISING OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -You are under no obligation whatsoever to provide any bug fixes, patches, or -upgrades to the features, functionality or performance of the source code -("Enhancements") to anyone; however, if you choose to make your Enhancements -available either publicly, or directly to The HDF Group, without imposing a -separate written license agreement for such Enhancements, then you hereby -grant the following license: a non-exclusive, royalty-free perpetual license -to install, use, modify, prepare derivative works, incorporate into other -computer software, distribute, and sublicense such enhancements or derivative + +You are under no obligation whatsoever to provide any bug fixes, patches, or +upgrades to the features, functionality or performance of the source code +("Enhancements") to anyone; however, if you choose to make your Enhancements +available either publicly, or directly to The HDF Group, without imposing a +separate written license agreement for such Enhancements, then you hereby +grant the following license: a non-exclusive, royalty-free perpetual license +to install, use, modify, prepare derivative works, incorporate into other +computer software, distribute, and sublicense such enhancements or derivative works thereof, in binary and source code form. ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -Limited portions of HDF5 1.12.0 were developed by Lawrence Berkeley National +Limited portions of HDF5 1.12.0 were developed by Lawrence Berkeley National Laboratory (LBNL). LBNL's Copyright Notice and Licensing Terms can be found in the LICENSE_LBNL_HDF5 file in this directory. ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -Contributors: National Center for Supercomputing Applications (NCSA) at -the University of Illinois, Fortner Software, Unidata Program Center -(netCDF), The Independent JPEG Group (JPEG), Jean-loup Gailly and Mark Adler +Contributors: National Center for Supercomputing Applications (NCSA) at +the University of Illinois, Fortner Software, Unidata Program Center +(netCDF), The Independent JPEG Group (JPEG), Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment Corporation (DEC). ----------------------------------------------------------------------------- - -Portions of HDF5 were developed with support from the Lawrence Berkeley -National Laboratory (LBNL) and the United States Department of Energy + +Portions of HDF5 were developed with support from the Lawrence Berkeley +National Laboratory (LBNL) and the United States Department of Energy under Prime Contract No. DE-AC02-05CH11231. ----------------------------------------------------------------------------- -Portions of HDF5 were developed with support from Lawrence Livermore -National Laboratory and the United States Department of Energy under +Portions of HDF5 were developed with support from Lawrence Livermore +National Laboratory and the United States Department of Energy under Prime Contract No. DE-AC52-07NA27344. ----------------------------------------------------------------------------- -Portions of HDF5 were developed with support from the University of -California, Lawrence Livermore National Laboratory (UC LLNL). -The following statement applies to those portions of the product and must -be retained in any redistribution of source code, binaries, documentation, +Portions of HDF5 were developed with support from the University of +California, Lawrence Livermore National Laboratory (UC LLNL). +The following statement applies to those portions of the product and must +be retained in any redistribution of source code, binaries, documentation, and/or accompanying materials: - This work was partially produced at the University of California, - Lawrence Livermore National Laboratory (UC LLNL) under contract - no. W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy - (DOE) and The Regents of the University of California (University) + This work was partially produced at the University of California, + Lawrence Livermore National Laboratory (UC LLNL) under contract + no. W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy + (DOE) and The Regents of the University of California (University) for the operation of UC LLNL. - DISCLAIMER: - THIS WORK WAS PREPARED AS AN ACCOUNT OF WORK SPONSORED BY AN AGENCY OF - THE UNITED STATES GOVERNMENT. NEITHER THE UNITED STATES GOVERNMENT NOR - THE UNIVERSITY OF CALIFORNIA NOR ANY OF THEIR EMPLOYEES, MAKES ANY - WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY OR RESPONSIBILITY - FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY INFORMATION, - APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS THAT ITS USE - WOULD NOT INFRINGE PRIVATELY- OWNED RIGHTS. REFERENCE HEREIN TO ANY - SPECIFIC COMMERCIAL PRODUCTS, PROCESS, OR SERVICE BY TRADE NAME, - TRADEMARK, MANUFACTURER, OR OTHERWISE, DOES NOT NECESSARILY CONSTITUTE - OR IMPLY ITS ENDORSEMENT, RECOMMENDATION, OR FAVORING BY THE UNITED - STATES GOVERNMENT OR THE UNIVERSITY OF CALIFORNIA. THE VIEWS AND - OPINIONS OF AUTHORS EXPRESSED HEREIN DO NOT NECESSARILY STATE OR REFLECT - THOSE OF THE UNITED STATES GOVERNMENT OR THE UNIVERSITY OF CALIFORNIA, + DISCLAIMER: + THIS WORK WAS PREPARED AS AN ACCOUNT OF WORK SPONSORED BY AN AGENCY OF + THE UNITED STATES GOVERNMENT. NEITHER THE UNITED STATES GOVERNMENT NOR + THE UNIVERSITY OF CALIFORNIA NOR ANY OF THEIR EMPLOYEES, MAKES ANY + WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY OR RESPONSIBILITY + FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY INFORMATION, + APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS THAT ITS USE + WOULD NOT INFRINGE PRIVATELY- OWNED RIGHTS. REFERENCE HEREIN TO ANY + SPECIFIC COMMERCIAL PRODUCTS, PROCESS, OR SERVICE BY TRADE NAME, + TRADEMARK, MANUFACTURER, OR OTHERWISE, DOES NOT NECESSARILY CONSTITUTE + OR IMPLY ITS ENDORSEMENT, RECOMMENDATION, OR FAVORING BY THE UNITED + STATES GOVERNMENT OR THE UNIVERSITY OF CALIFORNIA. THE VIEWS AND + OPINIONS OF AUTHORS EXPRESSED HEREIN DO NOT NECESSARILY STATE OR REFLECT + THOSE OF THE UNITED STATES GOVERNMENT OR THE UNIVERSITY OF CALIFORNIA, AND SHALL NOT BE USED FOR ADVERTISING OR PRODUCT ENDORSEMENT PURPOSES. ----------------------------------------------------------------------------- diff --git a/config/cmake/H5pubconf.h.in b/config/cmake/H5pubconf.h.in index 9d495ceac1e..00012ace66b 100644 --- a/config/cmake/H5pubconf.h.in +++ b/config/cmake/H5pubconf.h.in @@ -336,6 +336,14 @@ # cmakedefine H5_HAVE_THREADSAFE @H5_HAVE_THREADSAFE@ #endif +#if defined(_WIN32) && !defined(H5_BUILT_AS_DYNAMIC_LIB) +/* Not supported on WIN32 platforms with static linking */ +/* #undef H5_HAVE_CONCURRENCY */ +#else +/* Define if we have multi-threaded concurrency support */ +# cmakedefine H5_HAVE_CONCURRENCY @H5_HAVE_CONCURRENCY@ +#endif + /* Define if timezone is a global variable */ #cmakedefine H5_HAVE_TIMEZONE @H5_HAVE_TIMEZONE@ diff --git a/configure.ac b/configure.ac index 5a8f31a4d33..72bc8f91b76 100644 --- a/configure.ac +++ b/configure.ac @@ -2419,6 +2419,88 @@ case "X-$THREADSAFE" in esac +## ---------------------------------------------------------------------- +## Enable multi-threaded concurrent version of library +## +## Note: requires threads support +## +AC_SUBST([CONCURRENCY]) + +## Default is no multi-threaded concurrency +CONCURRENCY=no + +AC_MSG_CHECKING([for concurrency support]) +AC_ARG_ENABLE([concurrency], + [AS_HELP_STRING([--enable-concurrency], + [Enable multi-threaded concurrency capability. Not compatible with the high-level library, Fortran, or C++ wrappers. + [default=no]])], + [CONCURRENCY=$enableval]) + +## The high-level, C++, Fortran and Java interfaces are not compatible +## with the thread-safety option because the lock is not hoisted +## into the higher-level API calls. + +## --enable-concurrency is incompatible with --enable-hl unless +## --enable-unsupported has been specified on the configure line. +## +## Note that the high-level library is enabled by default so most +## users will have to add --disable-hl to the configure options. +if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then + if test "X${HDF5_HL}" = "Xyes" -a "X${enable_concurrency}" = "Xyes"; then + AC_MSG_ERROR([The multi-threaded concurrent library is incompatible with the high-level library. --disable-hl can be used to prevent building the high-level library (recommended). Alternatively, --enable-unsupported will allow building the high-level library, though this configuration is not supported by The HDF Group.]) + fi +fi + +## The --enable-concurrency flag is not compatible with --enable-cxx. +## If the user tried to specify both flags, throw an error, unless +## they also provided the --enable-unsupported flag. +if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then + if test "X${HDF_CXX}" = "Xyes" -a "X${enable_concurrency}" = "Xyes"; then + AC_MSG_ERROR([--enable-cxx and --enable-concurrency flags are incompatible. Use --enable-unsupported to override this error.]) + fi +fi + +## --enable-concurrency is also incompatible with --enable-fortran unless +## --enable-unsupported has been specified on the configure line. +if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then + if test "X${HDF_FORTRAN}" = "Xyes" -a "X${enable_concurrency}" = "Xyes"; then + AC_MSG_ERROR([--enable-fortran and --enable-concurrency flags are incompatible. Use --enable-unsupported to override this error.]) + fi +fi + +## --enable-concurrency is also incompatible with --enable-java unless +## --enable-unsupported has been specified on the configure line. +if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then + if test "X${HDF_JAVA}" = "Xyes" -a "X${enable_concurrency}" = "Xyes"; then + AC_MSG_ERROR([--enable-java and --enable-concurrency flags are incompatible. Use --enable-unsupported to override this error.]) + fi +fi + +# Need a threading package to enable multi-threaded concurrency +if test "X${enable_concurrency}" = "Xyes" -a "X$THREADS" = "Xno"; then + AC_MSG_ERROR([--enable-concurrency given, but no threading package found.]) +fi + +# The concurrency and threadsafe options are mutually exclusive +if test "X${enable_concurrency}" = "Xyes" -a "X${enable_threadsafe}" = "Xyes"; then + AC_MSG_ERROR([--enable-threadsafe and --enable-concurrency are mutually exclusive]) +fi + +case "X-$CONCURRENCY" in + X-|X-no) + AC_MSG_RESULT([no]) + ;; + X-yes) + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_CONCURRENCY], [1], [Define if we have multi-threaded concurrency support]) + ;; + *) + AC_MSG_RESULT([error]) + AC_MSG_ERROR([\'$enableval\' is not a valid concurrency type]) + ;; +esac + + ## ---------------------------------------------------------------------- ## Check for MONOTONIC_TIMER support (used in clock_gettime). This has ## to be done after any POSIX defines to ensure that the test gets diff --git a/release_docs/INSTALL_Autotools.txt b/release_docs/INSTALL_Autotools.txt index 07c3b7f0182..7335ce5b156 100644 --- a/release_docs/INSTALL_Autotools.txt +++ b/release_docs/INSTALL_Autotools.txt @@ -320,14 +320,14 @@ III. Full installation instructions for source distributions parallelism on a distributed multi-processor system. Read the file INSTALL_parallel for detailed information. - The threadsafe, C++ and Java interfaces are not compatible - with the parallel option. + The threadsafe and multi-threaded concurrency options and the C++ and + Java interfaces are not compatible with the parallel option. Unless --enable-unsupported has been specified on the configure line, the following options must be disabled: - --enable-threadsafe, --enable-cxx, --enable-java + --enable-threadsafe, --enable-concurrency, --enable-cxx, --enable-java - 3.10. Threadsafe capability + 3.10. Threadsafe and multi-threaded concurrency capabilities The HDF5 library can be configured to be thread-safe (on a very large scale) with the `--enable-threadsafe' flag to the configure script. Some platforms may also require the '-with-pthread=INC,LIB' @@ -343,6 +343,21 @@ III. Full installation instructions for source distributions the following options must be disabled: --enable-hl, --enable-cxx, --enable-fortran, --enable-java + The multi-threaded concurrency option improves upon the basic + thread-safe capability by providing both threadsafety for API calls + and allowing multi-threaded concurrent execution within the library. + This may be enabled with the '--enable-concurrency' configure option, + which is mutually exclusive with the '--enable-threadsafe' option. + + The current list of API routines that are enabled for concurrent + execution by multiple threads is: + + The high-level, C++, Fortran, and Java interfaces are not compatible + with the multi-threaded concurrency option because the lock is not + hoisted into the higher-level API calls. + Unless --enable-unsupported has been specified on the configure line, + the following options must be disabled: + --enable-hl, --enable-cxx, --enable-fortran, --enable-java 3.11. Backward compatibility The 2.0.0 version of the HDF5 library can be configured to operate diff --git a/release_docs/INSTALL_CMake.txt b/release_docs/INSTALL_CMake.txt index 1a855b60396..19044fe4385 100644 --- a/release_docs/INSTALL_CMake.txt +++ b/release_docs/INSTALL_CMake.txt @@ -858,6 +858,7 @@ HDF5_ONLY_SHARED_LIBS "Only Build Shared Libraries" HDF5_ALLOW_UNSUPPORTED "Allow unsupported combinations of configure options" OFF HDF5_ENABLE_PARALLEL "Enable parallel build (requires MPI)" OFF HDF5_ENABLE_THREADSAFE "Enable Threadsafety" OFF +HDF5_ENABLE_CONCURRENCY "Enable multi-threaded concurrency" OFF HDF5_DIMENSION_SCALES_NEW_REF "Use new-style references with dimension scale APIs" OFF HDF5_EXTERNAL_LIB_PREFIX "Use prefix for custom library naming." "" HDF5_EXTERNAL_LIB_SUFFIX "Use suffix for custom library naming." "" @@ -989,11 +990,24 @@ NOTE: The high-level, C++, Fortran and Java interfaces are not compatible with the HDF5_ENABLE_THREADSAFE option because the lock is not hoisted - into the higher-level API calls. - Unless HDF5_ALLOW_UNSUPPORTED has been specified, - the following options must be disabled: + into the higher-level API calls. Unless HDF5_ALLOW_UNSUPPORTED has been + specified, the following options must be disabled: HDF5_BUILD_HL_LIB, HDF5_BUILD_CPP_LIB, HDF5_BUILD_FORTRAN, HDF5_BUILD_JAVA + The multi-threaded concurrency and threadsafe options are mutually + exclusive, only one or the other may be enabled. + + The multi-threaded concurrency, C++, and Java interfaces are not compatible + with the HDF5_ENABLE_PARALLEL option. + Unless ALLOW_UNSUPPORTED has been specified, + the following options must be disabled: + HDF5_ENABLE_CONCURRENCY, HDF5_BUILD_CPP_LIB, HDF5_BUILD_JAVA + + The high-level, C++, Fortran, and Java interfaces are not compatible + with the HDF5_ENABLE_CONCURRENCY option because the lock is not hoisted + into the higher-level API calls. Unless HDF5_ALLOW_UNSUPPORTED has been + specified, the following options must be disabled: + HDF5_BUILD_HL_LIB, HDF5_BUILD_CPP_LIB, HDF5_BUILD_FORTRAN, HDF5_BUILD_JAVA ======================================================================== VII. User Defined Options for HDF5 Libraries with CMake diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index ccb73119e62..80a7019fed3 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -47,6 +47,21 @@ New Features Configuration: ------------- + - Added configuration option for API concurrency support: + + CMake: HDF5_ENABLE_CONCURRENCY (ON/OFF) (Default: OFF) + Autotools: --enable-concurrency (yes/no) (Default: no) + + This option enables support for concurrent multithreaded operation + of supported API routines. This option also provides threadsafe + execution of all other, non-concurrent operations. The 'concurrency' + option thus is a superset of the existing 'threadsafe' option. Both + options are currently available, although mutually exclusive. As the + 'concurrency' code becomes more stable over time, the 'threadsafe' option + may be deprecated in favor of the new 'concurrency' option. + The following API routines support concurrent multithreaded operation: + + - ************ Renamed the option: HDF5_ENABLE_Z_LIB_SUPPORT ************ The option has been renamed to HDF5_ENABLE_ZLIB_SUPPORT to be consistent @@ -84,18 +99,6 @@ New Features Intel, GNU and Clang compilers are now in separate files included from the current compiler flags files; HDFCompilerFlags.cmake. - - Added a configuration option for internal threading/concurrency support: - - CMake: HDF5_ENABLE_THREADS (ON/OFF) (Default: ON) - Autotools: --enable-threads (yes/no) (Default: yes) - - This option enables support for threading and concurrency algorithms - within the HDF5 library. It is required for, but separate from, the - 'threadsafe' configure option, which makes the HDF5 API safe to call from - multiple threads. It is possible to enable the 'threads' option and - disable the 'threadsafe' option, but not vice versa. The 'threads' option - must be on to enable the subfiling VFD. - - Added support for native zlib-ng compression. Changed the zlib-ng CMake logic to prefer the native zlib-ng library. Added @@ -155,7 +158,6 @@ New Features some platforms use gnu11 to get some GNU things to work. - Library: -------- - The H5Iregister_type() signature has changed diff --git a/src/H5.c b/src/H5.c index b246763b490..63d7aa15a26 100644 --- a/src/H5.c +++ b/src/H5.c @@ -31,6 +31,7 @@ #include "H5PLprivate.h" /* Plugins */ #include "H5SLprivate.h" /* Skip lists */ #include "H5Tprivate.h" /* Datatypes */ +#include "H5TSprivate.h" /* Threadsafety */ /****************/ /* Local Macros */ @@ -214,14 +215,14 @@ H5_init_library(void) */ if (!H5_dont_atexit_g) { -#if defined(H5_HAVE_THREADSAFE) +#ifdef H5_HAVE_THREADSAFE_API /* 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_term_package); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Normal library termination code */ (void)atexit(H5_term_library); @@ -321,7 +322,7 @@ H5_term_library(void) H5CX_push(&api_ctx); /* Check if we should display error output */ - (void)H5Eget_auto2(H5E_DEFAULT, &func, NULL); + (void)H5E_get_default_auto_func(&func); /* Iterate over the list of 'atclose' callbacks that have been registered */ if (H5_atclose_head) { @@ -332,8 +333,13 @@ H5_term_library(void) while (curr_atclose) { H5_atclose_node_t *tmp_atclose; /* Temporary pointer to 'atclose' node */ - /* Invoke callback, providing context */ - (*curr_atclose->func)(curr_atclose->ctx); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOCHECK + { + /* Invoke callback, providing context */ + (*curr_atclose->func)(curr_atclose->ctx); + } + H5_AFTER_USER_CB_NOCHECK /* Advance to next node and free this one */ tmp_atclose = curr_atclose; @@ -1057,11 +1063,11 @@ H5close(void) * whole library just to release it all right away. It is safe to call * this function for an uninitialized library. */ - FUNC_ENTER_API_NOINIT_NOERR + FUNC_ENTER_API_NAMECHECK_ONLY H5_term_library(); - FUNC_LEAVE_API_NOERR(SUCCEED) + FUNC_LEAVE_API_NAMECHECK_ONLY(SUCCEED) } /* end H5close() */ /*------------------------------------------------------------------------- @@ -1097,13 +1103,14 @@ H5allocate_memory(size_t size, bool clear) FUNC_ENTER_API_NOINIT if (0 == size) - return NULL; + HGOTO_DONE(NULL); if (clear) ret_value = H5MM_calloc(size); else ret_value = H5MM_malloc(size); +done: FUNC_LEAVE_API_NOINIT(ret_value) } /* end H5allocate_memory() */ @@ -1184,11 +1191,11 @@ H5is_library_threadsafe(bool *is_ts /*out*/) FUNC_ENTER_API_NOINIT if (is_ts) { -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API *is_ts = true; -#else /* H5_HAVE_THREADSAFE */ +#else /* H5_HAVE_THREADSAFE_API */ *is_ts = false; -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ } else ret_value = FAIL; @@ -1226,3 +1233,63 @@ H5is_library_terminating(bool *is_terminating /*out*/) FUNC_LEAVE_API_NOINIT(ret_value) } /* end H5is_library_terminating() */ + +/*------------------------------------------------------------------------- + * Function: H5_user_cb_prepare + * + * Purpose: Prepares library before a user callback + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5_user_cb_prepare(H5_user_cb_state_t *state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Prepare H5E package for user callback */ + if (H5E_user_cb_prepare(&state->h5e_state) < 0) + HGOTO_ERROR(H5E_LIB, H5E_CANTSET, FAIL, "unable to prepare H5E package for user callback"); + +#ifdef H5_HAVE_CONCURRENCY + /* Prepare H5TS package for user callback */ + if (H5TS_user_cb_prepare() < 0) + HGOTO_ERROR(H5E_LIB, H5E_CANTSET, FAIL, "unable to prepare H5TS package for user callback"); +#endif /* H5_HAVE_THREADSAFE_API */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5_user_cb_prepare() */ + +/*------------------------------------------------------------------------- + * Function: H5_user_cb_restore + * + * Purpose: Restores library after a user callback + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5_user_cb_restore(const H5_user_cb_state_t *state) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Restore H5E package after user callback */ + if (H5E_user_cb_restore(&state->h5e_state) < 0) + HGOTO_ERROR(H5E_LIB, H5E_CANTRESTORE, FAIL, "unable to restore H5E package after user callback"); + +#ifdef H5_HAVE_CONCURRENCY + /* Restore H5TS package after user callback */ + if (H5TS_user_cb_restore() < 0) + HGOTO_ERROR(H5E_LIB, H5E_CANTRESTORE, FAIL, "unable to restore H5TS package after user callback"); +#endif /* H5_HAVE_THREADSAFE_API */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5_user_cb_restore() */ diff --git a/src/H5Adense.c b/src/H5Adense.c index 11bb5479e93..f9ba92d1aa9 100644 --- a/src/H5Adense.c +++ b/src/H5Adense.c @@ -1053,17 +1053,27 @@ H5A__dense_iterate_bt2_cb(const void *_record, void *_bt2_udata) if (H5A__get_info(fh_udata.attr, &ainfo) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, H5_ITER_ERROR, "unable to get attribute info"); - /* Make the application callback */ - ret_value = (bt2_udata->attr_op->u.app_op2)(bt2_udata->loc_id, fh_udata.attr->shared->name, - &ainfo, bt2_udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + ret_value = (bt2_udata->attr_op->u.app_op2)( + bt2_udata->loc_id, fh_udata.attr->shared->name, &ainfo, bt2_udata->op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) break; } #ifndef H5_NO_DEPRECATED_SYMBOLS case H5A_ATTR_OP_APP: - /* Make the application callback */ - ret_value = (bt2_udata->attr_op->u.app_op)(bt2_udata->loc_id, fh_udata.attr->shared->name, - bt2_udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + ret_value = (bt2_udata->attr_op->u.app_op)( + bt2_udata->loc_id, fh_udata.attr->shared->name, bt2_udata->op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) break; #endif /* H5_NO_DEPRECATED_SYMBOLS */ diff --git a/src/H5Aint.c b/src/H5Aint.c index f06c5ea0ede..88e26790cd0 100644 --- a/src/H5Aint.c +++ b/src/H5Aint.c @@ -1892,15 +1892,26 @@ H5A__attr_iterate_table(const H5A_attr_table_t *atable, hsize_t skip, hsize_t *l if (H5A__get_info(atable->attrs[u], &ainfo) < 0) HGOTO_ERROR(H5E_ATTR, H5E_CANTGET, H5_ITER_ERROR, "unable to get attribute info"); - /* Make the application callback */ - ret_value = (attr_op->u.app_op2)(loc_id, ((atable->attrs[u])->shared)->name, &ainfo, op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + ret_value = + (attr_op->u.app_op2)(loc_id, ((atable->attrs[u])->shared)->name, &ainfo, op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) break; } #ifndef H5_NO_DEPRECATED_SYMBOLS case H5A_ATTR_OP_APP: - /* Make the application callback */ - ret_value = (attr_op->u.app_op)(loc_id, ((atable->attrs[u])->shared)->name, op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + ret_value = (attr_op->u.app_op)(loc_id, ((atable->attrs[u])->shared)->name, op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) break; #endif /* H5_NO_DEPRECATED_SYMBOLS */ diff --git a/src/H5CX.c b/src/H5CX.c index 78892aacbd4..c6a43801d0b 100644 --- a/src/H5CX.c +++ b/src/H5CX.c @@ -40,7 +40,7 @@ /* Local Macros */ /****************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /* * The per-thread API context. * @@ -48,12 +48,12 @@ * by "H5CX_node_t **ctx =". */ #define H5CX_get_my_context() H5TS_get_api_ctx_ptr() -#else /* H5_HAVE_THREADSAFE */ +#else /* H5_HAVE_THREADSAFE_API */ /* * The current API context. */ #define H5CX_get_my_context() (&H5CX_head_g) -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Common macro for the retrieving the pointer to a property list */ #define H5CX_RETRIEVE_PLIST(PL, FAILVAL) \ @@ -226,9 +226,9 @@ bool H5_PKG_INIT_VAR = false; /* Local Variables */ /*******************/ -#ifndef H5_HAVE_THREADSAFE +#ifndef H5_HAVE_THREADSAFE_API static H5CX_node_t *H5CX_head_g = NULL; /* Pointer to head of context stack */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Define a "default" dataset transfer property list cache structure to use for default DXPLs */ static H5CX_dxpl_cache_t H5CX_def_dxpl_cache; diff --git a/src/H5D.c b/src/H5D.c index 492f80793cc..711a257712a 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -1592,8 +1592,14 @@ H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, hid_t dst_space_ /* Loop until all data has been scattered */ while (nelmts > 0) { - /* Make callback to retrieve data */ - if (op(&src_buf, &src_buf_nbytes, op_data) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Make callback to retrieve data */ + ret_value = op(&src_buf, &src_buf_nbytes, op_data); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure"); /* Calculate number of elements */ @@ -1704,8 +1710,16 @@ H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id, size_t dst_buf assert(nelmts_gathered == MIN(dst_buf_nelmts, (size_t)nelmts)); /* Make callback to process dst_buf */ - if (op && op(dst_buf, nelmts_gathered * type_size, op_data) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure"); + if (op) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = op(dst_buf, nelmts_gathered * type_size, op_data); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure"); + } nelmts -= (hssize_t)nelmts_gathered; assert(op || (nelmts == 0)); diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index e02ef6227e5..5fb47e7054a 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -1436,7 +1436,11 @@ H5D__chunk_mem_xfree(void *chk, const void *pline) void H5D__chunk_mem_free(void *chk, void *pline) { - (void)H5D__chunk_mem_xfree(chk, pline); + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + H5D__chunk_mem_xfree(chk, pline); + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY } /*------------------------------------------------------------------------- @@ -8134,16 +8138,23 @@ H5D__chunk_iter_cb(const H5D_chunk_rec_t *chunk_rec, void *udata) hsize_t offset[H5O_LAYOUT_NDIMS]; int ret_value = H5_ITER_CONT; + FUNC_ENTER_PACKAGE_NOERR + /* Similar to H5D__get_chunk_info */ for (unsigned i = 0; i < chunk->ndims; i++) offset[i] = chunk_rec->scaled[i] * chunk->dim[i]; - FUNC_ENTER_PACKAGE_NOERR + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(FAIL) + { + ret_value = + (data->op)(offset, (unsigned)chunk_rec->filter_mask, data->base_addr + chunk_rec->chunk_addr, + (hsize_t)chunk_rec->nbytes, data->op_data); + } + H5_AFTER_USER_CB_NOERR(FAIL) /* Check for callback failure and pass along return value */ - if ((ret_value = - (data->op)(offset, (unsigned)chunk_rec->filter_mask, data->base_addr + chunk_rec->chunk_addr, - (hsize_t)chunk_rec->nbytes, data->op_data)) < 0) + if (ret_value < 0) HERROR(H5E_DATASET, H5E_CANTNEXT, "iteration operator failed"); FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Dfill.c b/src/H5Dfill.c index e4703b8af74..093039987b8 100644 --- a/src/H5Dfill.c +++ b/src/H5Dfill.c @@ -144,7 +144,7 @@ H5D__fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_ /* Get a pointer to a buffer that's large enough for element */ if (NULL == (elem_ptr = H5WB_actual_clear(elem_wb, dst_type_size))) - HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't get actual buffer"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't get actual buffer"); /* Fill the selection in the memory buffer */ if (H5S_select_fill(elem_ptr, dst_type_size, space, buf) < 0) @@ -179,12 +179,12 @@ H5D__fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_ /* Allocate a temporary buffer */ if (NULL == (tmp_buf = H5FL_BLK_MALLOC(type_conv, (size_t)nelmts * buf_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed"); /* Allocate a background buffer, if necessary */ if (H5T_path_bkg(tpath) && NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, (size_t)nelmts * buf_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed"); /* Replicate the file's fill value into the temporary buffer */ H5VM_array_fill(tmp_buf, fill, src_type_size, (size_t)nelmts); @@ -222,7 +222,7 @@ H5D__fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_ /* Get a pointer to a buffer that's large enough for element */ if (NULL == (elem_ptr = H5WB_actual(elem_wb, buf_size))) - HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't get actual buffer"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't get actual buffer"); /* Copy the user's data into the buffer for conversion */ H5MM_memcpy(elem_ptr, fill, src_type_size); @@ -236,7 +236,7 @@ H5D__fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_ /* Get a pointer to a buffer that's large enough for element */ if (NULL == (bkg_ptr = H5WB_actual_clear(bkg_elem_wb, buf_size))) - HGOTO_ERROR(H5E_DATASET, H5E_NOSPACE, FAIL, "can't get actual buffer"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't get actual buffer"); } /* end if */ /* Perform datatype conversion */ @@ -264,9 +264,9 @@ H5D__fill(const void *fill, const H5T_t *fill_type, void *buf, const H5T_t *buf_ if (tmp_buf) tmp_buf = H5FL_BLK_FREE(type_conv, tmp_buf); if (elem_wb && H5WB_unwrap(elem_wb) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); + HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); if (bkg_elem_wb && H5WB_unwrap(bkg_elem_wb) < 0) - HDONE_ERROR(H5E_ATTR, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); + HDONE_ERROR(H5E_DATASET, H5E_CLOSEERROR, FAIL, "can't close wrapped buffer"); if (bkg_buf) bkg_buf = H5FL_BLK_FREE(type_conv, bkg_buf); @@ -347,22 +347,28 @@ H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf, H5MM_allocat fb_info->use_caller_fill_buf = true; } /* end if */ else { - if (alloc_func) - fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info); + if (alloc_func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info); + } + H5_AFTER_USER_CB(FAIL) + } else fb_info->fill_buf = H5FL_BLK_MALLOC(non_zero_fill, fb_info->fill_buf_size); if (NULL == fb_info->fill_buf) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fill buffer"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed for fill buffer"); } /* end else */ /* Get the datatype conversion path for this operation */ if (NULL == (fb_info->fill_to_mem_tpath = H5T_path_find(dset_type, fb_info->mem_type))) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes"); /* Get the inverse datatype conversion path for this operation */ if (NULL == (fb_info->mem_to_dset_tpath = H5T_path_find(fb_info->mem_type, dset_type))) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes"); /* Check if we need to allocate a background buffer */ @@ -376,7 +382,7 @@ H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf, H5MM_allocat /* Allocate the background buffer */ if (NULL == (fb_info->bkg_buf = H5FL_BLK_MALLOC(type_conv, fb_info->bkg_buf_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed"); } /* end if */ } /* end if */ else { @@ -400,12 +406,18 @@ H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf, H5MM_allocat fb_info->use_caller_fill_buf = true; } /* end if */ else { - if (alloc_func) - fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info); + if (alloc_func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info); + } + H5_AFTER_USER_CB(FAIL) + } else fb_info->fill_buf = H5FL_BLK_MALLOC(non_zero_fill, fb_info->fill_buf_size); if (NULL == fb_info->fill_buf) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fill buffer"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed for fill buffer"); } /* end else */ /* Replicate the fill value into the cached buffer */ @@ -436,7 +448,14 @@ H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf, H5MM_allocat } /* end if */ else { if (alloc_func) { - fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + fb_info->fill_buf = alloc_func(fb_info->fill_buf_size, alloc_info); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == fb_info->fill_buf) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed for fill buffer"); memset(fb_info->fill_buf, 0, fb_info->fill_buf_size); } /* end if */ @@ -453,7 +472,7 @@ H5D__fill_init(H5D_fill_buf_info_t *fb_info, void *caller_fill_buf, H5MM_allocat fb_info->fill_buf = H5FL_BLK_MALLOC(zero_fill, fb_info->fill_buf_size); } /* end else */ if (fb_info->fill_buf == NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for fill buffer"); + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed for fill buffer"); } /* end else */ } /* end else */ @@ -510,8 +529,14 @@ H5D__fill_refill_vl(H5D_fill_buf_info_t *fb_info, size_t nelmts) memset(fb_info->bkg_buf, 0, fb_info->bkg_buf_size); /* Make a copy of the fill buffer so we can free dynamic elements after conversion */ - if (fb_info->fill_alloc_func) - buf = fb_info->fill_alloc_func(fb_info->fill_buf_size, fb_info->fill_alloc_info); + if (fb_info->fill_alloc_func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + buf = fb_info->fill_alloc_func(fb_info->fill_buf_size, fb_info->fill_alloc_info); + } + H5_AFTER_USER_CB(FAIL) + } else buf = H5FL_BLK_MALLOC(non_zero_fill, fb_info->fill_buf_size); if (!buf) @@ -537,8 +562,14 @@ H5D__fill_refill_vl(H5D_fill_buf_info_t *fb_info, size_t nelmts) } /* end else */ /* Free temporary fill buffer */ - if (fb_info->fill_free_func) - fb_info->fill_free_func(buf, fb_info->fill_free_info); + if (fb_info->fill_free_func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(FAIL) + { + fb_info->fill_free_func(buf, fb_info->fill_free_info); + } + H5_AFTER_USER_CB_NOERR(FAIL) + } else buf = H5FL_BLK_FREE(non_zero_fill, buf); } /* end if */ @@ -558,6 +589,8 @@ H5D__fill_refill_vl(H5D_fill_buf_info_t *fb_info, size_t nelmts) static herr_t H5D__fill_release(H5D_fill_buf_info_t *fb_info) { + herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_PACKAGE_NOERR /* Check args */ @@ -566,8 +599,14 @@ H5D__fill_release(H5D_fill_buf_info_t *fb_info) /* Free the buffer for fill values */ if (!fb_info->use_caller_fill_buf && fb_info->fill_buf) { - if (fb_info->fill_free_func) - fb_info->fill_free_func(fb_info->fill_buf, fb_info->fill_free_info); + if (fb_info->fill_free_func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(FAIL) + { + fb_info->fill_free_func(fb_info->fill_buf, fb_info->fill_free_info); + } + H5_AFTER_USER_CB_NOERR(FAIL) + } else { if (fb_info->fill->buf) fb_info->fill_buf = H5FL_BLK_FREE(non_zero_fill, fb_info->fill_buf); @@ -577,7 +616,7 @@ H5D__fill_release(H5D_fill_buf_info_t *fb_info) fb_info->fill_buf = NULL; } /* end if */ - FUNC_LEAVE_NOAPI(SUCCEED) + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__fill_release() */ /*------------------------------------------------------------------------- diff --git a/src/H5ESint.c b/src/H5ESint.c index 6a72d911440..655fb818c04 100644 --- a/src/H5ESint.c +++ b/src/H5ESint.c @@ -298,9 +298,18 @@ H5ES__insert(H5ES_t *es, H5VL_connector_t *connector, void *request_token, const ev_inserted = true; /* Invoke the event set's 'insert' callback, if present */ - if (es->ins_func) - if ((es->ins_func)(&ev->op_info, es->ins_ctx) < 0) + if (es->ins_func) { + int status = -1; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = (es->ins_func)(&ev->op_info, es->ins_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (status < 0) HGOTO_ERROR(H5E_EVENTSET, H5E_CALLBACK, FAIL, "'insert' callback for event set failed"); + } done: /* Release resources on error */ @@ -557,6 +566,7 @@ H5ES__op_complete(H5ES_t *es, H5ES_event_t *ev, H5VL_request_status_t ev_status) /* Invoke the event set's 'complete' callback, if present */ if (es->comp_func) { H5ES_status_t op_status; /* Status for complete callback */ + int status = -1; /* Set appropriate info for callback */ if (H5VL_REQUEST_STATUS_SUCCEED == ev_status) { @@ -577,7 +587,13 @@ H5ES__op_complete(H5ES_t *es, H5ES_event_t *ev, H5VL_request_status_t ev_status) /* Translate status */ op_status = H5ES_STATUS_CANCELED; - if ((es->comp_func)(&ev->op_info, op_status, H5I_INVALID_HID, es->comp_ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = (es->comp_func)(&ev->op_info, op_status, H5I_INVALID_HID, es->comp_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (status < 0) HGOTO_ERROR(H5E_EVENTSET, H5E_CALLBACK, FAIL, "'complete' callback for event set failed"); } /* end if */ @@ -591,6 +607,7 @@ H5ES__op_complete(H5ES_t *es, H5ES_event_t *ev, H5VL_request_status_t ev_status) /* Set up VOL callback arguments */ vol_cb_args.op_type = H5VL_REQUEST_GET_ERR_STACK; vol_cb_args.args.get_err_stack.err_stack_id = H5I_INVALID_HID; + int status = -1; /* Retrieve the error stack for the operation */ if (H5VL_request_specific(ev->request, &vol_cb_args) < 0) @@ -599,7 +616,13 @@ H5ES__op_complete(H5ES_t *es, H5ES_event_t *ev, H5VL_request_status_t ev_status) /* Set values */ err_stack_id = vol_cb_args.args.get_err_stack.err_stack_id; - if ((es->comp_func)(&ev->op_info, H5ES_STATUS_FAIL, err_stack_id, es->comp_ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = (es->comp_func)(&ev->op_info, H5ES_STATUS_FAIL, err_stack_id, es->comp_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (status < 0) HGOTO_ERROR(H5E_EVENTSET, H5E_CALLBACK, FAIL, "'complete' callback for event set failed"); } /* end if */ diff --git a/src/H5Eint.c b/src/H5Eint.c index 8227e7cd421..271eb7639e0 100644 --- a/src/H5Eint.c +++ b/src/H5Eint.c @@ -78,12 +78,12 @@ static herr_t H5E__close_stack(H5E_stack_t *err_stack, void **request); /* Package Variables */ /*********************/ -#ifndef H5_HAVE_THREADSAFE +#ifndef H5_HAVE_THREADSAFE_API /* * The current error stack. */ H5E_stack_t H5E_stack_g[1]; -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Declare a free list to manage the H5E_stack_t struct */ H5FL_DEFINE(H5E_stack_t); @@ -112,14 +112,6 @@ hid_t H5E_ERR_CLS_g = FAIL; /* Local Variables */ /*******************/ -#ifdef H5_HAVE_PARALLEL -/* - * variables used for MPI error reporting - */ -char H5E_mpi_error_str[MPI_MAX_ERROR_STRING]; -int H5E_mpi_error_str_len; -#endif /* H5_HAVE_PARALLEL */ - /* Default value to initialize error stacks */ static const H5E_stack_t H5E_err_stack_def = { 0, /* nused */ @@ -265,9 +257,9 @@ H5E__init_package(void) if (H5I_register_type(H5I_ERRSTK_CLS) < 0) HGOTO_ERROR(H5E_ID, H5E_CANTINIT, FAIL, "unable to initialize ID group"); -#ifndef H5_HAVE_THREADSAFE +#ifndef H5_HAVE_THREADSAFE_API H5E__set_default_auto(H5E_stack_g); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Register the HDF5 error class */ if ((H5E_ERR_CLS_g = H5I_register(H5I_ERROR_CLASS, &H5E_err_cls_s, false)) < 0) @@ -363,6 +355,82 @@ H5E_term_package(void) FUNC_LEAVE_NOAPI(n) } /* end H5E_term_package() */ +/*------------------------------------------------------------------------- + * Function: H5E_user_cb_prepare + * + * Purpose: Prepare the H5E package before a user callback + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5E_user_cb_prepare(H5E_user_cb_state_t *state) +{ + H5E_stack_t *stack; /* Pointer to the current error stack */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Get a pointer to the current error stack */ + if (NULL == (stack = H5E__get_my_stack())) + HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack"); + + /* Save state for current error stack */ +#ifndef H5_NO_DEPRECATED_SYMBOLS + assert(1 == stack->auto_op.vers || 2 == stack->auto_op.vers); + + state->vers = stack->auto_op.vers; + if (1 == stack->auto_op.vers) + state->u.func1 = stack->auto_op.func1; + else + state->u.func2 = stack->auto_op.func2; +#else /* H5_NO_DEPRECATED_SYMBOLS */ + state->func2 = stack->auto_op.func2; +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + state->data = stack->auto_data; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5E_user_cb_prepare() */ + +/*------------------------------------------------------------------------- + * Function: H5E_user_cb_restore + * + * Purpose: Restores the state of the H5E package after a user callback + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5E_user_cb_restore(const H5E_user_cb_state_t *state) +{ + H5E_stack_t *stack; /* Pointer to the current error stack */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Get a pointer to the current error stack */ + if (NULL == (stack = H5E__get_my_stack())) + HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack"); + + /* Restore state for current error stack */ +#ifndef H5_NO_DEPRECATED_SYMBOLS + stack->auto_op.vers = state->vers; + if (1 == state->vers) + stack->auto_op.func1 = state->u.func1; + else + stack->auto_op.func2 = state->u.func2; +#else /* H5_NO_DEPRECATED_SYMBOLS */ + stack->auto_op.func2 = state->func2; +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + stack->auto_data = state->data; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5E_user_cb_restore() */ + /*------------------------------------------------------------------------- * Function: H5E__free_class * @@ -950,7 +1018,7 @@ H5E__walk1_cb(int n, H5E_error1_t *err_desc, void *client_data) const char *maj_str = "No major description"; /* Major error description */ const char *min_str = "No minor description"; /* Minor error description */ bool have_desc = true; /* Flag to indicate whether the error has a "real" description */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API uint64_t thread_id = 0; /* ID of thread */ #endif herr_t ret_value = SUCCEED; @@ -982,7 +1050,7 @@ H5E__walk1_cb(int n, H5E_error1_t *err_desc, void *client_data) /* Get error class info */ cls_ptr = maj_ptr->cls; -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API if (H5TS_thread_id(&thread_id) < 0) HGOTO_DONE(FAIL); #endif @@ -1014,13 +1082,13 @@ H5E__walk1_cb(int n, H5E_error1_t *err_desc, void *client_data) MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); fprintf(stream, " MPI-process %d", mpi_rank); } /* end if */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API else fprintf(stream, " thread %" PRIu64, thread_id); #endif } /* end block */ #else -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API fprintf(stream, " thread %" PRIu64, thread_id); #endif #endif @@ -1081,7 +1149,7 @@ H5E__walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data) const char *maj_str = "No major description"; /* Major error description */ const char *min_str = "No minor description"; /* Minor error description */ bool have_desc = true; /* Flag to indicate whether the error has a "real" description */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API uint64_t thread_id = 0; /* ID of thread */ #endif herr_t ret_value = SUCCEED; @@ -1118,7 +1186,7 @@ H5E__walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data) if (!cls_ptr) HGOTO_DONE(FAIL); -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API if (H5TS_thread_id(&thread_id) < 0) HGOTO_DONE(FAIL); #endif @@ -1150,13 +1218,13 @@ H5E__walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data) MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); fprintf(stream, " MPI-process %d", mpi_rank); } /* end if */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API else fprintf(stream, " thread %" PRIu64, thread_id); #endif } /* end block */ #else -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API fprintf(stream, " thread %" PRIu64, thread_id); #endif #endif @@ -1293,7 +1361,12 @@ H5E__walk(const H5E_stack_t *estack, H5E_direction_t direction, const H5E_walk_o old_err.line = estack->entries[i].err.line; old_err.desc = estack->entries[i].err.desc; - ret_value = (op->u.func1)(i, &old_err, client_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + ret_value = (op->u.func1)(i, &old_err, client_data); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) } /* end for */ } /* end if */ else { @@ -1307,7 +1380,13 @@ H5E__walk(const H5E_stack_t *estack, H5E_direction_t direction, const H5E_walk_o old_err.line = estack->entries[i].err.line; old_err.desc = estack->entries[i].err.desc; - ret_value = (op->u.func1)((int)(estack->nused - (size_t)(i + 1)), &old_err, client_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + ret_value = + (op->u.func1)((int)(estack->nused - (size_t)(i + 1)), &old_err, client_data); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) } /* end for */ } /* end else */ @@ -1323,14 +1402,26 @@ H5E__walk(const H5E_stack_t *estack, H5E_direction_t direction, const H5E_walk_o if (op->u.func2) { ret_value = SUCCEED; if (H5E_WALK_UPWARD == direction) { - for (i = 0; i < (int)estack->nused && ret_value == H5_ITER_CONT; i++) - ret_value = (op->u.func2)((unsigned)i, &estack->entries[i].err, client_data); + for (i = 0; i < (int)estack->nused && ret_value == H5_ITER_CONT; i++) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + ret_value = (op->u.func2)((unsigned)i, &estack->entries[i].err, client_data); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) + } } /* end if */ else { H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int); - for (i = (int)(estack->nused - 1); i >= 0 && ret_value == H5_ITER_CONT; i--) - ret_value = (op->u.func2)((unsigned)(estack->nused - (size_t)(i + 1)), - &estack->entries[i].err, client_data); + for (i = (int)(estack->nused - 1); i >= 0 && ret_value == H5_ITER_CONT; i--) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + ret_value = (op->u.func2)((unsigned)(estack->nused - (size_t)(i + 1)), + &estack->entries[i].err, client_data); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) + } } /* end else */ if (ret_value < 0) @@ -1369,6 +1460,40 @@ H5E__get_auto(const H5E_stack_t *estack, H5E_auto_op_t *op, void **client_data) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5E__get_auto() */ +/*------------------------------------------------------------------------- + * Function: H5E_get_default_auto_func + * + * Purpose: Private function to retrieve the default error stack's + * reporting function. + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5E_get_default_auto_func(H5E_auto2_t *func) +{ + H5E_stack_t *estack; /* Error stack to operate on */ + H5E_auto_op_t op; /* Error stack function */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Retrieve default error stack */ + if (NULL == (estack = H5E__get_my_stack())) + HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack"); + + /* Get the automatic error reporting information */ + if (H5E__get_auto(estack, &op, NULL) < 0) + HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get automatic error info"); + + /* Retrieve error output function */ + *func = op.func2; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5E_get_default_auto_func() */ + /*------------------------------------------------------------------------- * Function: H5E__set_auto * @@ -1821,16 +1946,34 @@ H5E_dump_api_stack(void) assert(estack); #ifdef H5_NO_DEPRECATED_SYMBOLS - if (estack->auto_op.func2) - (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data)); + if (estack->auto_op.func2) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data)); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) + } #else /* H5_NO_DEPRECATED_SYMBOLS */ if (estack->auto_op.vers == 1) { - if (estack->auto_op.func1) - (void)((estack->auto_op.func1)(estack->auto_data)); + if (estack->auto_op.func1) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + (void)((estack->auto_op.func1)(estack->auto_data)); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) + } } /* end if */ else { - if (estack->auto_op.func2) - (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data)); + if (estack->auto_op.func2) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data)); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) + } } /* end else */ #endif /* H5_NO_DEPRECATED_SYMBOLS */ diff --git a/src/H5Epkg.h b/src/H5Epkg.h index 4eaad76fb6f..666f42e7d9f 100644 --- a/src/H5Epkg.h +++ b/src/H5Epkg.h @@ -37,7 +37,7 @@ /* Number of entries in an error stack */ #define H5E_MAX_ENTRIES 32 -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /* * The per-thread error stack. * @@ -45,12 +45,12 @@ * by "H5E_stack_t *estack =". */ #define H5E__get_my_stack() H5TS_get_err_stack() -#else /* H5_HAVE_THREADSAFE */ +#else /* H5_HAVE_THREADSAFE_API */ /* * The current error stack. */ #define H5E__get_my_stack() (H5E_stack_g + 0) -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /****************************/ /* Package Private Typedefs */ @@ -118,7 +118,7 @@ typedef struct H5E_stack_t { /* Package Private Variables */ /*****************************/ -#ifndef H5_HAVE_THREADSAFE +#ifndef H5_HAVE_THREADSAFE_API /* * The current error stack. */ diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h index 1bb6d714eea..5b2b28c4173 100644 --- a/src/H5Eprivate.h +++ b/src/H5Eprivate.h @@ -16,11 +16,16 @@ #ifndef H5Eprivate_H #define H5Eprivate_H +/* Include package's public header */ #include "H5Epublic.h" /* Private headers needed by this file */ #include "H5private.h" +/**************************/ +/* Library Private Macros */ +/**************************/ + /* * When one needs to temporarily disable recording errors while trying * something that's likely or expected to fail. The code to try can be nested @@ -181,29 +186,58 @@ /* * MPI error handling macros. */ - -extern char H5E_mpi_error_str[MPI_MAX_ERROR_STRING]; -extern int H5E_mpi_error_str_len; - #define HMPI_DONE_ERROR(retcode, str, mpierr) \ { \ + char H5E_mpi_error_str[MPI_MAX_ERROR_STRING]; \ + int H5E_mpi_error_str_len; \ + \ MPI_Error_string(mpierr, H5E_mpi_error_str, &H5E_mpi_error_str_len); \ HDONE_ERROR(H5E_INTERNAL, H5E_MPI, retcode, "%s: MPI error string is '%s'", str, H5E_mpi_error_str); \ } #define HMPI_GOTO_ERROR(retcode, str, mpierr) \ { \ + char H5E_mpi_error_str[MPI_MAX_ERROR_STRING]; \ + int H5E_mpi_error_str_len; \ + \ MPI_Error_string(mpierr, H5E_mpi_error_str, &H5E_mpi_error_str_len); \ HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, retcode, "%s: MPI error string is '%s'", str, H5E_mpi_error_str); \ } #endif /* H5_HAVE_PARALLEL */ -/* Library-private functions defined in H5E package */ +/****************************/ +/* Library Private Typedefs */ +/****************************/ + +/* State to preserve across user callbacks */ +typedef struct H5E_user_cb_state_t { +#ifndef H5_NO_DEPRECATED_SYMBOLS + unsigned vers; /* Which version callback to use */ + union { + H5E_auto1_t func1; + H5E_auto2_t func2; + } u; +#else /* H5_NO_DEPRECATED_SYMBOLS */ + H5E_auto2_t func2; +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + void *data; /* Callback data for 'automatic error reporting */ +} H5E_user_cb_state_t; + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + +/******************************/ +/* Library Private Prototypes */ +/******************************/ H5_DLL herr_t H5E_init(void); +H5_DLL herr_t H5E_get_default_auto_func(H5E_auto2_t *func); H5_DLL herr_t H5E_printf_stack(const char *file, const char *func, unsigned line, hid_t maj_idx, hid_t min_idx, const char *fmt, ...) H5_ATTR_FORMAT(printf, 6, 7); H5_DLL herr_t H5E_clear_stack(void); H5_DLL herr_t H5E_dump_api_stack(void); H5_DLL void H5E_pause_stack(void); H5_DLL void H5E_resume_stack(void); +H5_DLL herr_t H5E_user_cb_prepare(H5E_user_cb_state_t *state); +H5_DLL herr_t H5E_user_cb_restore(const H5E_user_cb_state_t *state); #endif /* H5Eprivate_H */ diff --git a/src/H5FD.c b/src/H5FD.c index 567eb2c809f..cd971011b19 100644 --- a/src/H5FD.c +++ b/src/H5FD.c @@ -296,9 +296,17 @@ H5FD__free_cls(H5FD_class_t *cls, void H5_ATTR_UNUSED **request) * driver a chance to free singletons or other resources which will become * invalid once the class structure is freed. */ - if (cls->terminate && cls->terminate() < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEOBJ, FAIL, "virtual file driver '%s' did not terminate cleanly", - cls->name); + if (cls->terminate) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = cls->terminate(); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEOBJ, FAIL, "virtual file driver '%s' did not terminate cleanly", + cls->name); + } H5MM_xfree(cls); @@ -390,13 +398,12 @@ H5FD_register(const void *_cls, size_t size, bool app_ref) assert(cls->get_eoa && cls->set_eoa); assert(cls->get_eof); assert(cls->read && cls->write); - for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) { + for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) assert(cls->fl_map[type] >= H5FD_MEM_NOLIST && cls->fl_map[type] < H5FD_MEM_NTYPES); - } /* Copy the class structure so the caller can reuse or free it */ if (NULL == (saved = (H5FD_class_t *)H5MM_malloc(size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5I_INVALID_HID, + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, H5I_INVALID_HID, "memory allocation failed for file driver class struct"); H5MM_memcpy(saved, cls, size); @@ -570,8 +577,14 @@ H5FD_sb_size(H5FD_t *file) assert(file->cls); /* Dispatch to driver */ - if (file->cls->sb_size) - ret_value = (file->cls->sb_size)(file); + if (file->cls->sb_size) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(0) + { + ret_value = (file->cls->sb_size)(file); + } + H5_AFTER_USER_CB_NOERR(0) + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -603,8 +616,16 @@ H5FD_sb_encode(H5FD_t *file, char *name /*out*/, uint8_t *buf) assert(file->cls); /* Dispatch to driver */ - if (file->cls->sb_encode && (file->cls->sb_encode)(file, name /*out*/, buf /*out*/) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_encode request failed"); + if (file->cls->sb_encode) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->sb_encode)(file, name /*out*/, buf /*out*/); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_encode request failed"); + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -631,8 +652,16 @@ H5FD__sb_decode(H5FD_t *file, const char *name, const uint8_t *buf) assert(file->cls); /* Dispatch to driver */ - if (file->cls->sb_decode && (file->cls->sb_decode)(file, name, buf) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_decode request failed"); + if (file->cls->sb_decode) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->sb_decode)(file, name, buf); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_decode request failed"); + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -708,8 +737,14 @@ H5FD_fapl_get(H5FD_t *file) assert(file->cls); /* Dispatch to driver */ - if (file->cls->fapl_get) - ret_value = (file->cls->fapl_get)(file); + if (file->cls->fapl_get) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(NULL) + { + ret_value = (file->cls->fapl_get)(file); + } + H5_AFTER_USER_CB_NOERR(NULL) + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -740,9 +775,15 @@ H5FD_free_driver_info(hid_t driver_id, const void *driver_info) /* Allow driver to free info or do it ourselves */ if (driver->fapl_free) { - /* Free the const pointer */ - /* Cast through uintptr_t to de-const memory */ - if ((driver->fapl_free)((void *)(uintptr_t)driver_info) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Free the const pointer */ + /* (Cast through uintptr_t to de-const memory) */ + ret_value = (driver->fapl_free)((void *)(uintptr_t)driver_info); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "driver free request failed"); } else @@ -895,20 +936,35 @@ H5FD_open(bool try, H5FD_t **_file, const char *name, unsigned flags, hid_t fapl if (HADDR_UNDEF == maxaddr) maxaddr = driver->maxaddr; + /* clang-format off */ + /* Try dispatching to file driver */ if (try) { H5E_PAUSE_ERRORS - { - file = (driver->open)(name, flags, fapl_id, maxaddr); - } + {/* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + file = (driver->open)(name, flags, fapl_id, maxaddr); + } + H5_AFTER_USER_CB(FAIL) + } H5E_RESUME_ERRORS /* Check if file was not opened */ if (NULL == file) HGOTO_DONE(SUCCEED); } - else if (NULL == (file = (driver->open)(name, flags, fapl_id, maxaddr))) - HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "can't open file"); + else + { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + file = (driver->open)(name, flags, fapl_id, maxaddr); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == file) + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "can't open file"); + } /* Set the file access flags */ file->access_flags = flags; @@ -931,10 +987,9 @@ H5FD_open(bool try, H5FD_t **_file, const char *name, unsigned flags, hid_t fapl HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to query file driver"); /* Increment the global serial number & assign it to this H5FD_t object */ - if (++H5FD_file_serial_no_g == 0) { + if (++H5FD_file_serial_no_g == 0) /* (Just error out if we wrap around for now...) */ HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to get file serial number"); - } /* end if */ file->fileno = H5FD_file_serial_no_g; /* Start with base address set to 0 */ @@ -944,7 +999,9 @@ H5FD_open(bool try, H5FD_t **_file, const char *name, unsigned flags, hid_t fapl /* Set 'out' parameter */ *_file = file; -done: +/* clang-format on */ + +done : /* Can't cleanup 'file' information, since we don't know what type it is */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_open() */ @@ -1009,11 +1066,17 @@ H5FD_close(H5FD_t *file) if (H5I_dec_ref(file->driver_id) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID"); - /* Dispatch to the driver for actual close. If the driver fails to - * close the file then the file will be in an unusable state. - */ - assert(driver->close); - if ((driver->close)(file) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to the driver for actual close. If the driver fails to + * close the file then the file will be in an unusable state. + */ + assert(driver->close); + ret_value = (driver->close)(file); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTCLOSEFILE, FAIL, "close failed"); done: @@ -1091,8 +1154,13 @@ H5FD_cmp(const H5FD_t *f1, const H5FD_t *f2) HGOTO_DONE(0); } - /* Dispatch to driver */ - ret_value = (f1->cls->cmp)(f1, f2); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOCHECK + { + /* Dispatch to driver */ + ret_value = (f1->cls->cmp)(f1, f2); + } + H5_AFTER_USER_CB_NOCHECK done: FUNC_LEAVE_NOAPI(ret_value) @@ -1153,7 +1221,13 @@ H5FD__query(const H5FD_t *file, unsigned long *flags /*out*/) /* Dispatch to driver (if available) */ if (file->cls->query) { - if ((file->cls->query)(file, flags) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->query)(file, flags); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "unable to query feature flags"); } else @@ -1505,8 +1579,14 @@ H5FD_get_fs_type_map(const H5FD_t *file, H5FD_mem_t *type_map) /* Check for VFD class providing a type map retrieval routine */ if (file->cls->get_type_map) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->get_type_map)(file, type_map); + } + H5_AFTER_USER_CB(FAIL) /* Retrieve type mapping for this file */ - if ((file->cls->get_type_map)(file, type_map) < 0) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get type map failed"); } /* end if */ else @@ -2400,8 +2480,16 @@ H5FD_flush(H5FD_t *file, bool closing) assert(file->cls); /* Dispatch to driver */ - if (file->cls->flush && (file->cls->flush)(file, H5CX_get_dxpl(), closing) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver flush request failed"); + if (file->cls->flush) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->flush)(file, H5CX_get_dxpl(), closing); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver flush request failed"); + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -2465,8 +2553,16 @@ H5FD_truncate(H5FD_t *file, bool closing) assert(file->cls); /* Dispatch to driver */ - if (file->cls->truncate && (file->cls->truncate)(file, H5CX_get_dxpl(), closing) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver truncate request failed"); + if (file->cls->truncate) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->truncate)(file, H5CX_get_dxpl(), closing); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTUPDATE, FAIL, "driver truncate request failed"); + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -2523,8 +2619,16 @@ H5FD_lock(H5FD_t *file, bool rw) assert(file->cls); /* Dispatch to driver */ - if (file->cls->lock && (file->cls->lock)(file, rw) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "driver lock request failed"); + if (file->cls->lock) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->lock)(file, rw); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "driver lock request failed"); + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -2581,8 +2685,16 @@ H5FD_unlock(H5FD_t *file) assert(file->cls); /* Dispatch to driver */ - if (file->cls->unlock && (file->cls->unlock)(file) < 0) - HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "driver unlock request failed"); + if (file->cls->unlock) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->unlock)(file); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "driver unlock request failed"); + } done: FUNC_LEAVE_NOAPI(ret_value) @@ -2671,16 +2783,18 @@ H5FD_ctl(H5FD_t *file, uint64_t op_code, uint64_t flags, const void *input, void * Otherwise, report success. */ if (file->cls->ctl) { - - if ((file->cls->ctl)(file, op_code, flags, input, output) < 0) - + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->ctl)(file, op_code, flags, input, output); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed"); } - else if (flags & H5FD_CTL_FAIL_IF_UNKNOWN_FLAG) { - + else if (flags & H5FD_CTL_FAIL_IF_UNKNOWN_FLAG) HGOTO_ERROR(H5E_VFL, H5E_FCNTL, FAIL, "VFD ctl request failed (no ctl callback and fail if unknown flag is set)"); - } done: @@ -2778,7 +2892,14 @@ H5FD_get_vfd_handle(H5FD_t *file, hid_t fapl_id, void **file_handle) /* Dispatch to driver */ if (NULL == file->cls->get_handle) HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, FAIL, "file driver has no `get_vfd_handle' method"); - if ((file->cls->get_handle)(file, fapl_id, file_handle) < 0) + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->get_handle)(file, fapl_id, file_handle); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "can't get file handle for file driver"); done: diff --git a/src/H5FDcore.c b/src/H5FDcore.c index 42542c4dabc..f2c2a820e54 100644 --- a/src/H5FDcore.c +++ b/src/H5FDcore.c @@ -824,13 +824,19 @@ H5FD__core_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr if (size) { /* Allocate memory for the file's data, using the file image callback if available. */ if (file->fi_callbacks.image_malloc) { - if (NULL == (file->mem = (unsigned char *)file->fi_callbacks.image_malloc( - size, H5FD_FILE_IMAGE_OP_FILE_OPEN, file->fi_callbacks.udata))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "image malloc callback failed"); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + file->mem = file->fi_callbacks.image_malloc(size, H5FD_FILE_IMAGE_OP_FILE_OPEN, + file->fi_callbacks.udata); + } + H5_AFTER_USER_CB(NULL) + if (NULL == file->mem) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "image malloc callback failed"); } /* end if */ else { - if (NULL == (file->mem = (unsigned char *)H5MM_malloc(size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, NULL, "unable to allocate memory block"); + if (NULL == (file->mem = H5MM_malloc(size))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate memory block"); } /* end else */ /* Set up data structures */ @@ -839,10 +845,18 @@ H5FD__core_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr /* If there is an initial file image, copy it, using the callback if possible */ if (file_image_info.buffer && file_image_info.size > 0) { if (file->fi_callbacks.image_memcpy) { - if (file->mem != file->fi_callbacks.image_memcpy(file->mem, file_image_info.buffer, size, - H5FD_FILE_IMAGE_OP_FILE_OPEN, - file->fi_callbacks.udata)) - HGOTO_ERROR(H5E_FILE, H5E_CANTCOPY, NULL, "image_memcpy callback failed"); + void *tmp; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + tmp = file->fi_callbacks.image_memcpy(file->mem, file_image_info.buffer, size, + H5FD_FILE_IMAGE_OP_FILE_OPEN, + file->fi_callbacks.udata); + } + H5_AFTER_USER_CB(NULL) + if (file->mem != tmp) + HGOTO_ERROR(H5E_VFL, H5E_CANTCOPY, NULL, "image_memcpy callback failed"); } /* end if */ else H5MM_memcpy(file->mem, file_image_info.buffer, size); @@ -977,9 +991,15 @@ H5FD__core_close(H5FD_t *_file) if (file->mem) { /* Use image callback if available */ if (file->fi_callbacks.image_free) { - if (file->fi_callbacks.image_free(file->mem, H5FD_FILE_IMAGE_OP_FILE_CLOSE, - file->fi_callbacks.udata) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "image_free callback failed"); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = file->fi_callbacks.image_free(file->mem, H5FD_FILE_IMAGE_OP_FILE_CLOSE, + file->fi_callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "image_free callback failed"); } /* end if */ else H5MM_xfree(file->mem); @@ -1346,16 +1366,22 @@ H5FD__core_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UN /* (Re)allocate memory for the file buffer, using callbacks if available */ if (file->fi_callbacks.image_realloc) { - if (NULL == (x = (unsigned char *)file->fi_callbacks.image_realloc( - file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + x = file->fi_callbacks.image_realloc(file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, + file->fi_callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == x) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes with callback", (unsigned long long)new_eof); } /* end if */ else { - if (NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, - "unable to allocate memory block of %llu bytes", (unsigned long long)new_eof); + if (NULL == (x = H5MM_realloc(file->mem, new_eof))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block of %llu bytes", + (unsigned long long)new_eof); } /* end else */ memset(x + file->eof, 0, (size_t)(new_eof - file->eof)); @@ -1504,15 +1530,20 @@ H5FD__core_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool closing) /* (Re)allocate memory for the file buffer, using callback if available */ if (file->fi_callbacks.image_realloc) { - if (NULL == - (x = (unsigned char *)file->fi_callbacks.image_realloc( - file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + x = file->fi_callbacks.image_realloc( + file->mem, new_eof, H5FD_FILE_IMAGE_OP_FILE_RESIZE, file->fi_callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == x) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block with callback"); } /* end if */ else { - if (NULL == (x = (unsigned char *)H5MM_realloc(file->mem, new_eof))) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "unable to allocate memory block"); + if (NULL == (x = H5MM_realloc(file->mem, new_eof))) + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate memory block"); } /* end else */ if (file->eof < new_eof) diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c index fa65dc594cc..939a3ac5c4a 100644 --- a/src/H5FDfamily.c +++ b/src/H5FDfamily.c @@ -1488,9 +1488,9 @@ H5FD__family_delete(const char *filename, hid_t fapl_id) herr_t delete_error; H5E_PAUSE_ERRORS - { - delete_error = H5FD_delete(member_name, memb_fapl_id); - } + { + delete_error = H5FD_delete(member_name, memb_fapl_id); + } H5E_RESUME_ERRORS if (delete_error < 0) break; diff --git a/src/H5FDint.c b/src/H5FDint.c index 07761742c13..bcb79e3fee6 100644 --- a/src/H5FDint.c +++ b/src/H5FDint.c @@ -245,7 +245,13 @@ H5FD_read(H5FD_t *file, H5FD_mem_t type, haddr_t addr, size_t size, void *buf /* if (!(file->access_flags & H5F_ACC_SWMR_READ)) { haddr_t eoa; - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); if ((addr + file->base_addr + size) > eoa) @@ -254,8 +260,14 @@ H5FD_read(H5FD_t *file, H5FD_mem_t type, haddr_t addr, size_t size, void *buf /* (unsigned long long)eoa); } - /* Dispatch to driver */ - if ((file->cls->read)(file, type, dxpl_id, addr + file->base_addr, size, buf) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to driver */ + ret_value = (file->cls->read)(file, type, dxpl_id, addr + file->base_addr, size, buf); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -306,15 +318,27 @@ H5FD_write(H5FD_t *file, H5FD_mem_t type, haddr_t addr, size_t size, const void HGOTO_DONE(SUCCEED); #endif /* H5_HAVE_PARALLEL */ - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); if ((addr + file->base_addr + size) > eoa) HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addr = %llu, size=%llu, eoa=%llu", (unsigned long long)(addr + file->base_addr), (unsigned long long)size, (unsigned long long)eoa); - /* Dispatch to driver */ - if ((file->cls->write)(file, type, dxpl_id, addr + file->base_addr, size, buf) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to driver */ + ret_value = (file->cls->write)(file, type, dxpl_id, addr + file->base_addr, size, buf); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -404,20 +428,16 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs * Do not return early for Parallel mode since the I/O could be a * collective transfer. */ - if (0 == count) { + if (0 == count) HGOTO_DONE(SUCCEED); - } #endif /* H5_HAVE_PARALLEL */ if (file->base_addr > 0) { - /* apply the base_addr offset to the addrs array. Must undo before * we return. */ - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) addrs[i] += file->base_addr; - } addrs_cooked = true; } @@ -434,29 +454,21 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs extend_types = false; for (i = 0; i < count; i++) { - if (!extend_sizes) { - if (sizes[i] == 0) { - extend_sizes = true; size = sizes[i - 1]; } - else { - + else size = sizes[i]; - } } if (!extend_types) { - if (types[i] == H5FD_MEM_NOLIST) { - extend_types = true; type = types[i - 1]; } else { - type = types[i]; /* Check for raw data operation */ @@ -465,11 +477,16 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs } } - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); if ((addrs[i] + size) > eoa) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, eoa = %llu", (int)i, (unsigned long long)(addrs[i]), (int)i, (unsigned long long)size, @@ -486,7 +503,13 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs /* if the underlying VFD supports vector read, make the call */ if (file->cls->read_vector) { - if ((file->cls->read_vector)(file, dxpl_id, count, types, addrs, sizes, bufs) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->read_vector)(file, dxpl_id, count, types, addrs, sizes, bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read vector request failed"); /* Set actual selection I/O mode, if this is a raw data operation */ @@ -499,7 +522,6 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs } } else { - /* otherwise, implement the vector read as a sequence of regular * read calls. */ @@ -509,38 +531,34 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs uint32_t actual_selection_io_mode; for (i = 0; i < count; i++) { - /* we have already verified that sizes[0] != 0 and * types[0] != H5FD_MEM_NOLIST */ - if (!extend_sizes) { - if (sizes[i] == 0) { - extend_sizes = true; size = sizes[i - 1]; } - else { - + else size = sizes[i]; - } } if (!extend_types) { - if (types[i] == H5FD_MEM_NOLIST) { - extend_types = true; type = types[i - 1]; } - else { - + else type = types[i]; - } } - if ((file->cls->read)(file, type, dxpl_id, addrs[i], size, bufs[i]) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->read)(file, type, dxpl_id, addrs[i], size, bufs[i]); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed"); } @@ -560,14 +578,11 @@ H5FD_read_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addrs done: /* undo the base addr offset to the addrs array if necessary */ if (addrs_cooked) { - assert(file->base_addr > 0); - - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) addrs[i] -= file->base_addr; - } } + FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_read_vector() */ @@ -651,14 +666,11 @@ H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addr #endif /* H5_HAVE_PARALLEL */ if (file->base_addr > 0) { - /* apply the base_addr offset to the addrs array. Must undo before * we return. */ - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) addrs[i] += file->base_addr; - } addrs_cooked = true; } @@ -666,29 +678,21 @@ H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addr extend_types = false; for (i = 0; i < count; i++) { - if (!extend_sizes) { - if (sizes[i] == 0) { - extend_sizes = true; size = sizes[i - 1]; } - else { - + else size = sizes[i]; - } } if (!extend_types) { - if (types[i] == H5FD_MEM_NOLIST) { - extend_types = true; type = types[i - 1]; } else { - type = types[i]; /* Check for raw data operation */ @@ -697,21 +701,31 @@ H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addr } } - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) - + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); if ((addrs[i] + size) > eoa) - - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, \ - eoa = %llu", - (int)i, (unsigned long long)(addrs[i]), (int)i, (unsigned long long)size, + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, + "addr overflow, addrs[%d] = %llu, sizes[%d] = %llu, eoa = %llu", (int)i, + (unsigned long long)(addrs[i]), (int)i, (unsigned long long)size, (unsigned long long)eoa); } /* if the underlying VFD supports vector write, make the call */ if (file->cls->write_vector) { - if ((file->cls->write_vector)(file, dxpl_id, count, types, addrs, sizes, bufs) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->write_vector)(file, dxpl_id, count, types, addrs, sizes, bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write vector request failed"); /* Set actual selection I/O mode, if this is a raw data operation */ @@ -733,38 +747,34 @@ H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addr uint32_t actual_selection_io_mode; for (i = 0; i < count; i++) { - /* we have already verified that sizes[0] != 0 and * types[0] != H5FD_MEM_NOLIST */ - if (!extend_sizes) { - if (sizes[i] == 0) { - extend_sizes = true; size = sizes[i - 1]; } - else { - + else size = sizes[i]; - } } if (!extend_types) { - if (types[i] == H5FD_MEM_NOLIST) { - extend_types = true; type = types[i - 1]; } - else { - + else type = types[i]; - } } - if ((file->cls->write)(file, type, dxpl_id, addrs[i], size, bufs[i]) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->write)(file, type, dxpl_id, addrs[i], size, bufs[i]); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver write request failed"); } @@ -784,14 +794,11 @@ H5FD_write_vector(H5FD_t *file, uint32_t count, H5FD_mem_t types[], haddr_t addr done: /* undo the base addr offset to the addrs array if necessary */ if (addrs_cooked) { - assert(file->base_addr > 0); - - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) addrs[i] -= file->base_addr; - } } + FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD_write_vector() */ @@ -1020,11 +1027,18 @@ H5FD__read_selection_translate(uint32_t skip_vector_cb, H5FD_t *file, H5FD_mem_t vec_bufs[vec_arr_nused] = (void *)((uint8_t *)buf + mem_off[mem_seq_i]); vec_arr_nused++; } - else - /* Issue scalar read call */ - if ((file->cls->read)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, - (void *)((uint8_t *)buf + mem_off[mem_seq_i])) < 0) + else { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Issue scalar read call */ + ret_value = (file->cls->read)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], + io_len, (void *)((uint8_t *)buf + mem_off[mem_seq_i])); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read request failed"); + } /* Update file sequence */ if (io_len == file_len[file_seq_i]) @@ -1062,8 +1076,14 @@ H5FD__read_selection_translate(uint32_t skip_vector_cb, H5FD_t *file, H5FD_mem_t uint32_t actual_selection_io_mode; H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t); - if ((file->cls->read_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, vec_bufs) < - 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->read_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, + sizes, vec_bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read vector request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -1197,20 +1217,16 @@ H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_s * Do not return early for Parallel mode since the I/O could be a * collective transfer. */ - if (0 == count) { + if (0 == count) HGOTO_DONE(SUCCEED); - } #endif /* H5_HAVE_PARALLEL */ if (file->base_addr > 0) { - /* apply the base_addr offset to the offsets array. Must undo before * we return. */ - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] += file->base_addr; - } offsets_cooked = true; } @@ -1227,16 +1243,19 @@ H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_s if (!(file->access_flags & H5F_ACC_SWMR_READ)) { haddr_t eoa; - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) if ((offsets[i]) > eoa) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa); - } } /* if the underlying VFD supports selection read, make the call */ @@ -1265,8 +1284,14 @@ H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_s } } - if ((file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, - element_sizes, bufs) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, + file_space_ids, offsets, element_sizes, bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read selection request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -1287,13 +1312,9 @@ H5FD_read_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_s done: /* undo the base addr offset to the offsets array if necessary */ if (offsets_cooked) { - assert(file->base_addr > 0); - - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] -= file->base_addr; - } } /* Cleanup dataspace arrays. Use H5I_remove() so we only close the IDs and @@ -1379,23 +1400,19 @@ H5FD_read_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_t * Do not return early for Parallel mode since the I/O could be a * collective transfer. */ - if (0 == count) { + if (0 == count) HGOTO_DONE(SUCCEED); - } #endif /* H5_HAVE_PARALLEL */ skip_selection_cb = skip_cb & SKIP_SELECTION_CB; skip_vector_cb = skip_cb & SKIP_VECTOR_CB; if (file->base_addr > 0) { - /* apply the base_addr offset to the offsets array. Must undo before * we return. */ - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] += file->base_addr; - } offsets_cooked = true; } @@ -1412,24 +1429,33 @@ H5FD_read_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_t if (!(file->access_flags & H5F_ACC_SWMR_READ)) { haddr_t eoa; - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) if ((offsets[i]) > eoa) - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa); - } } /* if the underlying VFD supports selection read, make the call */ if (!skip_selection_cb && file->cls->read_selection) { uint32_t actual_selection_io_mode; - if ((file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, - element_sizes, bufs) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->read_selection)(file, type, dxpl_id, count, mem_space_ids, + file_space_ids, offsets, element_sizes, bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "driver read selection request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -1471,13 +1497,9 @@ H5FD_read_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_t done: /* undo the base addr offset to the offsets array if necessary */ if (offsets_cooked) { - assert(file->base_addr > 0); - - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] -= file->base_addr; - } } /* Cleanup dataspace arrays */ @@ -1571,34 +1593,24 @@ H5FD__write_selection_translate(uint32_t skip_vector_cb, H5FD_t *file, H5FD_mem_ /* Loop over dataspaces */ for (i = 0; i < count; i++) { - /* we have already verified that element_sizes[0] != 0 and bufs[0] * != NULL */ - if (!extend_sizes) { - if (element_sizes[i] == 0) { - extend_sizes = true; element_size = element_sizes[i - 1]; } - else { - + else element_size = element_sizes[i]; - } } if (!extend_bufs) { - if (bufs[i] == NULL) { - extend_bufs = true; buf = bufs[i - 1]; } - else { - + else buf = bufs[i]; - } } /* Initialize sequence lists for memory and file spaces */ @@ -1712,11 +1724,19 @@ H5FD__write_selection_translate(uint32_t skip_vector_cb, H5FD_t *file, H5FD_mem_ vec_bufs[vec_arr_nused] = (const void *)((const uint8_t *)buf + mem_off[mem_seq_i]); vec_arr_nused++; } - else - /* Issue scalar write call */ - if ((file->cls->write)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, - (const void *)((const uint8_t *)buf + mem_off[mem_seq_i])) < 0) + else { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Issue scalar write call */ + ret_value = + (file->cls->write)(file, type, dxpl_id, offsets[i] + file_off[file_seq_i], io_len, + (const void *)((const uint8_t *)buf + mem_off[mem_seq_i])); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write request failed"); + } /* Update file sequence */ if (io_len == file_len[file_seq_i]) @@ -1754,8 +1774,14 @@ H5FD__write_selection_translate(uint32_t skip_vector_cb, H5FD_t *file, H5FD_mem_ uint32_t actual_selection_io_mode; H5_CHECK_OVERFLOW(vec_arr_nused, size_t, uint32_t); - if ((file->cls->write_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, sizes, vec_bufs) < - 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->write_vector)(file, dxpl_id, (uint32_t)vec_arr_nused, types, addrs, + sizes, vec_bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write vector request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -1857,8 +1883,9 @@ H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_ hid_t *mem_space_ids = mem_space_ids_local; hid_t file_space_ids_local[H5FD_LOCAL_SEL_ARR_LEN]; hid_t *file_space_ids = file_space_ids_local; - uint32_t num_spaces = 0; - hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ + haddr_t eoa; + uint32_t num_spaces = 0; + hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ uint32_t i; herr_t ret_value = SUCCEED; /* Return value */ @@ -1887,20 +1914,16 @@ H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_ * Do not return early for Parallel mode since the I/O could be a * collective transfer. */ - if (0 == count) { + if (0 == count) HGOTO_DONE(SUCCEED); - } #endif /* H5_HAVE_PARALLEL */ if (file->base_addr > 0) { - /* apply the base_addr offset to the offsets array. Must undo before * we return. */ - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] += file->base_addr; - } offsets_cooked = true; } @@ -1908,20 +1931,19 @@ H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_ * looking into the highest offset in the selection (different from the * bounds) is potentially expensive. */ - { - haddr_t eoa; - - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); - - for (i = 0; i < count; i++) { - - if ((offsets[i]) > eoa) - - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", - (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); } - } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); + + for (i = 0; i < count; i++) + if ((offsets[i]) > eoa) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", (int)i, + (unsigned long long)(offsets[i]), (unsigned long long)eoa); /* if the underlying VFD supports selection write, make the call */ if (file->cls->write_selection) { @@ -1949,8 +1971,14 @@ H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_ } } - if ((file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, - element_sizes, bufs) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, + file_space_ids, offsets, element_sizes, bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write selection request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -1972,13 +2000,9 @@ H5FD_write_selection(H5FD_t *file, H5FD_mem_t type, uint32_t count, H5S_t **mem_ done: /* undo the base addr offset to the offsets array if necessary */ if (offsets_cooked) { - assert(file->base_addr > 0); - - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] -= file->base_addr; - } } /* Cleanup dataspace arrays. Use H5I_remove() so we only close the IDs and @@ -2031,7 +2055,8 @@ H5FD_write_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_ H5S_t **mem_spaces = mem_spaces_local; H5S_t *file_spaces_local[H5FD_LOCAL_SEL_ARR_LEN]; H5S_t **file_spaces = file_spaces_local; - hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ + haddr_t eoa; + hid_t dxpl_id = H5I_INVALID_HID; /* DXPL for operation */ uint32_t i; uint32_t skip_selection_cb; uint32_t skip_vector_cb; @@ -2062,23 +2087,19 @@ H5FD_write_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_ * Do not return early for Parallel mode since the I/O could be a * collective transfer. */ - if (0 == count) { + if (0 == count) HGOTO_DONE(SUCCEED); - } #endif /* H5_HAVE_PARALLEL */ skip_selection_cb = skip_cb & SKIP_SELECTION_CB; skip_vector_cb = skip_cb & SKIP_VECTOR_CB; if (file->base_addr > 0) { - /* apply the base_addr offset to the offsets array. Must undo before * we return. */ - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] += file->base_addr; - } offsets_cooked = true; } @@ -2086,27 +2107,32 @@ H5FD_write_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_ * looking into the highest offset in the selection (different from the * bounds) is potentially expensive. */ - { - haddr_t eoa; - - if (HADDR_UNDEF == (eoa = (file->cls->get_eoa)(file, type))) - HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); - - for (i = 0; i < count; i++) { - - if ((offsets[i]) > eoa) - - HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", - (int)i, (unsigned long long)(offsets[i]), (unsigned long long)eoa); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + eoa = (file->cls->get_eoa)(file, type); } - } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver get_eoa request failed"); + + for (i = 0; i < count; i++) + if ((offsets[i]) > eoa) + HGOTO_ERROR(H5E_ARGS, H5E_OVERFLOW, FAIL, "addr overflow, offsets[%d] = %llu, eoa = %llu", (int)i, + (unsigned long long)(offsets[i]), (unsigned long long)eoa); /* if the underlying VFD supports selection write, make the call */ if (!skip_selection_cb && file->cls->write_selection) { uint32_t actual_selection_io_mode; - if ((file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, file_space_ids, offsets, - element_sizes, bufs) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (file->cls->write_selection)(file, type, dxpl_id, count, mem_space_ids, + file_space_ids, offsets, element_sizes, bufs); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "driver write selection request failed"); /* Set actual selection I/O, if this is a raw data operation */ @@ -2139,7 +2165,6 @@ H5FD_write_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_ } /* Translate to vector or scalar I/O */ - if (H5FD__write_selection_translate(skip_vector_cb, file, type, dxpl_id, count, mem_spaces, file_spaces, offsets, element_sizes, bufs) < 0) HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "translation to vector or scalar write failed"); @@ -2148,13 +2173,9 @@ H5FD_write_selection_id(uint32_t skip_cb, H5FD_t *file, H5FD_mem_t type, uint32_ done: /* undo the base addr offset to the offsets array if necessary */ if (offsets_cooked) { - assert(file->base_addr > 0); - - for (i = 0; i < count; i++) { - + for (i = 0; i < count; i++) offsets[i] -= file->base_addr; - } } /* Cleanup dataspace arrays */ @@ -2393,8 +2414,14 @@ H5FD_set_eoa(H5FD_t *file, H5FD_mem_t type, haddr_t addr) assert(file && file->cls); assert(H5_addr_defined(addr) && addr <= file->maxaddr); - /* Dispatch to driver, convert to absolute address */ - if ((file->cls->set_eoa)(file, type, addr + file->base_addr) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to driver, convert to absolute address */ + ret_value = (file->cls->set_eoa)(file, type, addr + file->base_addr); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver set_eoa request failed"); done: @@ -2426,8 +2453,14 @@ H5FD_get_eoa(const H5FD_t *file, H5FD_mem_t type) assert(file && file->cls); - /* Dispatch to driver */ - if (HADDR_UNDEF == (ret_value = (file->cls->get_eoa)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + /* Dispatch to driver */ + ret_value = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(HADDR_UNDEF) + if (!H5_addr_defined(ret_value)) HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, "driver get_eoa request failed"); /* Adjust for base address in file (convert to relative address) */ @@ -2464,7 +2497,13 @@ H5FD_get_eof(const H5FD_t *file, H5FD_mem_t type) /* Dispatch to driver */ if (file->cls->get_eof) { - if (HADDR_UNDEF == (ret_value = (file->cls->get_eof)(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + ret_value = (file->cls->get_eof)(file, type); + } + H5_AFTER_USER_CB(HADDR_UNDEF) + if (!H5_addr_defined(ret_value)) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, HADDR_UNDEF, "driver get_eof request failed"); } else @@ -2500,8 +2539,14 @@ H5FD_driver_query(const H5FD_class_t *driver, unsigned long *flags /*out*/) assert(flags); /* Check for the driver to query and then query it */ - if (driver->query) - ret_value = (driver->query)(NULL, flags); + if (driver->query) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(FAIL) + { + ret_value = (driver->query)(NULL, flags); + } + H5_AFTER_USER_CB_NOERR(FAIL) + } else *flags = 0; @@ -3014,8 +3059,14 @@ H5FD_delete(const char *filename, hid_t fapl_id) if (NULL == driver->del) HGOTO_ERROR(H5E_VFL, H5E_UNSUPPORTED, FAIL, "file driver has no 'del' method"); - /* Dispatch to file driver */ - if ((driver->del)(filename, fapl_id)) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to file driver */ + ret_value = (driver->del)(filename, fapl_id); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTDELETEFILE, FAIL, "delete failed"); done: diff --git a/src/H5FDspace.c b/src/H5FDspace.c index 3bf233d56e5..cdd379e632e 100644 --- a/src/H5FDspace.c +++ b/src/H5FDspace.c @@ -86,6 +86,7 @@ static haddr_t H5FD__extend(H5FD_t *file, H5FD_mem_t type, hsize_t size) { haddr_t eoa; /* Address of end-of-allocated space */ + herr_t status; /* Generic status return */ haddr_t ret_value = HADDR_UNDEF; /* Return value */ FUNC_ENTER_PACKAGE @@ -96,8 +97,13 @@ H5FD__extend(H5FD_t *file, H5FD_mem_t type, hsize_t size) assert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES); assert(size > 0); - /* Get current end-of-allocated space address */ - eoa = file->cls->get_eoa(file, type); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + /* Get current end-of-allocated space address */ + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(HADDR_UNDEF) /* Check for overflow when extending */ if (H5_addr_overflow(eoa, size) || (eoa + size) > file->maxaddr) @@ -106,9 +112,15 @@ H5FD__extend(H5FD_t *file, H5FD_mem_t type, hsize_t size) /* Set the [NOT aligned] address to return */ ret_value = eoa; - /* Extend the end-of-allocated space address */ - eoa += size; - if (file->cls->set_eoa(file, type, eoa) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + /* Extend the end-of-allocated space address */ + eoa += size; + status = (file->cls->set_eoa)(file, type, eoa); + } + H5_AFTER_USER_CB(HADDR_UNDEF) + if (status < 0) HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed"); done: @@ -135,6 +147,7 @@ H5FD__alloc_real(H5FD_t *file, H5FD_mem_t type, hsize_t size, haddr_t *frag_addr hsize_t extra; /* Extra space to allocate, to align request */ unsigned long flags = 0; /* Driver feature flags */ bool use_alloc_size; /* Just pass alloc size to the driver */ + herr_t status; /* Generic status return */ haddr_t ret_value = HADDR_UNDEF; /* Return value */ FUNC_ENTER_PACKAGE @@ -149,14 +162,27 @@ H5FD__alloc_real(H5FD_t *file, H5FD_mem_t type, hsize_t size, haddr_t *frag_addr assert(size > 0); /* Check for query driver and call it */ - if (file->cls->query) - (file->cls->query)(file, &flags); + if (file->cls->query) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + status = (file->cls->query)(file, &flags); + } + H5_AFTER_USER_CB(HADDR_UNDEF) + if (status < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, HADDR_UNDEF, "driver query request failed"); + } /* Check for the driver feature flag */ use_alloc_size = flags & H5FD_FEAT_USE_ALLOC_SIZE; - /* Get current end-of-allocated space address */ - eoa = file->cls->get_eoa(file, type); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + /* Get current end-of-allocated space address */ + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(HADDR_UNDEF) /* Compute extra space to allocate, if this should be aligned */ extra = 0; @@ -179,7 +205,13 @@ H5FD__alloc_real(H5FD_t *file, H5FD_mem_t type, hsize_t size, haddr_t *frag_addr /* For all other drivers: the size passed down to the alloc callback is the size + [possibly] alignment * size */ if (file->cls->alloc) { - ret_value = (file->cls->alloc)(file, type, H5CX_get_dxpl(), use_alloc_size ? size : size + extra); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(HADDR_UNDEF) + { + ret_value = + (file->cls->alloc)(file, type, H5CX_get_dxpl(), use_alloc_size ? size : size + extra); + } + H5_AFTER_USER_CB(HADDR_UNDEF) if (!H5_addr_defined(ret_value)) HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver allocation request failed"); } /* end if */ @@ -292,7 +324,14 @@ H5FD__free_real(H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size) #ifdef H5FD_ALLOC_DEBUG fprintf(stderr, "%s: Letting VFD free space\n", __func__); #endif /* H5FD_ALLOC_DEBUG */ - if ((file->cls->free)(file, type, H5CX_get_dxpl(), addr, size) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to driver */ + ret_value = (file->cls->free)(file, type, H5CX_get_dxpl(), addr, size); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "driver free request failed"); } /* end if */ /* Check if this free block is at the end of file allocated space. @@ -301,7 +340,13 @@ H5FD__free_real(H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size) else if (file->cls->get_eoa) { haddr_t eoa; - eoa = file->cls->get_eoa(file, type); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to driver */ + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) #ifdef H5FD_ALLOC_DEBUG fprintf(stderr, "%s: eoa = %" PRIuHADDR "\n", __func__, eoa); #endif /* H5FD_ALLOC_DEBUG */ @@ -309,7 +354,14 @@ H5FD__free_real(H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size) #ifdef H5FD_ALLOC_DEBUG fprintf(stderr, "%s: Reducing file size to = %" PRIuHADDR "\n", __func__, addr); #endif /* H5FD_ALLOC_DEBUG */ - if (file->cls->set_eoa(file, type, addr) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Dispatch to driver */ + ret_value = (file->cls->set_eoa)(file, type, addr); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "set end of space allocation request failed"); } /* end if */ } /* end else-if */ @@ -395,8 +447,14 @@ H5FD_try_extend(H5FD_t *file, H5FD_mem_t type, H5F_t *f, haddr_t blk_end, hsize_ assert(extra_requested > 0); assert(f); - /* Retrieve the end of the address space */ - if (HADDR_UNDEF == (eoa = file->cls->get_eoa(file, type))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Retrieve the end of the address space */ + eoa = (file->cls->get_eoa)(file, type); + } + H5_AFTER_USER_CB(FAIL) + if (!H5_addr_defined(eoa)) HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_eoa request failed"); /* Adjust block end by base address of the file, to create absolute address */ diff --git a/src/H5FO.c b/src/H5FO.c index a5c47fdb4bd..3a57a57b3cb 100644 --- a/src/H5FO.c +++ b/src/H5FO.c @@ -20,12 +20,13 @@ #define H5F_FRIEND /*suppress error about including H5Fpkg */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5Fpkg.h" /* File access */ -#include "H5FLprivate.h" /* Free lists */ -#include "H5FOprivate.h" /* File objects */ -#include "H5Oprivate.h" /* Object headers */ -#include "H5SLprivate.h" /* Skip Lists */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fpkg.h" /* File access */ +#include "H5FLprivate.h" /* Free lists */ +#include "H5FOprivate.h" /* File objects */ +#include "H5Oprivate.h" /* Object headers */ +#include "H5SLprivate.h" /* Skip Lists */ /* Private typedefs */ diff --git a/src/H5Fint.c b/src/H5Fint.c index d2ede2f978d..9f2b41f572f 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -3501,9 +3501,16 @@ H5F_object_flush_cb(H5F_t *f, hid_t obj_id) assert(f->shared); /* Invoke object flush callback if there is one */ - if (f->shared->object_flush.func && - f->shared->object_flush.func(obj_id, f->shared->object_flush.udata) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "object flush callback returns error"); + if (f->shared->object_flush.func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = f->shared->object_flush.func(obj_id, f->shared->object_flush.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "object flush callback returns error"); + } done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Fsuper.c b/src/H5Fsuper.c index 1a84c455f83..095f17024b6 100644 --- a/src/H5Fsuper.c +++ b/src/H5Fsuper.c @@ -364,9 +364,9 @@ H5F__super_read(H5F_t *f, H5P_genplist_t *fa_plist, bool initial_read) /* Try detecting file's signature */ /* (Don't leave before Bcast, to avoid hang on error) */ H5E_PAUSE_ERRORS - { - H5FD_locate_signature(file, &super_addr); - } + { + H5FD_locate_signature(file, &super_addr); + } H5E_RESUME_ERRORS } /* end if */ diff --git a/src/H5Gint.c b/src/H5Gint.c index c037b99de8b..34dbfb97331 100644 --- a/src/H5Gint.c +++ b/src/H5Gint.c @@ -857,8 +857,13 @@ H5G__iterate_cb(const H5O_link_t *lnk, void *_udata) switch (udata->lnk_op.op_type) { #ifndef H5_NO_DEPRECATED_SYMBOLS case H5G_LINK_OP_OLD: - /* Make the old-type application callback */ - ret_value = (udata->lnk_op.op_func.op_old)(udata->gid, lnk->name, udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the old-type application callback */ + ret_value = (udata->lnk_op.op_func.op_old)(udata->gid, lnk->name, udata->op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) break; #endif /* H5_NO_DEPRECATED_SYMBOLS */ @@ -869,8 +874,13 @@ H5G__iterate_cb(const H5O_link_t *lnk, void *_udata) if (H5G_link_to_info(udata->link_loc, lnk, &info) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link"); - /* Make the application callback */ - ret_value = (udata->lnk_op.op_func.op_new)(udata->gid, lnk->name, &info, udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + ret_value = (udata->lnk_op.op_func.op_new)(udata->gid, lnk->name, &info, udata->op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) } break; default: @@ -1010,8 +1020,13 @@ H5G__visit_cb(const H5O_link_t *lnk, void *_udata) if (H5G_link_to_info(udata->curr_loc->oloc, lnk, &info) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get info for link"); - /* Make the application callback */ - ret_value = (udata->op)(udata->gid, udata->path, &info, udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + ret_value = (udata->op)(udata->gid, udata->path, &info, udata->op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) /* Check for doing more work */ if (ret_value == H5_ITER_CONT && lnk->type == H5L_TYPE_HARD) { diff --git a/src/H5Glink.c b/src/H5Glink.c index 4614d622a3c..2888481ae69 100644 --- a/src/H5Glink.c +++ b/src/H5Glink.c @@ -233,11 +233,17 @@ H5G_link_to_info(const H5O_loc_t *link_loc, const H5O_link_t *lnk, H5L_info2_t * if (link_class != NULL && link_class->query_func != NULL) { ssize_t cb_ret; /* Return value from UD callback */ - /* Call the link's query routine to retrieve the user-defined link's value size */ - /* (in case the query routine packs/unpacks the link value in some way that changes its - * size) */ - if ((cb_ret = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, NULL, - (size_t)0)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the link's query routine to retrieve the user-defined link's value size */ + /* (in case the query routine packs/unpacks the link value in some way that + * changes its size) */ + cb_ret = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, + NULL, (size_t)0); + } + H5_AFTER_USER_CB(FAIL) + if (cb_ret < 0) HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query buffer size callback returned failure"); diff --git a/src/H5Gnode.c b/src/H5Gnode.c index d647096b18c..336eb76d6cc 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -1420,9 +1420,9 @@ H5G_node_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, had /* Try loading symbol table node */ H5E_PAUSE_ERRORS - { - sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG); - } + { + sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG); + } H5E_RESUME_ERRORS if (sn) { unsigned u; /* Local index variable */ diff --git a/src/H5Gstab.c b/src/H5Gstab.c index c86406422b7..5c071b25f9c 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -975,9 +975,9 @@ H5G__stab_valid(H5O_loc_t *grp_oloc, H5O_stab_t *alt_stab) /* Check if the symbol table message's b-tree address is valid */ H5E_PAUSE_ERRORS - { - bt_status = H5B_valid(grp_oloc->file, H5B_SNODE, stab.btree_addr); - } + { + bt_status = H5B_valid(grp_oloc->file, H5B_SNODE, stab.btree_addr); + } H5E_RESUME_ERRORS if (bt_status < 0) { @@ -994,9 +994,9 @@ H5G__stab_valid(H5O_loc_t *grp_oloc, H5O_stab_t *alt_stab) /* Check if the symbol table message's heap address is valid */ H5E_PAUSE_ERRORS - { - heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG); - } + { + heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG); + } H5E_RESUME_ERRORS if (NULL == heap) { diff --git a/src/H5Gtraverse.c b/src/H5Gtraverse.c index 4f0e03fb849..89fac987c72 100644 --- a/src/H5Gtraverse.c +++ b/src/H5Gtraverse.c @@ -187,15 +187,32 @@ H5G__traverse_ud(const H5G_loc_t *grp_loc /*in,out*/, const H5O_link_t *lnk, H5G /* Invoke user-defined callback function */ #ifndef H5_NO_DEPRECATED_SYMBOLS /* (Backwardly compatible with v0 H5L_class_t traversal callback) */ - if (link_class->version == H5L_LINK_CLASS_T_VERS_0) - cb_return = (((const H5L_class_0_t *)link_class)->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, - lnk->u.ud.size, H5CX_get_lapl()); - else - cb_return = (link_class->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, - H5CX_get_lapl(), H5CX_get_dxpl()); + if (link_class->version == H5L_LINK_CLASS_T_VERS_0) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + cb_return = (((const H5L_class_0_t *)link_class)->trav_func)( + lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, H5CX_get_lapl()); + } + H5_AFTER_USER_CB(FAIL) + } + else { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + cb_return = (link_class->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, + H5CX_get_lapl(), H5CX_get_dxpl()); + } + H5_AFTER_USER_CB(FAIL) + } #else /* H5_NO_DEPRECATED_SYMBOLS */ - cb_return = (link_class->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, H5CX_get_lapl(), - H5CX_get_dxpl()); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + cb_return = (link_class->trav_func)(lnk->name, cur_grp, lnk->u.ud.udata, lnk->u.ud.size, + H5CX_get_lapl(), H5CX_get_dxpl()); + } + H5_AFTER_USER_CB(FAIL) #endif /* H5_NO_DEPRECATED_SYMBOLS */ /* Resume recording errors, if we were just checking for object's existence */ diff --git a/src/H5I.c b/src/H5I.c index 201a6fb8e83..dab4eed59a7 100644 --- a/src/H5I.c +++ b/src/H5I.c @@ -620,13 +620,18 @@ H5Iis_valid(hid_t id) static int H5I__search_cb(void *obj, hid_t id, void *_udata) { - H5I_search_ud_t *udata = (H5I_search_ud_t *)_udata; /* User data for callback */ - herr_t cb_ret_val; /* User callback return value */ - int ret_value = H5_ITER_ERROR; /* Callback return value */ + H5I_search_ud_t *udata = (H5I_search_ud_t *)_udata; /* User data for callback */ + herr_t cb_ret_val = FAIL; /* User callback return value */ + int ret_value = H5_ITER_ERROR; /* Callback return value */ FUNC_ENTER_PACKAGE_NOERR - cb_ret_val = (*udata->app_cb)(obj, id, udata->app_key); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + cb_ret_val = (*udata->app_cb)(obj, id, udata->app_key); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) /* Set the return value based on the callback's return value */ if (cb_ret_val > 0) { @@ -710,8 +715,13 @@ H5I__iterate_pub_cb(void H5_ATTR_UNUSED *obj, hid_t id, void *_udata) FUNC_ENTER_PACKAGE_NOERR - /* Invoke the callback */ - cb_ret_val = (*udata->op)(id, udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + /* Invoke the callback */ + cb_ret_val = (*udata->op)(id, udata->op_data); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) /* Set the return value based on the callback's return value */ if (cb_ret_val > 0) diff --git a/src/H5Iint.c b/src/H5Iint.c index 21c4bfc280a..fc59b1583bd 100644 --- a/src/H5Iint.c +++ b/src/H5Iint.c @@ -449,8 +449,16 @@ H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata) if (udata->force || (info->count - (!udata->app_ref * info->app_count)) <= 1) { /* Check if this is an un-realized future object */ if (info->is_future) { - /* Discard the future object */ - if ((info->discard_cb)(info->u.object) < 0) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOCHECK + { + /* Discard the future object */ + status = (info->discard_cb)(info->u.object); + } + H5_AFTER_USER_CB_NOCHECK + if (status < 0) { if (udata->force) { /* Indicate node should be removed from list */ mark = true; @@ -463,12 +471,24 @@ H5I__mark_node(void *_info, void H5_ATTR_UNUSED *key, void *_udata) } else { /* Check for a 'free' function and call it, if it exists */ - if (udata->type_info->cls->free_func && - (udata->type_info->cls->free_func)(info->u.object, H5_REQUEST_NULL) < 0) { - if (udata->force) { + if (udata->type_info->cls->free_func) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOCHECK + { + status = (udata->type_info->cls->free_func)(info->u.object, H5_REQUEST_NULL); + } + H5_AFTER_USER_CB_NOCHECK + if (status < 0) { + if (udata->force) { + /* Indicate node should be removed from list */ + mark = true; + } + } + else /* Indicate node should be removed from list */ mark = true; - } } else { /* Indicate node should be removed from list */ @@ -1042,15 +1062,31 @@ H5I__dec_ref(hid_t id, void **request) */ if (1 == info->count) { H5I_type_info_t *type_info; /*ptr to the type */ + bool remove_node = false; /* Get the ID's type */ type_info = H5I_type_info_array_g[H5I_TYPE(id)]; - if (!type_info->cls->free_func || (type_info->cls->free_func)(info->u.object, request) >= 0) { + if (type_info->cls->free_func) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB((-1)) + { + status = (type_info->cls->free_func)(info->u.object, request); + } + H5_AFTER_USER_CB((-1)) + + if (status >= 0) + remove_node = true; + } + else + remove_node = true; + + if (remove_node) { /* Remove the node from the type */ if (NULL == H5I__remove_common(type_info, id)) HGOTO_ERROR(H5E_ID, H5E_CANTDELETE, (-1), "can't remove ID node"); - ret_value = 0; } /* end if */ else ret_value = -1; @@ -1521,7 +1557,7 @@ H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) if ((!udata->app_ref) || (info->app_count > 0)) { H5I_type_t type = udata->obj_type; void *object; - herr_t cb_ret_val; + herr_t cb_ret_val = FAIL; /* The stored object pointer might be an H5VL_object_t, in which * case we'll need to get the wrapped object struct (H5F_t *, etc.). @@ -1529,7 +1565,12 @@ H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) object = H5I__unwrap(info->u.object, type); /* Invoke callback function */ - cb_ret_val = (*udata->user_func)((void *)object, info->id, udata->user_udata); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + cb_ret_val = (*udata->user_func)((void *)object, info->id, udata->user_udata); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) /* Set the return value based on the callback's return value */ if (cb_ret_val > 0) @@ -1650,12 +1691,19 @@ H5I__find_id(hid_t id) /* Check if this is a future ID */ if (id_info && id_info->is_future) { - hid_t actual_id = H5I_INVALID_HID; /* ID for actual object */ - void *future_object; /* Pointer to the future object */ - void *actual_object; /* Pointer to the actual object */ - - /* Invoke the realize callback, to get the actual object */ - if ((id_info->realize_cb)(id_info->u.object, &actual_id) < 0) + hid_t actual_id = H5I_INVALID_HID; /* ID for actual object */ + void *future_object; /* Pointer to the future object */ + void *actual_object; /* Pointer to the actual object */ + herr_t status = FAIL; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(NULL) + { + /* Invoke the realize callback, to get the actual object */ + status = (id_info->realize_cb)(id_info->u.object, &actual_id); + } + H5_AFTER_USER_CB_NOERR(NULL) + if (status < 0) HGOTO_DONE(NULL); /* Verify that we received a valid ID, of the same type */ @@ -1670,8 +1718,14 @@ H5I__find_id(hid_t id) assert(actual_object); id_info->u.object = actual_object; - /* Discard the future object */ - if ((id_info->discard_cb)(future_object) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(NULL) + { + /* Discard the future object */ + status = (id_info->discard_cb)(future_object); + } + H5_AFTER_USER_CB_NOERR(NULL) + if (status < 0) HGOTO_DONE(NULL); future_object = NULL; diff --git a/src/H5Lexternal.c b/src/H5Lexternal.c index 0d0e890e51e..793825d1c3d 100644 --- a/src/H5Lexternal.c +++ b/src/H5Lexternal.c @@ -193,9 +193,14 @@ H5L__extern_traverse(const char H5_ATTR_UNUSED *link_name, hid_t cur_group, cons if (H5G_get_name(&loc, parent_group_name, group_name_len, NULL, NULL) < 0) HGOTO_ERROR(H5E_LINK, H5E_CANTGET, H5I_INVALID_HID, "unable to retrieve group name"); - /* Make callback */ - if ((cb_info.func)(parent_file_name, parent_group_name, file_name, obj_name, &intent, fapl_id, - cb_info.user_data) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (cb_info.func)(parent_file_name, parent_group_name, file_name, obj_name, &intent, + fapl_id, cb_info.user_data); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, H5I_INVALID_HID, "traversal operator failed"); /* Check access flags */ diff --git a/src/H5Lint.c b/src/H5Lint.c index ab066dd20fd..e8d5e150241 100644 --- a/src/H5Lint.c +++ b/src/H5Lint.c @@ -641,9 +641,15 @@ H5L__link_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t H5_AT if ((grp_id = H5VL_wrap_register(H5I_GROUP, grp, true)) < 0) HGOTO_ERROR(H5E_LINK, H5E_CANTREGISTER, FAIL, "unable to register ID for group"); - /* Make callback */ - if ((link_class->create_func)(name, grp_id, udata->lnk->u.ud.udata, udata->lnk->u.ud.size, - H5P_DEFAULT) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Make callback */ + ret_value = (link_class->create_func)(name, grp_id, udata->lnk->u.ud.udata, + udata->lnk->u.ud.size, H5P_DEFAULT); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "link creation callback failed"); } /* end if */ } /* end if */ @@ -974,7 +980,15 @@ H5L__get_val_real(const H5O_link_t *lnk, void *buf, size_t size) link_class = H5L_find_class(lnk->type); if (link_class != NULL && link_class->query_func != NULL) { - if ((link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, buf, size) < 0) + ssize_t len; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + len = (link_class->query_func)(lnk->name, lnk->u.ud.udata, lnk->u.ud.size, buf, size); + } + H5_AFTER_USER_CB(FAIL) + if (len < 0) HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "query callback returned failure"); } /* end if */ else if (buf && size > 0) @@ -1378,13 +1392,25 @@ H5L__move_dest_cb(H5G_loc_t *grp_loc /*in*/, const char *name, const H5O_link_t HGOTO_ERROR(H5E_LINK, H5E_CANTREGISTER, FAIL, "unable to register group ID"); if (udata->copy) { - if ((link_class->copy_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, - udata->lnk->u.ud.size) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (link_class->copy_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, + udata->lnk->u.ud.size); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD copy callback returned error"); } /* end if */ else { - if ((link_class->move_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, - udata->lnk->u.ud.size) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (link_class->move_func)(udata->lnk->name, grp_id, udata->lnk->u.ud.udata, + udata->lnk->u.ud.size); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_LINK, H5E_CALLBACK, FAIL, "UD move callback returned error"); } /* end else */ } /* end if */ diff --git a/src/H5Ocopy.c b/src/H5Ocopy.c index 9317be0b4f7..3917ad15989 100644 --- a/src/H5Ocopy.c +++ b/src/H5Ocopy.c @@ -1506,9 +1506,16 @@ H5O__copy_search_comm_dt(H5F_t *file_src, H5O_t *oh_src, H5O_loc_t *oloc_dst /*i H5O_mcdt_search_ret_t search_cb_ret = H5O_MCDT_SEARCH_CONT; /* Make callback to see if we should search destination file */ - if (cpy_info->mcdt_cb) - if ((search_cb_ret = cpy_info->mcdt_cb(cpy_info->mcdt_ud)) == H5O_MCDT_SEARCH_ERROR) + if (cpy_info->mcdt_cb) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + search_cb_ret = cpy_info->mcdt_cb(cpy_info->mcdt_ud); + } + H5_AFTER_USER_CB(FAIL) + if (H5O_MCDT_SEARCH_ERROR == search_cb_ret) HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "callback returned error"); + } if (search_cb_ret == H5O_MCDT_SEARCH_CONT) { /* Build the complete dst dt list */ diff --git a/src/H5Odeprec.c b/src/H5Odeprec.c index c4395c1c011..76adad4db42 100644 --- a/src/H5Odeprec.c +++ b/src/H5Odeprec.c @@ -132,17 +132,32 @@ H5O__iterate1_adapter(hid_t obj_id, const char *name, const H5O_info2_t *oinfo2, if (H5O__reset_info1(&oinfo) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't reset object data struct"); + /* Get the location object */ + if (NULL == (vol_obj = H5VL_vol_object(obj_id))) + HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, H5_ITER_ERROR, "invalid location identifier"); + /* Check for retrieving data model information */ dm_fields = shim_data->fields & (H5O_INFO_BASIC | H5O_INFO_TIME | H5O_INFO_NUM_ATTRS); if (dm_fields) { /* Set the data model fields */ if (shim_data->fields & H5O_INFO_BASIC) { + H5I_type_t vol_obj_type = H5I_BADID; /* Object type of loc_id */ + void *vol_obj_data; + oinfo.fileno = oinfo2->fileno; oinfo.type = oinfo2->type; oinfo.rc = oinfo2->rc; + /* Get object type */ + if ((vol_obj_type = H5I_get_type(obj_id)) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "invalid location identifier"); + + /* Retrieve the underlying object */ + if (NULL == (vol_obj_data = H5VL_object_data(vol_obj))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get underlying VOL object"); + /* Deserialize VOL object token into object address */ - if (H5VLnative_token_to_addr(obj_id, oinfo2->token, &oinfo.addr) < 0) + if (H5VL_native_token_to_addr(vol_obj_data, vol_obj_type, oinfo2->token, &oinfo.addr) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize object token into address"); } @@ -170,10 +185,6 @@ H5O__iterate1_adapter(hid_t obj_id, const char *name, const H5O_info2_t *oinfo2, loc_params.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; loc_params.obj_type = H5I_get_type(obj_id); - /* Get the location object */ - if (NULL == (vol_obj = H5VL_vol_object(obj_id))) - HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, H5_ITER_ERROR, "invalid location identifier"); - /* Set up VOL callback arguments */ obj_opt_args.get_native_info.fields = nat_fields; obj_opt_args.get_native_info.ninfo = &nat_info; @@ -246,13 +257,14 @@ H5O__get_info_old(H5VL_object_t *vol_obj, H5VL_loc_params_t *loc_params, H5O_inf if (fields & H5O_INFO_BASIC) { void *vol_obj_data; - if (NULL == (vol_obj_data = H5VL_object_data(vol_obj))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get underlying VOL object"); - oinfo->fileno = dm_info.fileno; oinfo->type = dm_info.type; oinfo->rc = dm_info.rc; + /* Retrieve the underlying object */ + if (NULL == (vol_obj_data = H5VL_object_data(vol_obj))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get underlying VOL object"); + /* Deserialize VOL object token into object address */ if (H5VL_native_token_to_addr(vol_obj_data, loc_params->obj_type, dm_info.token, &oinfo->addr) < 0) @@ -359,8 +371,14 @@ H5Oopen_by_addr(hid_t loc_id, haddr_t addr) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5I_INVALID_HID, "can't determine if VOL object is native connector object"); if (is_native_vol_obj) { + void *vol_obj_data; + + /* Retrieve the underlying object */ + if (NULL == (vol_obj_data = H5VL_object_data(vol_obj))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5I_INVALID_HID, "can't retrieve pointer to native object"); + /* This is a native-specific routine that requires serialization of the token */ - if (H5VLnative_addr_to_token(loc_id, addr, &obj_token) < 0) + if (H5VL_native_addr_to_token(vol_obj_data, vol_obj_type, addr, &obj_token) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, H5I_INVALID_HID, "can't serialize address into object token"); } /* end if */ @@ -423,7 +441,7 @@ H5Oget_info1(hid_t loc_id, H5O_info1_t *oinfo /*out*/) /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_OHDR, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Deprecated H5Oget_info1 is only meant to be used with the native VOL connector"); /* Retrieve the object's information */ @@ -482,7 +500,7 @@ H5Oget_info_by_name1(hid_t loc_id, const char *name, H5O_info1_t *oinfo /*out*/, /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_OHDR, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Deprecated H5Oget_info_by_name1 is only meant to be used with the native VOL connector"); /* Retrieve the object's information */ @@ -547,7 +565,7 @@ H5Oget_info_by_idx1(hid_t loc_id, const char *group_name, H5_index_t idx_type, H /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_OHDR, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Deprecated H5Oget_info_by_idx1 is only meant to be used with the native VOL connector"); /* Retrieve the object's information */ @@ -798,7 +816,7 @@ H5Ovisit1(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, H5O_iterate1 /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_OHDR, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Deprecated H5Ovisit1 is only meant to be used with the native VOL connector"); /* Set location parameters */ @@ -895,7 +913,7 @@ H5Ovisit_by_name1(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_it /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_OHDR, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "Deprecated H5Ovisit_by_name1 is only meant to be used with the native VOL connector"); /* Set location parameters */ diff --git a/src/H5Oint.c b/src/H5Oint.c index 7f7921aeaf8..bf62ad35a9e 100644 --- a/src/H5Oint.c +++ b/src/H5Oint.c @@ -2572,8 +2572,13 @@ H5O__visit_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5L_info2_t *l if (H5O_get_info(&obj_oloc, &oinfo, udata->fields) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "unable to get object info"); - /* Make the application callback */ - ret_value = (udata->op)(udata->obj_id, name, &oinfo, udata->op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Make the application callback */ + ret_value = (udata->op)(udata->obj_id, name, &oinfo, udata->op_data); + } + H5_AFTER_USER_CB(FAIL) /* Check for continuing to visit objects */ if (ret_value == H5_ITER_CONT) { diff --git a/src/H5Olink.c b/src/H5Olink.c index b530e421cba..1aa5d14955c 100644 --- a/src/H5Olink.c +++ b/src/H5Olink.c @@ -636,8 +636,14 @@ H5O_link_delete(H5F_t *f, H5O_t H5_ATTR_UNUSED *open_oh, void *_mesg) if ((file_id = H5F_get_id(f)) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "unable to get file ID"); - /* Call user-defined link's 'delete' callback */ - if ((link_class->del_func)(lnk->name, file_id, lnk->u.ud.udata, lnk->u.ud.size) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user-defined link's 'delete' callback */ + ret_value = (link_class->del_func)(lnk->name, file_id, lnk->u.ud.udata, lnk->u.ud.size); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_OHDR, H5E_CALLBACK, FAIL, "link deletion callback returned failure"); } /* end if */ } /* end if */ diff --git a/src/H5Pdeprec.c b/src/H5Pdeprec.c index c7ea00e4aa4..c0895b837d5 100644 --- a/src/H5Pdeprec.c +++ b/src/H5Pdeprec.c @@ -53,6 +53,7 @@ /********************/ /* Local Prototypes */ /********************/ +static herr_t H5P__get_file_space(H5P_genplist_t *plist, H5F_file_space_type_t *strategy, hsize_t *threshold); /*********************/ /* Package Variables */ @@ -514,9 +515,9 @@ H5Pencode1(hid_t plist_id, void *buf, size_t *nalloc) /*------------------------------------------------------------------------- * Function: H5Pset_file_space * - * Purpose: It is mapped to H5Pset_file_space_strategy(). + * Purpose: Mapped to H5Pset_file_space_strategy(). * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ @@ -524,6 +525,7 @@ herr_t H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t threshold) { + H5P_genplist_t *plist; /* Property list pointer */ H5F_fspace_strategy_t new_strategy; /* File space strategy type */ bool new_persist = H5F_FREE_SPACE_PERSIST_DEF; /* Persisting free-space or not */ hsize_t new_threshold = H5F_FREE_SPACE_THRESHOLD_DEF; /* Free-space section threshold */ @@ -533,8 +535,14 @@ H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t thresh FUNC_ENTER_API(FAIL) + /* Check args */ if ((unsigned)in_strategy >= H5F_FILE_SPACE_NTYPES) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid strategy"); + + /* Get the plist structure */ + if (NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_CREATE, false))) + HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID"); + /* * For 1.10.0 H5Pset_file_space: * If strategy is zero, the property is not changed; @@ -543,9 +551,11 @@ H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t thresh * the existing threshold is retained. */ if (!in_strategy) - H5Pget_file_space(plist_id, &in_strategy, NULL); + if (H5P__get_file_space(plist, &in_strategy, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy"); if (!in_threshold) - H5Pget_file_space(plist_id, NULL, &in_threshold); + if (H5P__get_file_space(plist, NULL, &in_threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space threshold"); switch (in_strategy) { case H5F_FILE_SPACE_ALL_PERSIST: @@ -573,7 +583,7 @@ H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t thresh HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file space strategy"); } - if (H5Pset_file_space_strategy(plist_id, new_strategy, new_persist, new_threshold) < 0) + if (H5P__set_file_space_strategy(plist, new_strategy, new_persist, new_threshold) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file space strategy"); done: @@ -581,27 +591,27 @@ H5Pset_file_space(hid_t plist_id, H5F_file_space_type_t strategy, hsize_t thresh } /* H5Pset_file_space() */ /*------------------------------------------------------------------------- - * Function: H5Pget_file_space + * Function: H5P__get_file_space * - * Purpose: It is mapped to H5Pget_file_space_strategy(). + * Purpose: Mapped to H5Pget_file_space_strategy(). * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * *------------------------------------------------------------------------- */ -herr_t -H5Pget_file_space(hid_t plist_id, H5F_file_space_type_t *strategy /*out*/, hsize_t *threshold /*out*/) +static herr_t +H5P__get_file_space(H5P_genplist_t *plist, H5F_file_space_type_t *strategy, hsize_t *threshold) { H5F_fspace_strategy_t new_strategy; /* File space strategy type */ bool new_persist; /* Persisting free-space or not */ hsize_t new_threshold; /* Free-space section threshold */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_PACKAGE /* Get current file space info */ - if (H5Pget_file_space_strategy(plist_id, &new_strategy, &new_persist, &new_threshold) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy"); + if (H5P__get_file_space_strategy(plist, &new_strategy, &new_persist, &new_threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy values"); /* Get value(s) */ if (strategy) { @@ -632,6 +642,35 @@ H5Pget_file_space(hid_t plist_id, H5F_file_space_type_t *strategy /*out*/, hsize if (threshold) *threshold = new_threshold; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P__get_file_space() */ + +/*------------------------------------------------------------------------- + * Function: H5Pget_file_space + * + * Purpose: It is mapped to H5Pget_file_space_strategy(). + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_file_space(hid_t plist_id, H5F_file_space_type_t *strategy /*out*/, hsize_t *threshold /*out*/) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + + /* Get the plist structure */ + if (NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_CREATE, true))) + HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID"); + + /* Get current file space info */ + if (H5P__get_file_space(plist, strategy, threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy"); + done: FUNC_LEAVE_API(ret_value) } /* H5Pget_file_space() */ diff --git a/src/H5Pencdec.c b/src/H5Pencdec.c index 96cbfc3f018..9550a071be3 100644 --- a/src/H5Pencdec.c +++ b/src/H5Pencdec.c @@ -352,9 +352,15 @@ H5P__encode_cb(H5P_genprop_t *prop, void *_udata) } /* end if */ *(udata->enc_size_ptr) += prop_name_len; - /* Encode (or not, if *(udata->pp) is NULL) the property value */ - prop_value_len = 0; - if ((prop->encode)(prop->value, udata->pp, &prop_value_len) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Encode (or not, if *(udata->pp) is NULL) the property value */ + prop_value_len = 0; + ret_value = (prop->encode)(prop->value, udata->pp, &prop_value_len); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTENCODE, H5_ITER_ERROR, "property encoding routine failed"); *(udata->enc_size_ptr) += prop_value_len; } /* end if */ @@ -768,7 +774,13 @@ H5P__decode(const void *buf) /* Decode serialized value */ if (prop->decode) { - if ((prop->decode)((const void **)&p, value_buf) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (prop->decode)((const void **)&p, value_buf); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTDECODE, FAIL, "property decoding routine failed, property: '%s'", name); } /* end if */ diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c index 9c3e1a327f2..a07018a9214 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -2984,7 +2984,7 @@ H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len) /* Get the plist structure */ if (NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, false))) - HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); + HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID"); /* Get old image info */ if (H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0) @@ -2993,10 +2993,15 @@ H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len) /* Release previous buffer, if it exists */ if (image_info.buffer != NULL) { if (image_info.callbacks.image_free) { - if (SUCCEED != image_info.callbacks.image_free(image_info.buffer, - H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, - image_info.callbacks.udata)) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "image_free callback failed"); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = image_info.callbacks.image_free( + image_info.buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "image_free callback failed"); } /* end if */ else H5MM_xfree(image_info.buffer); @@ -3006,19 +3011,33 @@ H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len) if (buf_ptr) { /* Allocate memory */ if (image_info.callbacks.image_malloc) { - if (NULL == (image_info.buffer = image_info.callbacks.image_malloc( - buf_len, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed"); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + image_info.buffer = image_info.callbacks.image_malloc( + buf_len, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, image_info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == image_info.buffer) + HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "image malloc callback failed"); } /* end if */ else if (NULL == (image_info.buffer = H5MM_malloc(buf_len))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory block"); + HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate memory block"); /* Copy data */ if (image_info.callbacks.image_memcpy) { - if (image_info.buffer != image_info.callbacks.image_memcpy(image_info.buffer, buf_ptr, buf_len, - H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, - image_info.callbacks.udata)) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed"); + void *tmp; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + tmp = image_info.callbacks.image_memcpy(image_info.buffer, buf_ptr, buf_len, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET, + image_info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (image_info.buffer != tmp) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "image_memcpy callback failed"); } /* end if */ else H5MM_memcpy(image_info.buffer, buf_ptr, buf_len); @@ -3073,7 +3092,7 @@ H5Pget_file_image(hid_t fapl_id, void **buf /*out*/, size_t *buf_len /*out*/) /* Get the plist structure */ if (NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, true))) - HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); + HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID"); /* Get values */ if (H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &image_info) < 0) @@ -3094,20 +3113,34 @@ H5Pget_file_image(hid_t fapl_id, void **buf /*out*/, size_t *buf_len /*out*/) if (image_info.buffer != NULL) { /* Allocate memory */ if (image_info.callbacks.image_malloc) { - if (NULL == - (copy_ptr = image_info.callbacks.image_malloc( - image_info.size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, image_info.callbacks.udata))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "image malloc callback failed"); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + copy_ptr = image_info.callbacks.image_malloc(image_info.size, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, + image_info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == copy_ptr) + HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "image malloc callback failed"); } /* end if */ else if (NULL == (copy_ptr = H5MM_malloc(image_info.size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate copy"); + HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate copy"); /* Copy data */ if (image_info.callbacks.image_memcpy) { - if (copy_ptr != image_info.callbacks.image_memcpy( - copy_ptr, image_info.buffer, image_info.size, - H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, image_info.callbacks.udata)) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCOPY, FAIL, "image_memcpy callback failed"); + void *tmp; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + tmp = image_info.callbacks.image_memcpy(copy_ptr, image_info.buffer, image_info.size, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET, + image_info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (copy_ptr != tmp) + HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "image_memcpy callback failed"); } /* end if */ else H5MM_memcpy(copy_ptr, image_info.buffer, image_info.size); @@ -3145,7 +3178,7 @@ H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callback /* Get the plist structure */ if (NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, false))) - HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); + HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID"); /* Get old info */ if (H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0) @@ -3172,8 +3205,15 @@ H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callback /* Release old udata if it exists */ if (info.callbacks.udata != NULL) { assert(info.callbacks.udata_free); - if (info.callbacks.udata_free(info.callbacks.udata) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed"); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = info.callbacks.udata_free(info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "udata_free callback failed"); } /* end if */ /* Update struct */ @@ -3182,7 +3222,14 @@ H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callback if (callbacks_ptr->udata) { assert(callbacks_ptr->udata_copy); assert(callbacks_ptr->udata_free); - if ((info.callbacks.udata = callbacks_ptr->udata_copy(callbacks_ptr->udata)) == NULL) + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + info.callbacks.udata = callbacks_ptr->udata_copy(callbacks_ptr->udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == info.callbacks.udata) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy the supplied udata"); } /* end if */ @@ -3194,8 +3241,16 @@ H5Pset_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callback done: if (ret_value < 0) { - if (copied_udata && (callbacks_ptr->udata_free(info.callbacks.udata) < 0)) - HDONE_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "udata_free callback failed"); + if (copied_udata) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = callbacks_ptr->udata_free(info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HDONE_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "udata_free callback failed"); + } } FUNC_LEAVE_API(ret_value) @@ -3224,7 +3279,7 @@ H5Pget_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callback /* Get the plist structure */ if (NULL == (fapl = H5P_object_verify(fapl_id, H5P_FILE_ACCESS, true))) - HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); + HGOTO_ERROR(H5E_PLIST, H5E_BADID, FAIL, "can't find object for ID"); /* Get old info */ if (H5P_peek(fapl, H5F_ACS_FILE_IMAGE_INFO_NAME, &info) < 0) @@ -3243,7 +3298,14 @@ H5Pget_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callback /* Copy udata if it exists */ if (info.callbacks.udata != NULL) { assert(info.callbacks.udata_copy); - if ((callbacks->udata = info.callbacks.udata_copy(info.callbacks.udata)) == 0) + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + callbacks->udata = info.callbacks.udata_copy(info.callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == callbacks->udata) HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't copy udata"); } /* end if */ @@ -3290,20 +3352,32 @@ H5P__file_image_info_copy(void *value) /* Allocate new buffer */ if (info->callbacks.image_malloc) { - if (NULL == (info->buffer = info->callbacks.image_malloc( - info->size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, info->callbacks.udata))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + info->buffer = info->callbacks.image_malloc( + info->size, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, info->callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == info->buffer) HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "image malloc callback failed"); } /* end if */ - else { - if (NULL == (info->buffer = H5MM_malloc(info->size))) - HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate memory block"); - } /* end else */ + else if (NULL == (info->buffer = H5MM_malloc(info->size))) + HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "unable to allocate memory block"); /* Copy data to new buffer */ if (info->callbacks.image_memcpy) { - if (info->buffer != info->callbacks.image_memcpy(info->buffer, old_buffer, info->size, - H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, - info->callbacks.udata)) + void *tmp; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + tmp = info->callbacks.image_memcpy(info->buffer, old_buffer, info->size, + H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY, + info->callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (info->buffer != tmp) HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "image_memcpy callback failed"); } /* end if */ else @@ -3317,7 +3391,12 @@ H5P__file_image_info_copy(void *value) if (NULL == info->callbacks.udata_copy) HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "udata_copy not defined"); - info->callbacks.udata = info->callbacks.udata_copy(old_udata); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + info->callbacks.udata = info->callbacks.udata_copy(old_udata); + } + H5_AFTER_USER_CB(FAIL) } /* end if */ } /* end if */ @@ -3355,8 +3434,14 @@ H5P__file_image_info_free(void *value) /* Free buffer */ if (info->buffer != NULL && info->size > 0) { if (info->callbacks.image_free) { - if ((*info->callbacks.image_free)(info->buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, - info->callbacks.udata) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (*info->callbacks.image_free)( + info->buffer, H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE, info->callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "image_free callback failed"); } /* end if */ else @@ -3367,7 +3452,13 @@ H5P__file_image_info_free(void *value) if (info->callbacks.udata) { if (NULL == info->callbacks.udata_free) HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "udata_free not defined"); - if ((*info->callbacks.udata_free)(info->callbacks.udata) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (*info->callbacks.udata_free)(info->callbacks.udata); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "udata_free callback failed"); } /* end if */ } /* end if */ @@ -3428,13 +3519,13 @@ H5P__facc_cache_image_config_cmp(const void *_config1, const void *_config2, siz } /* end H5P__facc_cache_image_config_cmp() */ /*------------------------------------------------------------------------- - * Function: H5P__facc_cache_image_config_enc + * Function: H5P__facc_cache_image_config_enc * - * Purpose: Callback routine which is called whenever the default - * cache image config property in the file creation + * Purpose: Callback routine which is called whenever the default + * cache image config property in the file creation * property list is encoded. * - * Return: Success: Non-negative + * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- @@ -3456,11 +3547,8 @@ H5P__facc_cache_image_config_enc(const void *value, void **_pp, size_t *size) *(*pp)++ = (uint8_t)sizeof(unsigned); INT32ENCODE(*pp, (int32_t)config->version); - H5_ENCODE_UNSIGNED(*pp, config->generate_image); - H5_ENCODE_UNSIGNED(*pp, config->save_resize_status); - INT32ENCODE(*pp, (int32_t)config->entry_ageout); } /* end if */ @@ -3471,13 +3559,13 @@ H5P__facc_cache_image_config_enc(const void *value, void **_pp, size_t *size) } /* end H5P__facc_cache_image_config_enc() */ /*------------------------------------------------------------------------- - * Function: H5P__facc_cache_image_config_dec + * Function: H5P__facc_cache_image_config_dec * - * Purpose: Callback routine which is called whenever the default - * cache image config property in the file creation property + * Purpose: Callback routine which is called whenever the default + * cache image config property in the file creation property * list is decoded. * - * Return: Success: Non-negative + * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- @@ -3507,11 +3595,8 @@ H5P__facc_cache_image_config_dec(const void **_pp, void *_value) HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "unsigned value can't be decoded"); INT32DECODE(*pp, config->version); - H5_DECODE_UNSIGNED(*pp, config->generate_image); - H5_DECODE_UNSIGNED(*pp, config->save_resize_status); - INT32DECODE(*pp, config->entry_ageout); done: diff --git a/src/H5Pfcpl.c b/src/H5Pfcpl.c index efec3fd095b..401c550a7e9 100644 --- a/src/H5Pfcpl.c +++ b/src/H5Pfcpl.c @@ -1164,13 +1164,48 @@ H5Pget_shared_mesg_phase_change(hid_t plist_id, unsigned *max_list /*out*/, unsi FUNC_LEAVE_API(ret_value) } /* end H5Pget_shared_mesg_phase_change() */ +/*------------------------------------------------------------------------- + * Function: H5P__set_file_space_strategy + * + * Purpose: Internal routine to set file space strategy properties. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5P__set_file_space_strategy(H5P_genplist_t *plist, H5F_fspace_strategy_t strategy, hbool_t persist, + hsize_t threshold) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Set value(s), if non-zero */ + if (H5P_set(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &strategy) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file space strategy"); + + /* Ignore persist and threshold settings for strategies that do not use FSM */ + if (strategy == H5F_FSPACE_STRATEGY_FSM_AGGR || strategy == H5F_FSPACE_STRATEGY_PAGE) { + if (H5P_set(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, &persist) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set free-space persisting status"); + + if (H5P_set(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set free-space threshold"); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P__set_file_space_strategy() */ + /*------------------------------------------------------------------------- * Function: H5Pset_file_space_strategy * * Purpose: Sets the "strategy" that the library employs in managing file space - * Sets the "persist" value as to persist free-space or not - * Sets the "threshold" value that the free space manager(s) will use to track free space - *sections. Ignore "persist" and "threshold" for strategies that do not use free-space managers + * Sets the "persist" value as to persist free-space or not + * Sets the "threshold" value that the free space manager(s) will + * use to track free space sections. Ignore "persist" and + * "threshold" for strategies that do not use free-space managers. * * Return: Non-negative on success/Negative on failure * @@ -1192,23 +1227,47 @@ H5Pset_file_space_strategy(hid_t plist_id, H5F_fspace_strategy_t strategy, hbool if (NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_CREATE, false))) HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); - /* Set value(s), if non-zero */ - if (H5P_set(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, &strategy) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file space strategy"); - - /* Ignore persist and threshold settings for strategies that do not use FSM */ - if (strategy == H5F_FSPACE_STRATEGY_FSM_AGGR || strategy == H5F_FSPACE_STRATEGY_PAGE) { - if (H5P_set(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, &persist) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set free-space persisting status"); - - if (H5P_set(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, &threshold) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set free-space threshold"); - } /* end if */ + /* Set value(s) */ + if (H5P__set_file_space_strategy(plist, strategy, persist, threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set file space strategy values"); done: FUNC_LEAVE_API(ret_value) } /* H5Pset_file_space_strategy() */ +/*------------------------------------------------------------------------- + * Function: H5P__get_file_space_strategy + * + * Purpose: Retrieves the strategy, persist, and threshold that the library + * uses in managing file space. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5P__get_file_space_strategy(H5P_genplist_t *plist, H5F_fspace_strategy_t *strategy /*out*/, + hbool_t *persist /*out*/, hsize_t *threshold /*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Get value(s) */ + if (strategy) + if (H5P_get(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, strategy) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy"); + if (persist) + if (H5P_get(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, persist) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space persisting status"); + if (threshold) + if (H5P_get(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space threshold"); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5P__get_file_space_strategy() */ + /*------------------------------------------------------------------------- * Function: H5Pget_file_space_strategy * @@ -1233,15 +1292,8 @@ H5Pget_file_space_strategy(hid_t plist_id, H5F_fspace_strategy_t *strategy /*out HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); /* Get value(s) */ - if (strategy) - if (H5P_get(plist, H5F_CRT_FILE_SPACE_STRATEGY_NAME, strategy) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy"); - if (persist) - if (H5P_get(plist, H5F_CRT_FREE_SPACE_PERSIST_NAME, persist) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space persisting status"); - if (threshold) - if (H5P_get(plist, H5F_CRT_FREE_SPACE_THRESHOLD_NAME, threshold) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get free-space threshold"); + if (H5P__get_file_space_strategy(plist, strategy, persist, threshold) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get file space strategy values"); done: FUNC_LEAVE_API(ret_value) diff --git a/src/H5Pint.c b/src/H5Pint.c index 2c7af8ee273..0cacaf79527 100644 --- a/src/H5Pint.c +++ b/src/H5Pint.c @@ -804,8 +804,14 @@ H5P__do_prop_cb1(H5SL_t *slist, H5P_genprop_t *prop, H5P_prp_cb1_t cb) HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed for temporary property value"); H5MM_memcpy(tmp_value, prop->value, prop->size); - /* Call "type 1" callback ('create', 'copy' or 'close') */ - if (cb(prop->name, prop->size, tmp_value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call "type 1" callback ('create', 'copy' or 'close') */ + ret_value = cb(prop->name, prop->size, tmp_value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "Property callback failed"); /* Make a copy of the class's property */ @@ -1016,7 +1022,15 @@ H5P_copy_plist(const H5P_genplist_t *old_plist, bool app_ref) /* Call property copy callback, if it exists */ if (new_prop->copy) { - if ((new_prop->copy)(new_prop->name, new_prop->size, new_prop->value) < 0) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5I_INVALID_HID) + { + status = (new_prop->copy)(new_prop->name, new_prop->size, new_prop->value); + } + H5_AFTER_USER_CB(H5I_INVALID_HID) + if (status < 0) { H5P__free_prop(new_prop); HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, H5I_INVALID_HID, "Can't copy property"); } /* end if */ @@ -1104,7 +1118,16 @@ H5P_copy_plist(const H5P_genplist_t *old_plist, bool app_ref) tclass = new_plist->pclass; while (NULL != tclass) { if (NULL != tclass->copy_func) { - if ((tclass->copy_func)(new_plist_id, old_plist->plist_id, old_plist->pclass->copy_data) < 0) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5I_INVALID_HID) + { + status = + (tclass->copy_func)(new_plist_id, old_plist->plist_id, old_plist->pclass->copy_data); + } + H5_AFTER_USER_CB(H5I_INVALID_HID) + if (status < 0) { /* Delete ID, ignore return value */ H5I_remove(new_plist_id); HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, H5I_INVALID_HID, "Can't initialize property"); @@ -1530,8 +1553,15 @@ H5P__free_prop_cb(void *item, void H5_ATTR_UNUSED *key, void *op_data) assert(tprop); /* Call the close callback and ignore the return value, there's nothing we can do about it */ - if (make_cb && tprop->close != NULL) - (tprop->close)(tprop->name, tprop->size, tprop->value); + if (make_cb && tprop->close != NULL) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOCHECK + { + /* Call user's callback */ + (tprop->close)(tprop->name, tprop->size, tprop->value); + } + H5_AFTER_USER_CB_NOCHECK + } /* Free the property, ignoring return value, nothing we can do */ H5P__free_prop(tprop); @@ -2009,7 +2039,15 @@ H5P_create_id(H5P_genclass_t *pclass, bool app_ref) tclass = plist->pclass; while (NULL != tclass) { if (NULL != tclass->create_func) { - if ((tclass->create_func)(plist_id, tclass->create_data) < 0) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = (tclass->create_func)(plist_id, tclass->create_data); + } + H5_AFTER_USER_CB(FAIL) + if (status < 0) { /* Delete ID, ignore return value */ H5I_remove(plist_id); HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, H5I_INVALID_HID, "Can't initialize property"); @@ -3033,8 +3071,14 @@ H5P__set_plist_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop, HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed temporary property value"); H5MM_memcpy(tmp_value, udata->value, prop->size); - /* Call user's callback */ - if ((*(prop->set))(plist->plist_id, name, prop->size, tmp_value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (*(prop->set))(plist->plist_id, name, prop->size, tmp_value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value"); /* Set the pointer for copying */ @@ -3046,8 +3090,14 @@ H5P__set_plist_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop, /* Free any previous value for the property */ if (NULL != prop->del) { - /* Call user's 'delete' callback */ - if ((*(prop->del))(plist->plist_id, name, prop->size, prop->value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (*(prop->del))(plist->plist_id, name, prop->size, prop->value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't release property value"); } /* end if */ @@ -3111,8 +3161,14 @@ H5P__set_pclass_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop, HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed temporary property value"); H5MM_memcpy(tmp_value, udata->value, prop->size); - /* Call user's callback */ - if ((*(prop->set))(plist->plist_id, name, prop->size, tmp_value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (*(prop->set))(plist->plist_id, name, prop->size, tmp_value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value"); /* Set the pointer for copying */ @@ -3709,8 +3765,15 @@ H5P__cmp_prop(const H5P_genprop_t *prop1, const H5P_genprop_t *prop2) if (prop1->value != NULL && prop2->value == NULL) HGOTO_DONE(1); if (prop1->value != NULL) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOCHECK + { + /* Call comparison routine */ + cmp_value = prop1->cmp(prop1->value, prop2->value, prop1->size); + } + H5_AFTER_USER_CB_NOCHECK /* Call comparison routine */ - if ((cmp_value = prop1->cmp(prop1->value, prop2->value, prop1->size)) != 0) + if (0 != cmp_value) HGOTO_DONE(cmp_value); } /* end if */ @@ -4206,8 +4269,13 @@ H5P__iterate_plist_cb(void *_item, void *_key, void *_udata) /* Check if we've found the correctly indexed property */ if (*udata->curr_idx_ptr >= udata->prev_idx) { - /* Call the callback function */ - ret_value = (*udata->cb_func)(item, udata->udata); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + /* Call the callback function */ + ret_value = (*udata->cb_func)(item, udata->udata); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) if (ret_value != 0) HGOTO_DONE(ret_value); } /* end if */ @@ -4417,8 +4485,13 @@ H5P__iterate_pclass_cb(void *_item, void H5_ATTR_NDEBUG_UNUSED *_key, void *_uda /* Check if we've found the correctly indexed property */ if (*udata->curr_idx_ptr >= udata->prev_idx) { - /* Call the callback function */ - ret_value = (*udata->cb_func)(item, udata->udata); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR) + { + /* Call the callback function */ + ret_value = (*udata->cb_func)(item, udata->udata); + } + H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR) if (ret_value != 0) HGOTO_DONE(ret_value); } /* end if */ @@ -4653,8 +4726,14 @@ H5P__get_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop, void * HGOTO_ERROR(H5E_PLIST, H5E_CANTALLOC, FAIL, "memory allocation failed temporary property value"); H5MM_memcpy(tmp_value, prop->value, prop->size); - /* Call user's callback */ - if ((*(prop->get))(plist->plist_id, name, prop->size, tmp_value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (*(prop->get))(plist->plist_id, name, prop->size, tmp_value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set property value"); /* Copy new [possibly unchanged] value into return value */ @@ -4758,8 +4837,14 @@ H5P__del_plist_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop, /* Pass value to 'close' callback, if it exists */ if (NULL != prop->del) { - /* Call user's callback */ - if ((*(prop->del))(plist->plist_id, name, prop->size, prop->value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (*(prop->del))(plist->plist_id, name, prop->size, prop->value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTFREE, FAIL, "can't release property value"); } /* end if */ @@ -4833,8 +4918,14 @@ H5P__del_pclass_cb(H5P_genplist_t *plist, const char *name, H5P_genprop_t *prop, "memory allocation failed for temporary property value"); H5MM_memcpy(tmp_value, prop->value, prop->size); - /* Call user's callback */ - if ((*(prop->del))(plist->plist_id, name, prop->size, tmp_value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (*(prop->del))(plist->plist_id, name, prop->size, tmp_value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't close property value"); } /* end if */ @@ -4973,7 +5064,14 @@ H5P__copy_prop_plist(hid_t dst_id, hid_t src_id, const char *name) /* Call property copy callback, if it exists */ if (new_prop->copy) { - if ((new_prop->copy)(new_prop->name, new_prop->size, new_prop->value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + ret_value = (new_prop->copy)(new_prop->name, new_prop->size, new_prop->value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTCOPY, FAIL, "Can't copy property"); } /* end if */ } /* end if */ @@ -4990,7 +5088,13 @@ H5P__copy_prop_plist(hid_t dst_id, hid_t src_id, const char *name) /* Call property creation callback, if it exists */ if (new_prop->create) { - if ((new_prop->create)(new_prop->name, new_prop->size, new_prop->value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (new_prop->create)(new_prop->name, new_prop->size, new_prop->value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "Can't initialize property"); } /* end if */ } /* end else */ @@ -5200,8 +5304,13 @@ H5P_close(H5P_genplist_t *plist) tclass = plist->pclass; while (NULL != tclass) { if (NULL != tclass->close_func) { - /* Call user's "close" callback function, ignoring return value */ - (tclass->close_func)(plist->plist_id, tclass->close_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's "close" callback function, ignoring return value */ + (tclass->close_func)(plist->plist_id, tclass->close_data); + } + H5_AFTER_USER_CB(FAIL) } /* end if */ /* Go up to parent class */ @@ -5227,8 +5336,13 @@ H5P_close(H5P_genplist_t *plist) /* Call property close callback, if it exists */ if (tmp->close) { - /* Call the 'close' callback */ - (tmp->close)(tmp->name, tmp->size, tmp->value); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + (tmp->close)(tmp->name, tmp->size, tmp->value); + } + H5_AFTER_USER_CB(FAIL) } /* end if */ /* Add property name to "seen" list */ @@ -5274,8 +5388,13 @@ H5P_close(H5P_genplist_t *plist) "memory allocation failed for temporary property value"); H5MM_memcpy(tmp_value, tmp->value, tmp->size); - /* Call the 'close' callback */ - (tmp->close)(tmp->name, tmp->size, tmp_value); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call user's callback */ + (tmp->close)(tmp->name, tmp->size, tmp_value); + } + H5_AFTER_USER_CB(FAIL) /* Release the temporary value buffer */ H5MM_xfree(tmp_value); diff --git a/src/H5Ppkg.h b/src/H5Ppkg.h index a1f3e3a5233..c4abf101640 100644 --- a/src/H5Ppkg.h +++ b/src/H5Ppkg.h @@ -193,6 +193,12 @@ H5_DLL herr_t H5P__decode_coll_md_read_flag_t(const void **_pp, void *value); /* Private FAPL routines */ H5_DLL herr_t H5P__facc_set_def_driver(void); +/* Private FCPL routines */ +H5_DLL herr_t H5P__get_file_space_strategy(H5P_genplist_t *plist, H5F_fspace_strategy_t *strategy, + hbool_t *persist, hsize_t *threshold); +H5_DLL herr_t H5P__set_file_space_strategy(H5P_genplist_t *plist, H5F_fspace_strategy_t strategy, + hbool_t persist, hsize_t threshold); + /* Private OCPL routines */ H5_DLL herr_t H5P__get_filter(const struct H5Z_filter_info_t *filter, unsigned int *flags, size_t *cd_nelmts, unsigned cd_values[], size_t namelen, char name[], unsigned *filter_config); diff --git a/src/H5SMcache.c b/src/H5SMcache.c index 3be26d6945c..eb6d612a783 100644 --- a/src/H5SMcache.c +++ b/src/H5SMcache.c @@ -28,10 +28,11 @@ /***********/ /* Headers */ /***********/ -#include "H5Eprivate.h" /* Error handling */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* File access */ #include "H5FLprivate.h" /* Free Lists */ -#include "H5MMprivate.h" /* Memory management */ +#include "H5MMprivate.h" /* Memory management */ #include "H5SMpkg.h" /* Shared object header messages */ /****************/ diff --git a/src/H5Sselect.c b/src/H5Sselect.c index 88110be5f97..d40474a5ac0 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -1449,8 +1449,14 @@ H5S_select_iterate(void *buf, const H5T_t *type, H5S_t *space, const H5S_sel_ite /* Check which type of callback to make */ switch (op->op_type) { case H5S_SEL_ITER_OP_APP: - /* Make the application callback */ - user_ret = (op->u.app_op.op)(loc, op->u.app_op.type_id, ndims, coords, op_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(H5_ITER_ERROR) + { + /* Make the application callback */ + user_ret = + (op->u.app_op.op)(loc, op->u.app_op.type_id, ndims, coords, op_data); + } + H5_AFTER_USER_CB(H5_ITER_ERROR) break; case H5S_SEL_ITER_OP_LIB: diff --git a/src/H5T.c b/src/H5T.c index 1999141cfc1..4ad4f2dbf97 100644 --- a/src/H5T.c +++ b/src/H5T.c @@ -3198,7 +3198,14 @@ H5T__register(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst, H5T_con HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register ID for destination datatype"); - if ((conv->u.app_func)(tmp_sid, tmp_did, &cdata, 0, 0, 0, NULL, NULL, H5CX_get_dxpl()) < 0) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (conv->u.app_func)(tmp_sid, tmp_did, &cdata, 0, 0, 0, NULL, NULL, + H5CX_get_dxpl()); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) { if (H5I_dec_ref(tmp_sid) < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTDEC, FAIL, "unable to decrement reference count on temporary ID"); @@ -5870,7 +5877,13 @@ H5T__path_find_init_new_path(H5T_path_t *path, const H5T_t *src, const H5T_t *ds HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register ID for destination datatype"); - status = (conv->u.app_func)(src_id, dst_id, &(path->cdata), 0, 0, 0, NULL, NULL, H5CX_get_dxpl()); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = (conv->u.app_func)(src_id, dst_id, &(path->cdata), 0, 0, 0, NULL, NULL, + H5CX_get_dxpl()); + } + H5_AFTER_USER_CB(FAIL) } else status = (conv->u.lib_func)(path->src, path->dst, &(path->cdata), conv_ctx, 0, 0, 0, NULL, NULL); @@ -5924,8 +5937,13 @@ H5T__path_find_init_new_path(H5T_path_t *path, const H5T_t *src, const H5T_t *ds HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register ID for destination datatype"); - status = (H5T_g.soft[i].conv.u.app_func)(src_id, dst_id, &(path->cdata), 0, 0, 0, NULL, NULL, - H5CX_get_dxpl()); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = (H5T_g.soft[i].conv.u.app_func)(src_id, dst_id, &(path->cdata), 0, 0, 0, NULL, + NULL, H5CX_get_dxpl()); + } + H5_AFTER_USER_CB(FAIL) } else status = (H5T_g.soft[i].conv.u.lib_func)(path->src, path->dst, &(path->cdata), conv_ctx, 0, 0, 0, @@ -6010,9 +6028,16 @@ H5T__path_free(H5T_path_t *path, H5T_conv_ctx_t *conv_ctx) path->cdata.command = H5T_CONV_FREE; - if (path->conv.is_app) - status = (path->conv.u.app_func)(conv_ctx->u.free.src_type_id, conv_ctx->u.free.dst_type_id, - &(path->cdata), 0, 0, 0, NULL, NULL, H5CX_get_dxpl()); + if (path->conv.is_app) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(FAIL) + { + status = + (path->conv.u.app_func)(conv_ctx->u.free.src_type_id, conv_ctx->u.free.dst_type_id, + &(path->cdata), 0, 0, 0, NULL, NULL, H5CX_get_dxpl()); + } + H5_AFTER_USER_CB_NOERR(FAIL) + } else status = (path->conv.u.lib_func)(path->src, path->dst, &(path->cdata), conv_ctx, 0, 0, 0, NULL, NULL); @@ -6426,9 +6451,15 @@ H5T_convert_with_ctx(H5T_path_t *tpath, const H5T_t *src_type, const H5T_t *dst_ /* Call the appropriate conversion callback */ tpath->cdata.command = H5T_CONV_CONV; if (tpath->conv.is_app) { - if ((tpath->conv.u.app_func)(conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, - &(tpath->cdata), nelmts, buf_stride, bkg_stride, buf, bkg, - conv_ctx->u.conv.dxpl_id) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (tpath->conv.u.app_func)( + conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, &(tpath->cdata), nelmts, + buf_stride, bkg_stride, buf, bkg, conv_ctx->u.conv.dxpl_id); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "datatype conversion failed"); } /* end if */ else if ((tpath->conv.u.lib_func)(src_type, dst_type, &(tpath->cdata), conv_ctx, nelmts, buf_stride, diff --git a/src/H5TS.c b/src/H5TS.c index 2b025724cc4..469d492acf3 100644 --- a/src/H5TS.c +++ b/src/H5TS.c @@ -35,7 +35,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5TSpkg.h" /* Threadsafety */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /****************/ /* Local Macros */ @@ -147,4 +147,4 @@ H5TSmutex_release(unsigned *lock_count) FUNC_LEAVE_API_NAMECHECK_ONLY(ret_value) } /* end H5TSmutex_release() */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/src/H5TSc11.c b/src/H5TSc11.c index 016a066c1dd..6ea9caefb6f 100644 --- a/src/H5TSc11.c +++ b/src/H5TSc11.c @@ -58,7 +58,7 @@ /* Local Variables */ /*******************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /*-------------------------------------------------------------------------- * Function: H5TS__c11_first_thread_init * @@ -76,10 +76,10 @@ H5TS__c11_first_thread_init(void) FUNC_ENTER_PACKAGE_NAMECHECK_ONLY /* Initialize H5TS package */ - H5TS__init(); + H5TS__init_package(); FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY } /* end H5TS__c11_first_thread_init() */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #endif /* H5_HAVE_C11_THREADS */ diff --git a/src/H5TSint.c b/src/H5TSint.c index 503e21cb1e8..7edc46f5ada 100644 --- a/src/H5TSint.c +++ b/src/H5TSint.c @@ -37,7 +37,7 @@ #include "H5Epkg.h" /* Error handling */ #include "H5TSpkg.h" /* Threadsafety */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /****************/ /* Local Macros */ @@ -62,6 +62,9 @@ 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_stack_t err_stack; /* Error stack */ +#ifdef H5_HAVE_CONCURRENCY + unsigned dlftt; /* Whether locking is disabled for this thread */ +#endif /* H5_HAVE_CONCURRENCY */ } H5TS_thread_info_t; /* An H5TS_tinfo_node_t is a thread info that is available for reuse */ @@ -74,6 +77,12 @@ typedef struct H5TS_tinfo_node_t { /* Local Prototypes */ /********************/ static H5TS_tinfo_node_t *H5TS__tinfo_create(void); +#ifdef H5_HAVE_CONCURRENCY +static herr_t H5TS__get_dlftt(unsigned *dlftt); +static herr_t H5TS__set_dlftt(unsigned dlftt); +static herr_t H5TS__inc_dlftt(void); +static herr_t H5TS__dec_dlftt(void); +#endif /* H5_HAVE_CONCURRENCY */ /*********************/ /* Package Variables */ @@ -103,26 +112,33 @@ static uint64_t H5TS_next_thrd_id_s = 0; /* Mutex for access to H5TS_tinfo_next_free_s and H5TS_next_thrd_id_s */ static H5TS_mutex_t H5TS_tinfo_mtx_s; -/*------------------------------------------------------------------------- - * Function: H5TS__init - * - * Purpose: Initialize the H5TS interface - * - * Return: Non-negative on success / Negative on failure - * - *------------------------------------------------------------------------- - */ +/*-------------------------------------------------------------------------- +NAME + H5TS__init_package -- Initialize interface-specific information +USAGE + herr_t H5TS__init_package() +RETURNS + Non-negative on success/Negative on failure +DESCRIPTION + Initializes any interface-specific data or routines. + +--------------------------------------------------------------------------*/ herr_t -H5TS__init(void) +H5TS__init_package(void) { herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + FUNC_ENTER_PACKAGE_NOERR /* Initialize the global API lock info */ +#ifdef H5_HAVE_THREADSAFE if (H5_UNLIKELY(H5TS_mutex_init(&H5TS_api_info_p.api_mutex, H5TS_MUTEX_TYPE_RECURSIVE) < 0)) HGOTO_DONE(FAIL); H5TS_api_info_p.lock_count = 0; +#else /* H5_HAVE_CONCURRENCY */ + if (H5_UNLIKELY(H5TS_rwlock_init(&H5TS_api_info_p.api_lock) < 0)) + HGOTO_DONE(FAIL); +#endif H5TS_atomic_init_uint(&H5TS_api_info_p.attempt_lock_count, 0); /* Initialize per-thread library info */ @@ -130,8 +146,8 @@ H5TS__init(void) HGOTO_DONE(FAIL); done: - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__init() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* H5TS__init_package() */ /*------------------------------------------------------------------------- * Function: H5TS_term_package @@ -153,12 +169,66 @@ H5TS_term_package(void) FUNC_ENTER_NOAPI_NOINIT_NOERR /* Reset global API lock info */ +#ifdef H5_HAVE_THREADSAFE H5TS_mutex_destroy(&H5TS_api_info_p.api_mutex); +#else /* H5_HAVE_CONCURRENCY */ + H5TS_rwlock_destroy(&H5TS_api_info_p.api_lock); +#endif H5TS_atomic_destroy_uint(&H5TS_api_info_p.attempt_lock_count); FUNC_LEAVE_NOAPI_VOID } /* end H5TS_term_package() */ +#ifdef H5_HAVE_CONCURRENCY +/*------------------------------------------------------------------------- + * Function: H5TS_user_cb_prepare + * + * Purpose: Prepare the H5E package before a user callback + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_user_cb_prepare(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Increment the 'disable locking for this thread' (DLFTT) value */ + if (H5TS__inc_dlftt() < 0) + HGOTO_ERROR(H5E_LIB, H5E_CANTINC, FAIL, "unable to increment DLFTT value"); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5TS_user_cb_prepare() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_user_cb_restore + * + * Purpose: Restores the state of the H5TS package after a user callback + * + * Return: SUCCEED/FAIL + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_user_cb_restore(void) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Decrement the 'disable locking for this thread' (DLFTT) value */ + if (H5TS__dec_dlftt() < 0) + HGOTO_ERROR(H5E_LIB, H5E_CANTDEC, FAIL, "unable to decrement DLFTT value"); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5TS_user_cb_restore() */ +#endif /* H5_HAVE_CONCURRENCY */ + /*-------------------------------------------------------------------------- * Function: H5TS__api_mutex_acquire * @@ -174,21 +244,45 @@ H5TS_term_package(void) herr_t H5TS__api_mutex_acquire(unsigned lock_count, bool *acquired) { +#ifdef H5_HAVE_CONCURRENCY + unsigned dlftt = 0; +#endif herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE_NAMECHECK_ONLY +#ifdef H5_HAVE_THREADSAFE /* Attempt to acquire the lock */ if (H5_UNLIKELY(H5TS_mutex_trylock(&H5TS_api_info_p.api_mutex, acquired) < 0)) HGOTO_DONE(FAIL); - /* If acquired, increment the levels of recursion by 'lock_count' - 1 */ + /* If acquired, acquire the mutex ('lock_count' - 1) more times */ if (*acquired) { for (unsigned u = 0; u < (lock_count - 1); u++) if (H5_UNLIKELY(H5TS_mutex_lock(&H5TS_api_info_p.api_mutex) < 0)) HGOTO_DONE(FAIL); H5TS_api_info_p.lock_count += lock_count; } +#else /* H5_HAVE_CONCURRENCY */ + /* Query the DLFTT value */ + if (H5_UNLIKELY(H5TS__get_dlftt(&dlftt) < 0)) + HGOTO_DONE(FAIL); + + /* Check if we haven't acquired the lock */ + if (0 == dlftt) { + /* Attempt to acquire the lock */ + if (H5_UNLIKELY(H5TS_rwlock_trywrlock(&H5TS_api_info_p.api_lock, acquired) < 0)) + HGOTO_DONE(FAIL); + } + else + *acquired = true; + + /* If acquired, increment the DLFTT count by 'lock_count' */ + if (*acquired) + /* Set the DLFTT value */ + if (H5_UNLIKELY(H5TS__set_dlftt(dlftt + lock_count) < 0)) + HGOTO_DONE(FAIL); +#endif done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -209,6 +303,7 @@ H5TS__api_mutex_acquire(unsigned lock_count, bool *acquired) * *-------------------------------------------------------------------------- */ +#ifdef H5_HAVE_THREADSAFE herr_t H5TS_api_lock(void) { @@ -234,6 +329,40 @@ H5TS_api_lock(void) done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS_api_lock() */ +#else +#ifdef H5_HAVE_CONCURRENCY +herr_t +H5TS_api_lock(unsigned *dlftt) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Initialize the thread-safety code, once */ + if (H5_UNLIKELY(!H5_INIT_GLOBAL)) + if (H5_UNLIKELY(H5TS_once(&H5TS_first_init_s, H5TS_ONCE_INIT_FUNC) < 0)) + HGOTO_DONE(FAIL); + + /* Increment the attempt lock count */ + H5TS_atomic_fetch_add_uint(&H5TS_api_info_p.attempt_lock_count, 1); + + /* Query the DLFTT value */ + if (H5_UNLIKELY(H5TS__get_dlftt(dlftt) < 0)) + HGOTO_DONE(FAIL); + + /* Don't acquire the API lock if locking is disabled */ + if (0 == *dlftt) + /* Acquire the library's API lock */ + if (H5_UNLIKELY(H5TS_rwlock_wrlock(&H5TS_api_info_p.api_lock) < 0)) + HGOTO_DONE(FAIL); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_api_lock() */ +#else +#error "Unknown multithreading mode" +#endif +#endif /*-------------------------------------------------------------------------- * Function: H5TS__api_mutex_release @@ -253,6 +382,7 @@ H5TS__api_mutex_release(unsigned *lock_count) FUNC_ENTER_PACKAGE_NAMECHECK_ONLY +#ifdef H5_HAVE_THREADSAFE /* Return the current lock count */ *lock_count = H5TS_api_info_p.lock_count; @@ -263,6 +393,19 @@ H5TS__api_mutex_release(unsigned *lock_count) for (unsigned u = 0; u < *lock_count; u++) if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.api_mutex) < 0)) HGOTO_DONE(FAIL); +#else /* H5_HAVE_CONCURRENCY */ + /* Query the DLFTT value */ + if (H5_UNLIKELY(H5TS__get_dlftt(lock_count) < 0)) + HGOTO_DONE(FAIL); + + /* Reset the DLFTT value */ + if (H5_UNLIKELY(H5TS__set_dlftt(0) < 0)) + HGOTO_DONE(FAIL); + + /* Release the library's API lock */ + if (H5_UNLIKELY(H5TS_rwlock_wrunlock(&H5TS_api_info_p.api_lock) < 0)) + HGOTO_DONE(FAIL); +#endif done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -286,12 +429,18 @@ H5TS_api_unlock(void) FUNC_ENTER_NOAPI_NAMECHECK_ONLY +#ifdef H5_HAVE_THREADSAFE /* Decrement the lock count for this thread */ H5TS_api_info_p.lock_count--; /* Release the library's API lock */ if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_api_info_p.api_mutex) < 0)) HGOTO_DONE(FAIL); +#else /* H5_HAVE_CONCURRENCY */ + /* Release the library's API lock */ + if (H5_UNLIKELY(H5TS_rwlock_wrunlock(&H5TS_api_info_p.api_lock) < 0)) + HGOTO_DONE(FAIL); +#endif done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) @@ -506,6 +655,136 @@ H5TS_get_err_stack(void) FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* H5TS_get_err_stack() */ +#ifdef H5_HAVE_CONCURRENCY +/*-------------------------------------------------------------------------- + * Function: H5TS__get_dlftt + * + * Purpose: Retrieve the DLFTT value for this thread. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +static herr_t +H5TS__get_dlftt(unsigned *dlftt) +{ + H5TS_tinfo_node_t *tinfo_node; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(NULL == tinfo_node)) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(FAIL); + + /* Get value */ + *dlftt = tinfo_node->info.dlftt; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__get_dlftt() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__set_dlftt + * + * Purpose: Set the DLFTT value for this thread. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +static herr_t +H5TS__set_dlftt(unsigned dlftt) +{ + H5TS_tinfo_node_t *tinfo_node; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(NULL == tinfo_node)) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(FAIL); + + /* Set value */ + tinfo_node->info.dlftt = dlftt; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__set_dlftt() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__inc_dlftt + * + * Purpose: Increment the DLFTT value for this thread. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +static herr_t +H5TS__inc_dlftt(void) +{ + H5TS_tinfo_node_t *tinfo_node; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(NULL == tinfo_node)) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(FAIL); + + /* Increment value */ + tinfo_node->info.dlftt++; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__inc_dlftt() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__dec_dlftt + * + * Purpose: Decrement the DLFTT value for this thread. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +static herr_t +H5TS__dec_dlftt(void) +{ + H5TS_tinfo_node_t *tinfo_node; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + /* Check if info for thread has been created */ + if (H5_UNLIKELY(H5TS_key_get_value(H5TS_thrd_info_key_g, (void **)&tinfo_node) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(NULL == tinfo_node)) + /* Create thread info for this thread */ + if (H5_UNLIKELY(NULL == (tinfo_node = H5TS__tinfo_create()))) + HGOTO_DONE(FAIL); + + /* Decrement value */ + tinfo_node->info.dlftt--; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* H5TS__dec_dlftt() */ +#endif /* H5_HAVE_CONCURRENCY */ + /*-------------------------------------------------------------------------- * Function: H5TS__tinfo_destroy * @@ -528,11 +807,14 @@ H5TS__tinfo_destroy(void *_tinfo_node) if (tinfo_node) { H5TS_mutex_lock(&H5TS_tinfo_mtx_s); + /* Add thread info node to the free list */ tinfo_node->next = H5TS_tinfo_next_free_s; H5TS_tinfo_next_free_s = tinfo_node; + /* Release resources held by error records in thread-local error stack */ H5E__destroy_stack(&tinfo_node->info.err_stack); + H5TS_mutex_unlock(&H5TS_tinfo_mtx_s); } @@ -590,15 +872,16 @@ H5TS__tinfo_term(void) if (H5_UNLIKELY(H5TS_mutex_unlock(&H5TS_tinfo_mtx_s) < 0)) HGOTO_DONE(FAIL); + /* Release critical section / mutex for modifying the thread info globals */ + if (H5_UNLIKELY(H5TS_mutex_destroy(&H5TS_tinfo_mtx_s) < 0)) + HGOTO_DONE(FAIL); + /* Release key for thread-specific API contexts */ if (H5_UNLIKELY(H5TS_key_delete(H5TS_thrd_info_key_g) < 0)) HGOTO_DONE(FAIL); - /* Release critical section / mutex for modifying the thread info globals */ - if (H5_UNLIKELY(H5TS_mutex_destroy(&H5TS_tinfo_mtx_s) < 0)) - HGOTO_DONE(FAIL); done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS__tinfo_term() */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/src/H5TSmodule.h b/src/H5TSmodule.h index 71d0de45349..67648d0fdc3 100644 --- a/src/H5TSmodule.h +++ b/src/H5TSmodule.h @@ -24,6 +24,6 @@ #define H5TS_MODULE #define H5_MY_PKG H5TS #define H5_MY_PKG_ERR H5E_THREADSAFE -#define H5_MY_PKG_INIT YES +#define H5_MY_PKG_INIT NO #endif /* H5TSmodule_H */ diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index 47ab8cb7720..0b5ab28558c 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -43,19 +43,24 @@ /* Package Private Typedefs */ /****************************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /* Info for the global API lock */ typedef struct H5TS_api_info_t { +#ifdef H5_HAVE_THREADSAFE /* API lock */ H5TS_mutex_t api_mutex; /* Count of recursive API calls by the same thread */ unsigned lock_count; +#else /* H5_HAVE_CONCURRENCY */ + /* API lock */ + H5TS_rwlock_t api_lock; +#endif /* Count of # of attempts to acquire API lock */ H5TS_atomic_uint_t attempt_lock_count; } H5TS_api_info_t; -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #if H5TS_ENABLE_REC_RWLOCK_STATS /****************************************************************************** @@ -214,25 +219,25 @@ typedef struct H5TS_rec_rwlock_t { /* Package Private Variables */ /*****************************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /* API threadsafety info */ extern H5TS_api_info_t H5TS_api_info_p; /* Per-thread info */ extern H5TS_key_t H5TS_thrd_info_key_g; -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /******************************/ /* Package Private Prototypes */ /******************************/ -#ifdef H5_HAVE_THREADSAFE -H5_DLL herr_t H5TS__init(void); +#ifdef H5_HAVE_THREADSAFE_API +H5_DLL herr_t H5TS__init_package(void); H5_DLL herr_t H5TS__api_mutex_acquire(unsigned lock_count, bool *acquired); H5_DLL herr_t H5TS__api_mutex_release(unsigned *lock_count); H5_DLL herr_t H5TS__tinfo_init(void); H5_DLL void H5TS__tinfo_destroy(void *tinfo_node); H5_DLL herr_t H5TS__tinfo_term(void); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Recursive R/W lock related function declarations */ H5_DLL herr_t H5TS__rec_rwlock_init(H5TS_rec_rwlock_t *lock); @@ -243,7 +248,7 @@ H5_DLL herr_t H5TS__rec_rwlock_wrunlock(H5TS_rec_rwlock_t *lock); H5_DLL herr_t H5TS__rec_rwlock_destroy(H5TS_rec_rwlock_t *lock); /* 'once' callbacks */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #ifdef H5_HAVE_C11_THREADS H5_DLL void H5TS__c11_first_thread_init(void); #else @@ -253,7 +258,7 @@ H5_DLL BOOL CALLBACK H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parame H5_DLL void H5TS__pthread_first_thread_init(void); #endif /* H5_HAVE_WIN_THREADS */ #endif -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #if H5TS_ENABLE_REC_RWLOCK_STATS H5_DLL herr_t H5TS__rec_rwlock_get_stats(H5TS_rec_rwlock_t *lock, H5TS_rec_rwlock_stats_t *stats); diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index 1e62a4ec9af..f36f9a02dde 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -23,10 +23,10 @@ #ifdef H5_HAVE_THREADS -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /* Include package's public headers */ #include "H5TSdevelop.h" -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /**************************/ /* Library Private Macros */ @@ -178,14 +178,40 @@ typedef CONDITION_VARIABLE H5TS_cond_t; typedef INIT_ONCE H5TS_once_t; typedef PINIT_ONCE_FN H5TS_once_init_func_t; #else + +/* Non-recursive readers/writer lock */ +#if defined(__MACH__) +/* + * Emulated pthread rwlock for MacOS + * + * Can't use pthread rwlock on MacOS due to: "The results [of calling + * pthread_rwlock_wrlock] are undefined if the calling thread already + * holds the lock at the time the call is made." + * but the pthread standard says: "If a deadlock condition occurs or the + * calling thread already owns the read-write lock for writing or reading, + * the call shall either deadlock or return [EDEADLK]." + * + * The net result of this is that the current version of MacOS (v15.x) allows + * the same thread to recursively acquire a write lock, violating the pthread + * guarantee of deadlocking or failing. + * + */ +typedef struct H5TS_rwlock_t { + pthread_mutex_t mutex; + pthread_cond_t read_cv, write_cv; + unsigned readers, writers, read_waiters, write_waiters; +} H5TS_rwlock_t; +#else +typedef pthread_rwlock_t H5TS_rwlock_t; +#endif + typedef pthread_t H5TS_thread_t; typedef void *(*H5TS_thread_start_func_t)(void *); -typedef void *H5TS_thread_ret_t; -typedef pthread_key_t H5TS_key_t; -typedef pthread_mutex_t H5TS_CAPABILITY("mutex") H5TS_mutex_t; -typedef pthread_rwlock_t H5TS_rwlock_t; -typedef pthread_cond_t H5TS_cond_t; -typedef pthread_once_t H5TS_once_t; +typedef void *H5TS_thread_ret_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_once_t H5TS_once_t; typedef void (*H5TS_once_init_func_t)(void); #endif #endif @@ -273,20 +299,30 @@ typedef atomic_flag H5TS_spinlock_t; /* Library-private Function Prototypes */ /***************************************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /* Library/thread init/term operations */ H5_DLL void H5TS_term_package(void); H5_DLL int H5TS_top_term_package(void); +/* Prepare for / restore after user callback */ +#ifdef H5_HAVE_CONCURRENCY +H5_DLL herr_t H5TS_user_cb_prepare(void); +H5_DLL herr_t H5TS_user_cb_restore(void); +#endif /* H5_HAVE_CONCURRENCY */ + /* API locking */ +#ifdef H5_HAVE_THREADSAFE H5_DLL herr_t H5TS_api_lock(void); +#else /* H5_HAVE_CONCURRENCY */ +H5_DLL herr_t H5TS_api_lock(unsigned *dlftt); +#endif H5_DLL herr_t H5TS_api_unlock(void); /* Retrieve per-thread info */ H5_DLL herr_t H5TS_thread_id(uint64_t *id); H5_DLL struct H5CX_node_t **H5TS_get_api_ctx_ptr(void); H5_DLL struct H5E_stack_t *H5TS_get_err_stack(void); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* 'Once' operationss */ H5_DLL herr_t H5TS_once(H5TS_once_t *once, H5TS_once_init_func_t func); @@ -304,6 +340,8 @@ H5_DLL herr_t H5TS_rwlock_init(H5TS_rwlock_t *lock); static inline herr_t H5TS_rwlock_rdlock(H5TS_rwlock_t *lock); static inline herr_t H5TS_rwlock_rdunlock(H5TS_rwlock_t *lock); static inline herr_t H5TS_rwlock_wrlock(H5TS_rwlock_t *lock); +static inline herr_t H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired) + H5TS_TRY_ACQUIRE(SUCCEED, *lock); static inline herr_t H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock); #endif H5_DLL herr_t H5TS_rwlock_destroy(H5TS_rwlock_t *lock); @@ -378,18 +416,18 @@ static inline herr_t H5TS_semaphore_wait(H5TS_semaphore_t *sem); H5_DLL herr_t H5TS_semaphore_destroy(H5TS_semaphore_t *sem); /* Headers with inlined routines */ +#ifndef __cplusplus #include "H5TScond.h" #include "H5TSmutex.h" #include "H5TSkey.h" -#if !defined(__cplusplus) -#if !defined(H5_HAVE_STDATOMIC_H) +#ifndef H5_HAVE_STDATOMIC_H #include "H5TSatomic.h" #endif /* H5_HAVE_STDATOMIC_H */ #include "H5TSbarrier.h" #include "H5TSrwlock.h" #include "H5TSsemaphore.h" #include "H5TSpool.h" -#endif +#endif /* __cplusplus */ #endif /* H5_HAVE_THREADS */ diff --git a/src/H5TSpthread.c b/src/H5TSpthread.c index 56715654694..f9de512218b 100644 --- a/src/H5TSpthread.c +++ b/src/H5TSpthread.c @@ -58,7 +58,7 @@ /* Local Variables */ /*******************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /*-------------------------------------------------------------------------- * Function: H5TS__pthread_first_thread_init * @@ -76,10 +76,10 @@ H5TS__pthread_first_thread_init(void) FUNC_ENTER_PACKAGE_NAMECHECK_ONLY /* Initialize H5TS package */ - H5TS__init(); + H5TS__init_package(); FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY } /* end H5TS__pthread_first_thread_init() */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #endif /* H5_HAVE_PTHREAD_H */ diff --git a/src/H5TSrwlock.c b/src/H5TSrwlock.c index 70b7c27687f..8f9e73ca8df 100644 --- a/src/H5TSrwlock.c +++ b/src/H5TSrwlock.c @@ -178,6 +178,89 @@ H5TS_rwlock_destroy(H5TS_rwlock_t *lock) /* Destroy synchronization primitives */ /* SRWLOCKs don't have to be destroyed */ +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_rwlock_destroy() */ +#elif defined(__MACH__) +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_init + * + * Purpose: Initialize a H5TS_rwlock_t (does not allocate it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_rwlock_init(H5TS_rwlock_t *lock) +{ + pthread_mutexattr_t _attr; + pthread_mutexattr_t *attr = NULL; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Create mutex attribute */ + if (H5_UNLIKELY(pthread_mutexattr_init(&_attr))) + HGOTO_DONE(FAIL); + attr = &_attr; + + /* Use "normal" mutex, without error checking */ + if (H5_UNLIKELY(pthread_mutexattr_settype(attr, PTHREAD_MUTEX_NORMAL))) + HGOTO_DONE(FAIL); + + /* Initialize the mutex */ + if (H5_UNLIKELY(pthread_mutex_init(&lock->mutex, attr))) + HGOTO_DONE(FAIL); + + /* Initialize the condition variables */ + if (H5_UNLIKELY(pthread_cond_init(&lock->read_cv, NULL))) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(pthread_cond_init(&lock->write_cv, NULL))) + HGOTO_DONE(FAIL); + + /* Initialize scalar fields */ + lock->readers = 0; + lock->writers = 0; + lock->read_waiters = 0; + lock->write_waiters = 0; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS_rwlock_init() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_destroy + * + * Purpose: Destroy a H5TS_rwlock_t (does not free it) + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_rwlock_destroy(H5TS_rwlock_t *lock) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Destroy synchronization primitives */ + if (H5_UNLIKELY(pthread_mutex_destroy(&lock->mutex))) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(pthread_cond_destroy(&lock->read_cv))) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(pthread_cond_destroy(&lock->write_cv))) + HGOTO_DONE(FAIL); + done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) } /* end H5TS_rwlock_destroy() */ diff --git a/src/H5TSrwlock.h b/src/H5TSrwlock.h index 951f4569b3d..c05fb5b7e11 100644 --- a/src/H5TSrwlock.h +++ b/src/H5TSrwlock.h @@ -184,6 +184,52 @@ H5TS_rwlock_wrlock(H5TS_rwlock_t *lock) return SUCCEED; } /* end H5TS_rwlock_wrlock() */ +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_trywrlock + * + * Purpose: Attempt to acquire a write lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired) +{ + int ret; + + /* Check argument */ + if (H5_UNLIKELY(NULL == lock || NULL == acquired)) + return FAIL; + + /* Acquire the lock's mutex */ + if (H5_UNLIKELY(thrd_error == (ret = mtx_lock(&lock->mutex)))) + return FAIL; + if (thrd_busy == ret) { + /* We did not acquire the lock */ + *acquired = false; + return SUCCEED; + } + + /* Check for readers or other writers */ + if (lock->readers || lock->writers) + /* We did not acquire the lock */ + *acquired = false; + else { + /* Increment # of writers */ + lock->writers++; + + /* We acquired the lock */ + *acquired = true; + } + + /* Release mutex */ + if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success)) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_trywrlock() */ + /*------------------------------------------------------------------------- * Function: H5TS_rwlock_wrunlock * @@ -292,6 +338,30 @@ H5TS_rwlock_wrlock(H5TS_rwlock_t *lock) return SUCCEED; } /* end H5TS_rwlock_wrlock() */ +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_trywrlock + * + * Purpose: Attempt to acquire a write lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired) +{ + /* Check argument */ + if (H5_UNLIKELY(NULL == lock || NULL == acquired)) + return FAIL; + + if (TryAcquireSRWLockExclusive(lock)) + *acquired = true; + else + *acquired = false; + + return SUCCEED; +} /* end H5TS_rwlock_trywrlock() */ + /*------------------------------------------------------------------------- * Function: H5TS_rwlock_wrunlock * @@ -313,6 +383,228 @@ H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock) return SUCCEED; } /* end H5TS_rwlock_wrunlock() */ +#elif defined(__MACH__) +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_rdlock + * + * Purpose: Acquire a read lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_rdlock(H5TS_rwlock_t *lock) +{ + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) + return FAIL; + + /* Acquire the lock's mutex */ + if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex))) + return FAIL; + + /* Check for writers */ + if (lock->writers || lock->write_waiters) { + /* Read waiting */ + lock->read_waiters++; + + /* Wait for writers */ + do { + if (H5_UNLIKELY(pthread_cond_wait(&lock->read_cv, &lock->mutex))) { + pthread_mutex_unlock(&lock->mutex); + return FAIL; + } + } while (lock->writers || lock->write_waiters); + + /* Read not waiting any longer */ + lock->read_waiters--; + } + + /* Increment # of readers */ + lock->readers++; + + /* Release mutex */ + if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_rdlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_rdunlock + * + * Purpose: Release a read lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_rdunlock(H5TS_rwlock_t *lock) +{ + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) + return FAIL; + + /* Acquire the lock's mutex */ + if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex))) + return FAIL; + + /* Decrement # of readers */ + lock->readers--; + + /* Check for waiting writers when last readers */ + if (lock->write_waiters && 0 == lock->readers) + if (H5_UNLIKELY(pthread_cond_signal(&lock->write_cv))) { + pthread_mutex_unlock(&lock->mutex); + return FAIL; + } + + /* Release mutex */ + if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_rdunlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_wrlock + * + * Purpose: Acquire a write lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_wrlock(H5TS_rwlock_t *lock) +{ + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) + return FAIL; + + /* Acquire the lock's mutex */ + if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex))) + return FAIL; + + /* Check for readers or other writers */ + if (lock->readers || lock->writers) { + /* Write waiting */ + lock->write_waiters++; + + /* Wait for mutex */ + do { + if (H5_UNLIKELY(pthread_cond_wait(&lock->write_cv, &lock->mutex))) { + pthread_mutex_unlock(&lock->mutex); + return FAIL; + } + } while (lock->readers || lock->writers); + + /* Write not waiting any longer */ + lock->write_waiters--; + } + + /* Increment # of writers */ + lock->writers++; + + /* Release mutex */ + if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_wrlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_trywrlock + * + * Purpose: Attempt to acquire a write lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired) +{ + int rc; + + /* Check argument */ + if (H5_UNLIKELY(NULL == lock || NULL == acquired)) + return FAIL; + + /* Acquire the lock's mutex */ + rc = pthread_mutex_trylock(&lock->mutex); + if (EBUSY == rc) { + /* We did not acquire the lock */ + *acquired = false; + return SUCCEED; + } + else if (0 != rc) + return FAIL; + + /* Check for readers or other writers */ + if (lock->readers || lock->writers) + /* We did not acquire the lock */ + *acquired = false; + else { + /* Increment # of writers */ + lock->writers++; + + /* We acquired the lock */ + *acquired = true; + } + + /* Release mutex */ + if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_trywrlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_wrunlock + * + * Purpose: Release a write lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +static inline herr_t +H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock) +{ + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) + return FAIL; + + /* Acquire the lock's mutex */ + if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex))) + return FAIL; + + /* Decrement # of writers */ + lock->writers--; + + /* Check for waiting writers */ + if (lock->write_waiters) { + if (H5_UNLIKELY(pthread_cond_signal(&lock->write_cv))) { + pthread_mutex_unlock(&lock->mutex); + return FAIL; + } + } + else if (lock->read_waiters) + if (H5_UNLIKELY(pthread_cond_broadcast(&lock->read_cv))) { + pthread_mutex_unlock(&lock->mutex); + return FAIL; + } + + /* Release mutex */ + if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_wrunlock() */ + #else /*------------------------------------------------------------------------- * Function: H5TS_rwlock_rdlock @@ -380,6 +672,35 @@ H5TS_rwlock_wrlock(H5TS_rwlock_t *lock) return SUCCEED; } /* end H5TS_rwlock_wrlock() */ +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_trywrlock + * + * Purpose: Attempt to acquire a write lock + * + * Return: Non-negative on success / Negative on failure + * + *------------------------------------------------------------------------- + */ +herr_t +H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired) +{ + int ret; + + /* Check argument */ + if (H5_UNLIKELY(NULL == lock || NULL == acquired)) + return FAIL; + + ret = pthread_rwlock_trywrlock(lock); + if (EBUSY == ret) + *acquired = false; /* We did not acquire the lock */ + else if (H5_UNLIKELY(0 != ret)) + return FAIL; + else + *acquired = true; /* We acquired the lock */ + + return SUCCEED; +} /* end H5TS_rwlock_trywrlock() */ + /*------------------------------------------------------------------------- * Function: H5TS_rwlock_rdunlock * diff --git a/src/H5TSwin.c b/src/H5TSwin.c index b82f364bdd2..59f5db42d57 100644 --- a/src/H5TSwin.c +++ b/src/H5TSwin.c @@ -64,7 +64,7 @@ static herr_t H5TS__win32_thread_exit(void); /* Local Variables */ /*******************/ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API /*-------------------------------------------------------------------------- * Function: H5TS__win32_process_enter * @@ -82,7 +82,7 @@ H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex) FUNC_ENTER_PACKAGE_NAMECHECK_ONLY /* Initialize H5TS package */ - if (H5_UNLIKELY(H5TS__init() < 0)) + if (H5_UNLIKELY(H5TS__init_package() < 0)) HGOTO_DONE(FALSE); done: @@ -206,6 +206,6 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved) return fOkay; } #endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #endif /* H5_HAVE_WIN_THREADS */ diff --git a/src/H5Tconv_bitfield.c b/src/H5Tconv_bitfield.c index 8b46c75c5c5..cc2ad9eb483 100644 --- a/src/H5Tconv_bitfield.c +++ b/src/H5Tconv_bitfield.c @@ -164,10 +164,18 @@ H5T__conv_b_b(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ if (src->shared->u.atomic.prec > dst->shared->u.atomic.prec) { /*overflow*/ if (conv_ctx->u.conv.cb_struct.func) { /*If user's exception handler is present, use it*/ - H5T__reverse_order(src_rev, s, src); /*reverse order first*/ - 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Reverse order first */ + H5T__reverse_order(src_rev, s, src); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } /* end if */ if (except_ret == H5T_CONV_UNHANDLED) { diff --git a/src/H5Tconv_complex.c b/src/H5Tconv_complex.c index cdd2402cb0f..9b4197c0f87 100644 --- a/src/H5Tconv_complex.c +++ b/src/H5Tconv_complex.c @@ -22,8 +22,9 @@ /***********/ /* Headers */ /***********/ -#include "H5Eprivate.h" -#include "H5Tconv.h" +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Tconv.h" /* Datatype conversions */ #include "H5Tconv_macros.h" #include "H5Tconv_complex.h" #include "H5Tconv_integer.h" @@ -280,7 +281,7 @@ H5T__conv_complex_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ct if (conv_ctx->u.conv.cb_struct.func) { H5T_conv_except_t except_type; /* type of conversion exception that occurred */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); /* @@ -308,9 +309,14 @@ H5T__conv_complex_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ct except_type = H5T_CONV_EXCEPT_NAN; } - except_ret = (conv_ctx->u.conv.cb_struct.func)(except_type, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + except_type, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, src_rev, + d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -619,12 +625,17 @@ H5T__conv_complex_part(const H5T_t *src_p, const H5T_t *dst_p, uint8_t *s, uint8 * original byte order. */ if (conv_ctx->u.conv.cb_struct.func) { /* If user's exception handler is present, use it */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, src_rev, - d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, + src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -711,12 +722,17 @@ H5T__conv_complex_part(const H5T_t *src_p, const H5T_t *dst_p, uint8_t *s, uint8 * hand it is in the original byte order. */ if (conv_ctx->u.conv.cb_struct.func) { /* If user's exception handler is present, use it */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, - src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -1075,7 +1091,7 @@ H5T__conv_complex_f_matched(const H5T_t *src_p, const H5T_t *dst_p, const H5T_co if (conv_ctx->u.conv.cb_struct.func) { H5T_conv_except_t except_type; /* type of conversion exception that occurred */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); if (specval_type == H5T_CONV_FLOAT_SPECVAL_POSINF) @@ -1085,9 +1101,14 @@ H5T__conv_complex_f_matched(const H5T_t *src_p, const H5T_t *dst_p, const H5T_co else except_type = H5T_CONV_EXCEPT_NAN; - except_ret = (conv_ctx->u.conv.cb_struct.func)(except_type, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + except_type, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, src_rev, + d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { diff --git a/src/H5Tconv_enum.c b/src/H5Tconv_enum.c index 744f7b9920c..6460f6a8291 100644 --- a/src/H5Tconv_enum.c +++ b/src/H5Tconv_enum.c @@ -401,11 +401,19 @@ H5T__conv_enum(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T if (n < 0 || (unsigned)n >= priv->length || priv->src2dst[n] < 0) { /*overflow*/ except_ret = H5T_CONV_UNHANDLED; - /*If user's exception handler is present, use it*/ - if (conv_ctx->u.conv.cb_struct.func) - 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 user's exception handler is present, use it*/ + if (conv_ctx->u.conv.cb_struct.func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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); + } + H5_AFTER_USER_CB(FAIL) + } if (except_ret == H5T_CONV_UNHANDLED) memset(d, 0xff, dst_sh->size); @@ -441,11 +449,19 @@ H5T__conv_enum(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T } /* end while */ if (lt >= rt) { except_ret = H5T_CONV_UNHANDLED; - /*If user's exception handler is present, use it*/ - if (conv_ctx->u.conv.cb_struct.func) - 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 user's exception handler is present, use it*/ + if (conv_ctx->u.conv.cb_struct.func) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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); + } + H5_AFTER_USER_CB(FAIL) + } if (except_ret == H5T_CONV_UNHANDLED) memset(d, 0xff, dst_sh->size); diff --git a/src/H5Tconv_float.c b/src/H5Tconv_float.c index b7231657281..e5767bb3f62 100644 --- a/src/H5Tconv_float.c +++ b/src/H5Tconv_float.c @@ -82,10 +82,8 @@ H5T__conv_f_f(const H5T_t *src_p, const H5T_t *dst_p, H5T_cdata_t *cdata, const HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); if (NULL == conv_ctx) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid datatype conversion context pointer"); - if (H5T__conv_f_f_loop(src_p, dst_p, conv_ctx, nelmts, buf_stride, buf) < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "unable to convert data values"); - break; default: @@ -294,7 +292,7 @@ H5T__conv_f_f_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t if (conv_ctx->u.conv.cb_struct.func) { H5T_conv_except_t except_type; /* type of conversion exception that occurred */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); if (specval_type == H5T_CONV_FLOAT_SPECVAL_POSINF) @@ -304,9 +302,14 @@ H5T__conv_f_f_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t else except_type = H5T_CONV_EXCEPT_NAN; - except_ret = (conv_ctx->u.conv.cb_struct.func)(except_type, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + except_type, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, src_rev, + d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -437,12 +440,17 @@ H5T__conv_f_f_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t * original byte order. */ if (conv_ctx->u.conv.cb_struct.func) { /* If user's exception handler is present, use it */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, - src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -529,12 +537,18 @@ H5T__conv_f_f_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t * hand it is in the original byte order. */ if (conv_ctx->u.conv.cb_struct.func) { /* If user's exception handler is present, use it */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, - src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -762,7 +776,6 @@ H5T__conv_f_i(const H5T_t *src_p, const H5T_t *dst_p, H5T_cdata_t *cdata, const if (H5T__conv_f_i_loop(src_p, dst_p, conv_ctx, nelmts, buf_stride, buf) < 0) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "unable to convert data values"); - break; default: @@ -962,7 +975,7 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t if (conv_ctx->u.conv.cb_struct.func) { H5T_conv_except_t except_type; /* type of conversion exception that occurred */ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); if (specval_type == H5T_CONV_FLOAT_SPECVAL_POSINF) @@ -972,9 +985,14 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t else except_type = H5T_CONV_EXCEPT_NAN; - except_ret = (conv_ctx->u.conv.cb_struct.func)(except_type, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + except_type, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, src_rev, + d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -1088,12 +1106,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t if (sign) { /* source is negative */ /* If user's exception handler is present, use it */ if (conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, - src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) if (except_ret == H5T_CONV_HANDLED) { /* No need to reverse the order of destination because user handles it */ @@ -1108,12 +1132,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t if (new_msb_pos >= (ssize_t)dst_atomic.prec) { /* overflow - if user's exception handler is present, use it */ if (conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) @@ -1129,12 +1159,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t else { /* If user's exception handler is present, use it */ if (truncated && conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - except_ret = (conv_ctx->u.conv.cb_struct.func)( - H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, + conv_ctx->u.conv.dst_type_id, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -1157,12 +1193,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t if ((new_msb_pos >= 0) && ((size_t)new_msb_pos < dst_atomic.prec - 1)) { /* If user's exception handler is present, use it */ if (truncated && conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - except_ret = (conv_ctx->u.conv.cb_struct.func)( - H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, + conv_ctx->u.conv.dst_type_id, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { /* If this case ignored by user handler */ @@ -1188,12 +1230,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t * If user's exception handler is present, use it */ if (conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) @@ -1211,12 +1259,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t if (new_msb_pos >= (ssize_t)dst_atomic.prec - 1) { /* overflow - if user's exception handler is present, use it */ if (conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) @@ -1232,12 +1286,18 @@ H5T__conv_f_i_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t else if (new_msb_pos < (ssize_t)dst_atomic.prec - 1) { /* If user's exception handler is present, use it */ if (truncated && conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - except_ret = (conv_ctx->u.conv.cb_struct.func)( - H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, - conv_ctx->u.conv.dst_type_id, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + except_ret = (conv_ctx->u.conv.cb_struct.func)( + H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, + conv_ctx->u.conv.dst_type_id, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { diff --git a/src/H5Tconv_integer.c b/src/H5Tconv_integer.c index b2af085c064..db61986c409 100644 --- a/src/H5Tconv_integer.c +++ b/src/H5Tconv_integer.c @@ -201,12 +201,18 @@ H5T__conv_i_i(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ /*overflow*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src); - 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, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -237,12 +243,18 @@ H5T__conv_i_i(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ /*overflow - source is negative*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src); - 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, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -265,12 +277,18 @@ H5T__conv_i_i(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ /*overflow - source is positive*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src); - 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, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) @@ -298,12 +316,18 @@ H5T__conv_i_i(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ /*overflow*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src); - 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, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -346,12 +370,18 @@ H5T__conv_i_i(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ /*overflow*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src); - 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, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -389,12 +419,18 @@ H5T__conv_i_i(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_ /*overflow*/ if (conv_ctx->u.conv.cb_struct .func) { /*If user's exception handler is present, use it*/ - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src); - 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, src_rev, d, - conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, + conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_UNHANDLED) { @@ -687,11 +723,17 @@ H5T__conv_i_f_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t * precision loss. Let user's handler deal with the case if it's present */ if (conv_ctx->u.conv.cb_struct.func) { - /* reverse source buffer order first */ + /* Reverse source buffer order first */ H5T__reverse_order(src_rev, s, src_p); - 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, - src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) } if (except_ret == H5T_CONV_HANDLED) { @@ -757,13 +799,19 @@ H5T__conv_i_f_loop(const H5T_t *src_p, const H5T_t *dst_p, const H5T_conv_ctx_t /* Check if the exponent is too big */ expo_max = (hsize_t)(pow(2.0, (double)dst_atomic.u.f.esize) - 1); - if (expo > expo_max) { /* overflows */ - if (conv_ctx->u.conv.cb_struct.func) { - /* user's exception handler. Reverse back source order */ + if (expo > expo_max) { /* overflows */ + if (conv_ctx->u.conv.cb_struct.func) { /* user's exception handler */ + /* Reverse back source order */ H5T__reverse_order(src_rev, s, src_p); - 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, - src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + 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, src_rev, d, conv_ctx->u.conv.cb_struct.user_data); + } + H5_AFTER_USER_CB(FAIL) if (except_ret == H5T_CONV_ABORT) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception"); diff --git a/src/H5Tconv_macros.h b/src/H5Tconv_macros.h index 843255e51cc..80a9369fc70 100644 --- a/src/H5Tconv_macros.h +++ b/src/H5Tconv_macros.h @@ -239,10 +239,16 @@ typedef struct H5T_conv_hw_t { */ #define H5T_CONV_Xx_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ + H5T_conv_ret_t except_ret; \ if (*(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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MAX); \ @@ -251,9 +257,14 @@ typedef struct H5T_conv_hw_t { /* 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MIN); \ @@ -279,9 +290,16 @@ typedef struct H5T_conv_hw_t { #define H5T_CONV_Ux_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ if (*(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MAX); \ @@ -310,9 +328,16 @@ typedef struct H5T_conv_hw_t { #define H5T_CONV_sU_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ if (*(S) < 0) { \ - 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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = 0; \ @@ -372,9 +397,16 @@ typedef struct H5T_conv_hw_t { /* Called if overflow is possible */ #define H5T_CONV_uS_CORE_1(S, D, ST, DT, D_MIN, D_MAX) \ if (*(S) > (DT)(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler */ \ *(D) = (DT)(D_MAX); \ @@ -434,10 +466,16 @@ typedef struct H5T_conv_hw_t { #define H5T_CONV_Su_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ + H5T_conv_ret_t except_ret; \ if (*(S) < 0) { \ - 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = 0; \ @@ -446,9 +484,14 @@ typedef struct H5T_conv_hw_t { /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ } \ else if (sizeof(ST) > sizeof(DT) && *(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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MAX); \ @@ -491,9 +534,16 @@ typedef struct H5T_conv_hw_t { { \ /* Assumes memory format of unsigned & signed integers is same */ \ if (*(S) < 0) { \ - 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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = 0; \ @@ -523,9 +573,16 @@ typedef struct H5T_conv_hw_t { { \ /* Assumes memory format of unsigned & signed integers is same */ \ if (*(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MAX); \ @@ -562,10 +619,16 @@ typedef struct H5T_conv_hw_t { */ #define H5T_CONV_Ff_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ + H5T_conv_ret_t except_ret; \ if (*(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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -574,9 +637,14 @@ typedef struct H5T_conv_hw_t { /* 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -673,9 +741,16 @@ typedef struct H5T_conv_hw_t { \ /* 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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(*(S)); \ @@ -709,10 +784,16 @@ typedef struct H5T_conv_hw_t { */ #define H5T_CONV_Fx_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ + H5T_conv_ret_t except_ret; \ 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MAX); \ @@ -721,9 +802,14 @@ typedef struct H5T_conv_hw_t { /* 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MIN); \ @@ -732,9 +818,14 @@ typedef struct H5T_conv_hw_t { /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ } \ else if (*(S) != (ST)((DT)(*(S)))) { \ - H5T_conv_ret_t except_ret = (conv_ctx->u.conv.cb_struct.func)( \ - H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, S, D, \ - conv_ctx->u.conv.cb_struct.user_data); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + except_ret = (conv_ctx->u.conv.cb_struct.func)( \ + H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, \ + conv_ctx->u.conv.dst_type_id, S, D, conv_ctx->u.conv.cb_struct.user_data); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(*(S)); \ @@ -768,10 +859,16 @@ typedef struct H5T_conv_hw_t { #define H5T_CONV_Xf_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ + H5T_conv_ret_t except_ret; \ 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -780,9 +877,14 @@ typedef struct H5T_conv_hw_t { /* 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -798,9 +900,14 @@ typedef struct H5T_conv_hw_t { \ /* 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(*(S)); \ @@ -988,14 +1095,24 @@ typedef struct H5T_conv_hw_t { * number. \ */ \ if (sr_over || si_over) { \ - 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ } \ else if (sr_under || si_under) { \ - 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); \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ } \ \ /* If user conversion exception function handled the exception, do nothing. \ @@ -1117,9 +1234,16 @@ typedef struct H5T_conv_hw_t { { \ H5T_CONV_##STYPE##_REALVAL(S); \ if ((sr_val) > (SBT)(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -1128,9 +1252,16 @@ typedef struct H5T_conv_hw_t { /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ } \ else if ((sr_val) < (SBT)(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -1196,9 +1327,16 @@ typedef struct H5T_conv_hw_t { #define H5T_CONV_Fz_CORE(STYPE, DTYPE, S, D, ST, DT, D_MIN, D_MAX) \ { \ if (*(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -1207,9 +1345,16 @@ typedef struct H5T_conv_hw_t { /* 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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ 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); \ @@ -1285,9 +1430,16 @@ typedef struct H5T_conv_hw_t { \ /* 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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ H5T_CONV_CAST_Z(xZ, STYPE, DTYPE, S, -, -, D, ST, DT); \ @@ -1316,9 +1468,16 @@ typedef struct H5T_conv_hw_t { { \ H5T_CONV_##STYPE##_REALVAL(S); /* Extract "real" part of complex number */ \ if ((sr_val) > (SBT)(D_MAX) || (sprec < dprec && (sr_val) == (SBT)(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MAX); \ @@ -1327,9 +1486,16 @@ typedef struct H5T_conv_hw_t { /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ } \ else if ((sr_val) < (SBT)(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); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + 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); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)(D_MIN); \ @@ -1338,9 +1504,16 @@ typedef struct H5T_conv_hw_t { /* if(except_ret==H5T_CONV_HANDLED): Fall through, user handled it */ \ } \ else if ((sr_val) != (SBT)((DT)((sr_val)))) { \ - H5T_conv_ret_t except_ret = (conv_ctx->u.conv.cb_struct.func)( \ - H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, conv_ctx->u.conv.dst_type_id, S, D, \ - conv_ctx->u.conv.cb_struct.user_data); \ + H5T_conv_ret_t except_ret; \ + \ + /* Prepare & restore library for user callback */ \ + H5_BEFORE_USER_CB(FAIL) \ + { \ + except_ret = (conv_ctx->u.conv.cb_struct.func)( \ + H5T_CONV_EXCEPT_TRUNCATE, conv_ctx->u.conv.src_type_id, \ + conv_ctx->u.conv.dst_type_id, S, D, conv_ctx->u.conv.cb_struct.user_data); \ + } \ + H5_AFTER_USER_CB(FAIL) \ if (except_ret == H5T_CONV_UNHANDLED) \ /* Let compiler convert if case is ignored by user handler*/ \ *(D) = (DT)((sr_val)); \ diff --git a/src/H5Tvlen.c b/src/H5Tvlen.c index f98d9287968..fc0ff4b18a8 100644 --- a/src/H5Tvlen.c +++ b/src/H5Tvlen.c @@ -500,7 +500,13 @@ H5T__vlen_mem_seq_write(H5VL_object_t H5_ATTR_UNUSED *file, const H5T_vlen_alloc /* Use the user's memory allocation routine if one is defined */ if (vl_alloc_info->alloc_func != NULL) { - if (NULL == (vl.p = (vl_alloc_info->alloc_func)(len, vl_alloc_info->alloc_info))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + vl.p = (vl_alloc_info->alloc_func)(len, vl_alloc_info->alloc_info); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == vl.p) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "application memory allocation routine failed for VL data"); } /* end if */ @@ -672,8 +678,13 @@ H5T__vlen_mem_str_write(H5VL_object_t H5_ATTR_UNUSED *file, const H5T_vlen_alloc /* Use the user's memory allocation routine if one is defined */ if (vl_alloc_info->alloc_func != NULL) { - if (NULL == - (t = (char *)(vl_alloc_info->alloc_func)((seq_len + 1) * base_size, vl_alloc_info->alloc_info))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + t = (vl_alloc_info->alloc_func)((seq_len + 1) * base_size, vl_alloc_info->alloc_info); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == t) HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "application memory allocation routine failed for VL data"); } /* end if */ diff --git a/src/H5UC.c b/src/H5UC.c index cab195eb6c0..212b7fe117f 100644 --- a/src/H5UC.c +++ b/src/H5UC.c @@ -20,7 +20,8 @@ * */ -#include "H5Eprivate.h" /* Error handling */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free lists */ #include "H5UCprivate.h" /* Reference-counted buffers */ diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index 830a61fc945..71ad2035565 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -233,8 +233,16 @@ H5VLinitialize(hid_t connector_id, hid_t vipl_id) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID"); /* Invoke class' callback, if there is one */ - if (connector->cls->initialize && connector->cls->initialize(vipl_id) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not initialize"); + if (connector->cls->initialize) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = connector->cls->initialize(vipl_id); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not initialize"); + } done: FUNC_LEAVE_API_NOINIT(ret_value) @@ -263,8 +271,16 @@ H5VLterminate(hid_t connector_id) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID"); /* Invoke class' callback, if there is one */ - if (connector->cls->terminate && connector->cls->terminate() < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not terminate cleanly"); + if (connector->cls->terminate) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = connector->cls->terminate(); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not terminate cleanly"); + } done: FUNC_LEAVE_API_NOINIT(ret_value) @@ -399,7 +415,13 @@ H5VL_copy_connector_info(const H5VL_connector_t *connector, void **dst_info, con if (src_info) { /* Allow the connector to copy or do it ourselves */ if (connector->cls->info_cls.copy) { - if (NULL == (new_connector_info = (connector->cls->info_cls.copy)(src_info))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + new_connector_info = (connector->cls->info_cls.copy)(src_info); + } + H5_AFTER_USER_CB(FAIL) + if (NULL == new_connector_info) HGOTO_ERROR(H5E_VOL, H5E_CANTCOPY, FAIL, "connector info copy callback failed"); } /* end if */ else if (connector->cls->info_cls.size > 0) { @@ -492,7 +514,13 @@ H5VL_cmp_connector_info(const H5VL_connector_t *connector, int *cmp_value, const * memory buffers */ if (connector->cls->info_cls.cmp) { - if ((connector->cls->info_cls.cmp)(cmp_value, info1, info2) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (connector->cls->info_cls.cmp)(cmp_value, info1, info2); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCOMPARE, FAIL, "can't compare connector info"); } /* end if */ else { @@ -563,8 +591,14 @@ H5VL_free_connector_info(const H5VL_connector_t *connector, const void *info) if (info) { /* Allow the connector to free info or do it ourselves */ if (connector->cls->info_cls.free) { - /* Cast through uintptr_t to de-const memory */ - if ((connector->cls->info_cls.free)((void *)(uintptr_t)info) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Cast through uintptr_t to de-const memory */ + ret_value = (connector->cls->info_cls.free)((void *)(uintptr_t)info); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "connector info free request failed"); } else @@ -632,7 +666,13 @@ H5VLconnector_info_to_str(const void *info, hid_t connector_id, char **str) /* Allow the connector to serialize info */ if (connector->cls->info_cls.to_str) { - if ((connector->cls->info_cls.to_str)(info, str) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (connector->cls->info_cls.to_str)(info, str); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSERIALIZE, FAIL, "can't serialize connector info"); } /* end if */ else @@ -666,7 +706,13 @@ H5VL__connector_str_to_info(const char *str, H5VL_connector_t *connector, void * if (str) { /* Allow the connector to deserialize info */ if (connector->cls->info_cls.from_str) { - if ((connector->cls->info_cls.from_str)(str, info) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (connector->cls->info_cls.from_str)(str, info); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize connector info"); } /* end if */ else @@ -734,8 +780,14 @@ H5VLget_object(void *obj, hid_t connector_id) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a VOL connector ID"); /* Check for 'get_object' callback in connector */ - if (connector->cls->wrap_cls.get_object) - ret_value = (connector->cls->wrap_cls.get_object)(obj); + if (connector->cls->wrap_cls.get_object) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + ret_value = (connector->cls->wrap_cls.get_object)(obj); + } + H5_AFTER_USER_CB(NULL) + } else ret_value = obj; @@ -773,8 +825,14 @@ H5VLget_wrap_ctx(void *obj, hid_t connector_id, void **wrap_ctx /*out*/) /* Sanity check */ assert(connector->cls->wrap_cls.free_wrap_ctx); - /* Invoke cls's callback */ - if ((connector->cls->wrap_cls.get_wrap_ctx)(obj, wrap_ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Invoke connector's callback */ + ret_value = (connector->cls->wrap_cls.get_wrap_ctx)(obj, wrap_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "connector wrap context callback failed"); } /* end if */ else @@ -807,8 +865,14 @@ H5VL_wrap_object(const H5VL_class_t *cls, void *wrap_ctx, void *obj, H5I_type_t /* Only wrap object if there's a wrap context */ if (wrap_ctx) { - /* Ask the connector to wrap the object */ - if (NULL == (ret_value = (cls->wrap_cls.wrap_object)(obj, obj_type, wrap_ctx))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Ask the connector to wrap the object */ + ret_value = (cls->wrap_cls.wrap_object)(obj, obj_type, wrap_ctx); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "can't wrap object"); } /* end if */ else @@ -873,8 +937,14 @@ H5VL_unwrap_object(const H5VL_class_t *cls, void *obj) /* Only unwrap object if there's an unwrap callback */ if (cls->wrap_cls.wrap_object) { - /* Ask the connector to unwrap the object */ - if (NULL == (ret_value = (cls->wrap_cls.unwrap_object)(obj))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Ask the connector to unwrap the object */ + ret_value = (cls->wrap_cls.unwrap_object)(obj); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, NULL, "can't unwrap object"); } /* end if */ else @@ -939,10 +1009,17 @@ H5VLfree_wrap_ctx(void *wrap_ctx, hid_t connector_id) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a VOL connector ID"); /* Only free wrap context, if it's non-NULL */ - if (wrap_ctx) - /* Free the connector's object wrapping context */ - if ((connector->cls->wrap_cls.free_wrap_ctx)(wrap_ctx) < 0) + if (wrap_ctx) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Free the connector's object wrapping context */ + ret_value = (connector->cls->wrap_cls.free_wrap_ctx)(wrap_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "connector wrap context free request failed"); + } /* end if */ done: FUNC_LEAVE_API_NOINIT(ret_value) @@ -970,9 +1047,15 @@ H5VL__attr_create(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_cla if (NULL == cls->attr_cls.create) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'attr create' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->attr_cls.create)(obj, loc_params, name, type_id, space_id, acpl_id, - aapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->attr_cls.create)(obj, loc_params, name, type_id, space_id, acpl_id, aapl_id, + dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "attribute create failed"); done: @@ -1073,8 +1156,14 @@ H5VL__attr_open(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_class if (NULL == cls->attr_cls.open) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'attr open' method"); - /* Call the corresponding VOL open callback */ - if (NULL == (ret_value = (cls->attr_cls.open)(obj, loc_params, name, aapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL open callback */ + ret_value = (cls->attr_cls.open)(obj, loc_params, name, aapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "attribute open failed"); done: @@ -1172,8 +1261,14 @@ H5VL__attr_read(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, void *buf if (NULL == cls->attr_cls.read) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'attr read' method"); - /* Call the corresponding VOL callback */ - if ((cls->attr_cls.read)(obj, mem_type_id, buf, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->attr_cls.read)(obj, mem_type_id, buf, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "attribute read failed"); done: @@ -1269,8 +1364,14 @@ H5VL__attr_write(void *obj, const H5VL_class_t *cls, hid_t mem_type_id, const vo if (NULL == cls->attr_cls.write) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'attr write' method"); - /* Call the corresponding VOL callback */ - if ((cls->attr_cls.write)(obj, mem_type_id, buf, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->attr_cls.write)(obj, mem_type_id, buf, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "write failed"); done: @@ -1366,8 +1467,14 @@ H5VL__attr_get(void *obj, const H5VL_class_t *cls, H5VL_attr_get_args_t *args, h if (NULL == cls->attr_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'attr get' method"); - /* Call the corresponding VOL callback */ - if ((cls->attr_cls.get)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->attr_cls.get)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "attribute get failed"); done: @@ -1465,9 +1572,15 @@ H5VL__attr_specific(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_c if (NULL == cls->attr_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'attr specific' method"); - /* Call the corresponding VOL callback */ - /* (Must return value from callback, for iterators) */ - if ((ret_value = (cls->attr_cls.specific)(obj, loc_params, args, dxpl_id, req)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + /* (Must return value from callback, for iterators) */ + ret_value = (cls->attr_cls.specific)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute attribute 'specific' callback"); done: @@ -1567,9 +1680,15 @@ H5VL__attr_optional(void *obj, const H5VL_class_t *cls, H5VL_optional_args_t *ar if (NULL == cls->attr_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'attr optional' method"); - /* Call the corresponding VOL callback */ - /* (Must return value from callback, for iterators) */ - if ((ret_value = (cls->attr_cls.optional)(obj, args, dxpl_id, req)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + /* (Must return value from callback, for iterators) */ + ret_value = (cls->attr_cls.optional)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute attribute optional callback"); done: @@ -1709,8 +1828,14 @@ H5VL__attr_close(void *obj, const H5VL_class_t *cls, hid_t dxpl_id, void **req) if (NULL == cls->attr_cls.close) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'attr close' method"); - /* Call the corresponding VOL callback */ - if ((cls->attr_cls.close)(obj, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->attr_cls.close)(obj, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "attribute close failed"); done: @@ -1810,9 +1935,15 @@ H5VL__dataset_create(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_ if (NULL == cls->dataset_cls.create) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'dataset create' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->dataset_cls.create)(obj, loc_params, name, lcpl_id, type_id, space_id, - dcpl_id, dapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.create)(obj, loc_params, name, lcpl_id, type_id, space_id, dcpl_id, + dapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "dataset create failed"); done: @@ -1915,8 +2046,14 @@ H5VL__dataset_open(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_cl if (NULL == cls->dataset_cls.open) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'dataset open' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->dataset_cls.open)(obj, loc_params, name, dapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.open)(obj, loc_params, name, dapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "dataset open failed"); done: @@ -2016,8 +2153,15 @@ H5VL__dataset_read(size_t count, void *obj[], const H5VL_class_t *cls, hid_t mem if (NULL == cls->dataset_cls.read) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset read' method"); - /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.read)(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.read)(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, + buf, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "dataset read failed"); done: @@ -2140,8 +2284,15 @@ H5VL__dataset_write(size_t count, void *obj[], const H5VL_class_t *cls, hid_t me if (NULL == cls->dataset_cls.write) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset write' method"); - /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.write)(count, obj, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.write)(count, obj, mem_type_id, mem_space_id, file_space_id, + dxpl_id, buf, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "dataset write failed"); done: @@ -2264,8 +2415,14 @@ H5VL__dataset_get(void *obj, const H5VL_class_t *cls, H5VL_dataset_get_args_t *a if (NULL == cls->dataset_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset get' method"); - /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.get)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.get)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "dataset get failed"); done: @@ -2362,8 +2519,14 @@ H5VL__dataset_specific(void *obj, const H5VL_class_t *cls, H5VL_dataset_specific if (NULL == cls->dataset_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset specific' method"); - /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.specific)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.specific)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute dataset specific callback"); done: @@ -2461,8 +2624,14 @@ H5VL__dataset_optional(void *obj, const H5VL_class_t *cls, H5VL_optional_args_t if (NULL == cls->dataset_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.optional)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.optional)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute dataset optional callback"); done: @@ -2604,8 +2773,14 @@ H5VL__dataset_close(void *obj, const H5VL_class_t *cls, hid_t dxpl_id, void **re if (NULL == cls->dataset_cls.close) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'dataset close' method"); - /* Call the corresponding VOL callback */ - if ((cls->dataset_cls.close)(obj, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->dataset_cls.close)(obj, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "dataset close failed"); done: @@ -2708,9 +2883,15 @@ H5VL__datatype_commit(void *obj, const H5VL_loc_params_t *loc_params, const H5VL if (NULL == cls->datatype_cls.commit) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'datatype commit' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->datatype_cls.commit)(obj, loc_params, name, type_id, lcpl_id, tcpl_id, - tapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->datatype_cls.commit)(obj, loc_params, name, type_id, lcpl_id, tcpl_id, tapl_id, + dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "datatype commit failed"); done: @@ -2811,8 +2992,14 @@ H5VL__datatype_open(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_c if (NULL == cls->datatype_cls.open) HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, NULL, "no datatype open callback"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->datatype_cls.open)(obj, loc_params, name, tapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->datatype_cls.open)(obj, loc_params, name, tapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "datatype open failed"); done: @@ -2912,8 +3099,14 @@ H5VL__datatype_get(void *obj, const H5VL_class_t *cls, H5VL_datatype_get_args_t if (NULL == cls->datatype_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'datatype get' method"); - /* Call the corresponding VOL callback */ - if ((cls->datatype_cls.get)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->datatype_cls.get)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "datatype 'get' failed"); done: @@ -3010,8 +3203,14 @@ H5VL__datatype_specific(void *obj, const H5VL_class_t *cls, H5VL_datatype_specif if (NULL == cls->datatype_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'datatype specific' method"); - /* Call the corresponding VOL callback */ - if ((cls->datatype_cls.specific)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->datatype_cls.specific)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute datatype specific callback"); done: @@ -3109,8 +3308,14 @@ H5VL__datatype_optional(void *obj, const H5VL_class_t *cls, H5VL_optional_args_t if (NULL == cls->datatype_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'datatype optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->datatype_cls.optional)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->datatype_cls.optional)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute datatype optional callback"); done: @@ -3296,8 +3501,14 @@ H5VL__datatype_close(void *obj, const H5VL_class_t *cls, hid_t dxpl_id, void **r if (NULL == cls->datatype_cls.close) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'datatype close' method"); - /* Call the corresponding VOL callback */ - if ((cls->datatype_cls.close)(obj, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->datatype_cls.close)(obj, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "datatype close failed"); done: @@ -3396,8 +3607,14 @@ H5VL__file_create(const H5VL_class_t *cls, const char *name, unsigned flags, hid if (NULL == cls->file_cls.create) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'file create' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->file_cls.create)(name, flags, fcpl_id, fapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->file_cls.create)(name, flags, fcpl_id, fapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "file create failed"); done: @@ -3490,8 +3707,14 @@ H5VL__file_open(const H5VL_class_t *cls, const char *name, unsigned flags, hid_t if (NULL == cls->file_cls.open) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'file open' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->file_cls.open)(name, flags, fapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->file_cls.open)(name, flags, fapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "open failed"); done: @@ -3559,9 +3782,9 @@ H5VL__file_open_find_connector_cb(H5PL_type_t H5_ATTR_UNUSED plugin_type, vol_cb_args.args.is_accessible.accessible = &is_accessible; H5E_PAUSE_ERRORS - { - status = H5VL_file_specific(NULL, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL); - } + { + status = H5VL_file_specific(NULL, &vol_cb_args, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL); + } H5E_RESUME_ERRORS if (status >= 0 && is_accessible) { @@ -3708,8 +3931,14 @@ H5VL__file_get(void *obj, const H5VL_class_t *cls, H5VL_file_get_args_t *args, h if (NULL == cls->file_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'file get' method"); - /* Call the corresponding VOL callback */ - if ((cls->file_cls.get)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->file_cls.get)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "file get failed"); done: @@ -3805,8 +4034,14 @@ H5VL__file_specific(void *obj, const H5VL_class_t *cls, H5VL_file_specific_args_ if (NULL == cls->file_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'file specific' method"); - /* Call the corresponding VOL callback */ - if ((cls->file_cls.specific)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->file_cls.specific)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "file specific failed"); done: @@ -3935,8 +4170,14 @@ H5VL__file_optional(void *obj, const H5VL_class_t *cls, H5VL_optional_args_t *ar if (NULL == cls->file_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'file optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->file_cls.optional)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->file_cls.optional)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "file optional failed"); done: @@ -4078,8 +4319,14 @@ H5VL__file_close(void *obj, const H5VL_class_t *cls, hid_t dxpl_id, void **req) if (NULL == cls->file_cls.close) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'file close' method"); - /* Call the corresponding VOL callback */ - if ((cls->file_cls.close)(obj, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->file_cls.close)(obj, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEFILE, FAIL, "file close failed"); done: @@ -4175,9 +4422,15 @@ H5VL__group_create(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_cl if (NULL == cls->group_cls.create) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'group create' method"); - /* Call the corresponding VOL callback */ - if (NULL == - (ret_value = (cls->group_cls.create)(obj, loc_params, name, lcpl_id, gcpl_id, gapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = + (cls->group_cls.create)(obj, loc_params, name, lcpl_id, gcpl_id, gapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, NULL, "group create failed"); done: @@ -4277,8 +4530,14 @@ H5VL__group_open(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_clas if (NULL == cls->group_cls.open) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'group open' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->group_cls.open)(obj, loc_params, name, gapl_id, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->group_cls.open)(obj, loc_params, name, gapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "group open failed"); done: @@ -4376,8 +4635,14 @@ H5VL__group_get(void *obj, const H5VL_class_t *cls, H5VL_group_get_args_t *args, if (NULL == cls->group_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'group get' method"); - /* Call the corresponding VOL callback */ - if ((cls->group_cls.get)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->group_cls.get)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "group get failed"); done: @@ -4473,8 +4738,14 @@ H5VL__group_specific(void *obj, const H5VL_class_t *cls, H5VL_group_specific_arg if (NULL == cls->group_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'group specific' method"); - /* Call the corresponding VOL callback */ - if ((cls->group_cls.specific)(obj, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->group_cls.specific)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute group specific callback"); done: @@ -4571,9 +4842,15 @@ H5VL__group_optional(void *obj, const H5VL_class_t *cls, H5VL_optional_args_t *a if (NULL == cls->group_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'group optional' method"); - /* Call the corresponding VOL callback */ - /* (Must return value from callback, for iterators) */ - if ((ret_value = (cls->group_cls.optional)(obj, args, dxpl_id, req)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + /* (Must return value from callback, for iterators) */ + ret_value = (cls->group_cls.optional)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute group optional callback"); done: @@ -4717,8 +4994,14 @@ H5VL__group_close(void *obj, const H5VL_class_t *cls, hid_t dxpl_id, void **req) if (NULL == cls->group_cls.close) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'group close' method"); - /* Call the corresponding VOL callback */ - if ((cls->group_cls.close)(obj, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->group_cls.close)(obj, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "group close failed"); done: @@ -4816,8 +5099,14 @@ H5VL__link_create(H5VL_link_create_args_t *args, void *obj, const H5VL_loc_param if (NULL == cls->link_cls.create) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'link create' method"); - /* Call the corresponding VOL callback */ - if ((cls->link_cls.create)(args, obj, loc_params, lcpl_id, lapl_id, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->link_cls.create)(args, obj, loc_params, lcpl_id, lapl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, FAIL, "link create failed"); done: @@ -4927,8 +5216,15 @@ H5VL__link_copy(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_o if (NULL == cls->link_cls.copy) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'link copy' method"); - /* Call the corresponding VOL callback */ - if ((cls->link_cls.copy)(src_obj, loc_params1, dst_obj, loc_params2, lcpl_id, lapl_id, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->link_cls.copy)(src_obj, loc_params1, dst_obj, loc_params2, lcpl_id, lapl_id, + dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCOPY, FAIL, "link copy failed"); done: @@ -5033,8 +5329,15 @@ H5VL__link_move(void *src_obj, const H5VL_loc_params_t *loc_params1, void *dst_o if (NULL == cls->link_cls.move) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'link move' method"); - /* Call the corresponding VOL callback */ - if ((cls->link_cls.move)(src_obj, loc_params1, dst_obj, loc_params2, lcpl_id, lapl_id, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->link_cls.move)(src_obj, loc_params1, dst_obj, loc_params2, lcpl_id, lapl_id, + dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTMOVE, FAIL, "link move failed"); done: @@ -5142,8 +5445,14 @@ H5VL__link_get(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_class_ if (NULL == cls->link_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'link get' method"); - /* Call the corresponding VOL callback */ - if ((cls->link_cls.get)(obj, loc_params, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->link_cls.get)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "link get failed"); done: @@ -5241,9 +5550,15 @@ H5VL__link_specific(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_c if (NULL == cls->link_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'link specific' method"); - /* Call the corresponding VOL callback */ - /* (Must return value from callback, for iterators) */ - if ((ret_value = (cls->link_cls.specific)(obj, loc_params, args, dxpl_id, req)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + /* (Must return value from callback, for iterators) */ + ret_value = (cls->link_cls.specific)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute link specific callback"); done: @@ -5344,8 +5659,14 @@ H5VL__link_optional(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_c if (NULL == cls->link_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'link optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->link_cls.optional)(obj, loc_params, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->link_cls.optional)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute link optional callback"); done: @@ -5502,8 +5823,14 @@ H5VL__object_open(void *obj, const H5VL_loc_params_t *params, const H5VL_class_t if (NULL == cls->object_cls.open) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, NULL, "VOL connector has no 'object open' method"); - /* Call the corresponding VOL callback */ - if (NULL == (ret_value = (cls->object_cls.open)(obj, params, opened_type, dxpl_id, req))) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->object_cls.open)(obj, params, opened_type, dxpl_id, req); + } + H5_AFTER_USER_CB(NULL) + if (NULL == ret_value) HGOTO_ERROR(H5E_VOL, H5E_CANTOPENOBJ, NULL, "object open failed"); done: @@ -5603,9 +5930,15 @@ H5VL__object_copy(void *src_obj, const H5VL_loc_params_t *src_loc_params, const if (NULL == cls->object_cls.copy) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'object copy' method"); - /* Call the corresponding VOL callback */ - if ((cls->object_cls.copy)(src_obj, src_loc_params, src_name, dst_obj, dst_loc_params, dst_name, - ocpypl_id, lcpl_id, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->object_cls.copy)(src_obj, src_loc_params, src_name, dst_obj, dst_loc_params, + dst_name, ocpypl_id, lcpl_id, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCOPY, FAIL, "object copy failed"); done: @@ -5712,8 +6045,14 @@ H5VL__object_get(void *obj, const H5VL_loc_params_t *loc_params, const H5VL_clas if (NULL == cls->object_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'object get' method"); - /* Call the corresponding VOL callback */ - if ((cls->object_cls.get)(obj, loc_params, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->object_cls.get)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "get failed"); done: @@ -5811,9 +6150,15 @@ H5VL__object_specific(void *obj, const H5VL_loc_params_t *loc_params, const H5VL if (NULL == cls->object_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'object specific' method"); - /* Call the corresponding VOL callback */ - /* (Must return value from callback, for iterators) */ - if ((ret_value = (cls->object_cls.specific)(obj, loc_params, args, dxpl_id, req)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + /* (Must return value from callback, for iterators) */ + ret_value = (cls->object_cls.specific)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HERROR(H5E_VOL, H5E_CANTOPERATE, "object specific failed"); done: @@ -5914,8 +6259,14 @@ H5VL__object_optional(void *obj, const H5VL_loc_params_t *loc_params, const H5VL if (NULL == cls->object_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'object optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->object_cls.optional)(obj, loc_params, args, dxpl_id, req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->object_cls.optional)(obj, loc_params, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute object optional callback"); done: @@ -6080,8 +6431,14 @@ H5VL__introspect_get_conn_cls(void *obj, const H5VL_class_t *cls, H5VL_get_conn_ if (NULL == cls->introspect_cls.get_conn_cls) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'get_conn_cls' method"); - /* Call the corresponding VOL callback */ - if ((cls->introspect_cls.get_conn_cls)(obj, lvl, conn_cls) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->introspect_cls.get_conn_cls)(obj, lvl, conn_cls); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't query connector class"); done: @@ -6189,8 +6546,14 @@ H5VL_introspect_get_cap_flags(const void *info, const H5VL_class_t *cls, uint64_ if (NULL == cls->introspect_cls.get_cap_flags) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'get_cap_flags' method"); - /* Call the corresponding VOL callback */ - if ((cls->introspect_cls.get_cap_flags)(info, cap_flags) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->introspect_cls.get_cap_flags)(info, cap_flags); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't query connector capability flags"); done: @@ -6255,8 +6618,14 @@ H5VL__introspect_opt_query(void *obj, const H5VL_class_t *cls, H5VL_subclass_t s if (NULL == cls->introspect_cls.opt_query) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'opt_query' method"); - /* Call the corresponding VOL callback */ - if ((cls->introspect_cls.opt_query)(obj, subcls, opt_type, flags) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->introspect_cls.opt_query)(obj, subcls, opt_type, flags); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't query optional operation support"); done: @@ -6357,8 +6726,14 @@ H5VL__request_wait(void *req, const H5VL_class_t *cls, uint64_t timeout, H5VL_re if (NULL == cls->request_cls.wait) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'async wait' method"); - /* Call the corresponding VOL callback */ - if ((cls->request_cls.wait)(req, timeout, status) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->request_cls.wait)(req, timeout, status); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "request wait failed"); done: @@ -6459,8 +6834,14 @@ H5VL__request_notify(void *req, const H5VL_class_t *cls, H5VL_request_notify_t c if (NULL == cls->request_cls.notify) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'async notify' method"); - /* Call the corresponding VOL callback */ - if ((cls->request_cls.notify)(req, cb, ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->request_cls.notify)(req, cb, ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "request notify failed"); done: @@ -6562,8 +6943,14 @@ H5VL__request_cancel(void *req, const H5VL_class_t *cls, H5VL_request_status_t * if (NULL == cls->request_cls.cancel) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'async cancel' method"); - /* Call the corresponding VOL callback */ - if ((cls->request_cls.cancel)(req, status) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->request_cls.cancel)(req, status); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "request cancel failed"); done: @@ -6663,8 +7050,14 @@ H5VL__request_specific(void *req, const H5VL_class_t *cls, H5VL_request_specific if (NULL == cls->request_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'async specific' method"); - /* Call the corresponding VOL callback */ - if ((cls->request_cls.specific)(req, args) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->request_cls.specific)(req, args); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute asynchronous request specific callback"); @@ -6767,8 +7160,14 @@ H5VL__request_optional(void *req, const H5VL_class_t *cls, H5VL_optional_args_t if (NULL == cls->request_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'async optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->request_cls.optional)(req, args) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->request_cls.optional)(req, args); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute asynchronous request optional callback"); @@ -6907,8 +7306,14 @@ H5VL__request_free(void *req, const H5VL_class_t *cls) if (NULL == cls->request_cls.free) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'async free' method"); - /* Call the corresponding VOL callback */ - if ((cls->request_cls.free)(req) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->request_cls.free)(req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "request free failed"); done: @@ -7009,8 +7414,14 @@ H5VL__blob_put(void *obj, const H5VL_class_t *cls, const void *buf, size_t size, if (NULL == cls->blob_cls.put) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'blob put' method"); - /* Call the corresponding VOL callback */ - if ((cls->blob_cls.put)(obj, buf, size, blob_id, ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->blob_cls.put)(obj, buf, size, blob_id, ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "blob put callback failed"); done: @@ -7103,8 +7514,14 @@ H5VL__blob_get(void *obj, const H5VL_class_t *cls, const void *blob_id, void *bu if (NULL == cls->blob_cls.get) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'blob get' method"); - /* Call the corresponding VOL callback */ - if ((cls->blob_cls.get)(obj, blob_id, buf, size, ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->blob_cls.get)(obj, blob_id, buf, size, ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "blob get callback failed"); done: @@ -7196,8 +7613,14 @@ H5VL__blob_specific(void *obj, const H5VL_class_t *cls, void *blob_id, H5VL_blob if (NULL == cls->blob_cls.specific) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'blob specific' method"); - /* Call the corresponding VOL callback */ - if ((cls->blob_cls.specific)(obj, blob_id, args) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->blob_cls.specific)(obj, blob_id, args); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute blob specific callback"); done: @@ -7289,8 +7712,14 @@ H5VL__blob_optional(void *obj, const H5VL_class_t *cls, void *blob_id, H5VL_opti if (NULL == cls->blob_cls.optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'blob optional' method"); - /* Call the corresponding VOL callback */ - if ((cls->blob_cls.optional)(obj, blob_id, args) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->blob_cls.optional)(obj, blob_id, args); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTOPERATE, FAIL, "unable to execute blob optional callback"); done: @@ -7396,7 +7825,13 @@ H5VL__token_cmp(void *obj, const H5VL_class_t *cls, const H5O_token_t *token1, c * memory buffers. */ if (cls->token_cls.cmp) { - if ((cls->token_cls.cmp)(obj, token1, token2, cmp_value) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (cls->token_cls.cmp)(obj, token1, token2, cmp_value); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCOMPARE, FAIL, "can't compare object tokens"); } /* end if */ else @@ -7508,7 +7943,13 @@ H5VL__token_to_str(void *obj, H5I_type_t obj_type, const H5VL_class_t *cls, cons * callback, otherwise just set the token_str to NULL. */ if (cls->token_cls.to_str) { - if ((cls->token_cls.to_str)(obj, obj_type, token, token_str) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (cls->token_cls.to_str)(obj, obj_type, token, token_str); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTSERIALIZE, FAIL, "can't serialize object token"); } /* end if */ else @@ -7614,7 +8055,13 @@ H5VL__token_from_str(void *obj, H5I_type_t obj_type, const H5VL_class_t *cls, co * callback, otherwise just set the token to H5_TOKEN_UNDEF. */ if (cls->token_cls.from_str) { - if ((cls->token_cls.from_str)(obj, obj_type, token_str, token) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = (cls->token_cls.from_str)(obj, obj_type, token_str, token); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTUNSERIALIZE, FAIL, "can't deserialize object token string"); } /* end if */ else @@ -7713,8 +8160,14 @@ H5VL__optional(void *obj, const H5VL_class_t *cls, H5VL_optional_args_t *args, h if (NULL == cls->optional) HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "VOL connector has no 'optional' method"); - /* Call the corresponding VOL callback */ - if ((ret_value = (cls->optional)(obj, args, dxpl_id, req)) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Call the corresponding VOL callback */ + ret_value = (cls->optional)(obj, args, dxpl_id, req); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HERROR(H5E_VOL, H5E_CANTOPERATE, "unable to execute optional callback"); done: diff --git a/src/H5VLint.c b/src/H5VLint.c index 6d2864e2d91..477f5bc319a 100644 --- a/src/H5VLint.c +++ b/src/H5VLint.c @@ -328,8 +328,16 @@ H5VL__free_cls(H5VL_class_t *cls) assert(cls); /* Shut down the VOL connector */ - if (cls->terminate && cls->terminate() < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not terminate cleanly"); + if (cls->terminate) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + ret_value = cls->terminate(); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "VOL connector did not terminate cleanly"); + } /* Release the class */ H5MM_xfree_const(cls->name); @@ -1320,8 +1328,18 @@ H5VL__register_connector(const H5VL_class_t *cls, hid_t vipl_id) HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, NULL, "memory allocation failed for VOL connector name"); /* Initialize the VOL connector */ - if (cls->initialize && cls->initialize(vipl_id) < 0) - HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, NULL, "unable to init VOL connector"); + if (cls->initialize) { + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(NULL) + { + status = cls->initialize(vipl_id); + } + H5_AFTER_USER_CB(NULL) + if (status < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTINIT, NULL, "unable to init VOL connector"); + } init_done = true; /* Create new connector for the class */ @@ -1787,8 +1805,14 @@ H5VL_object_data(const H5VL_object_t *vol_obj) FUNC_ENTER_NOAPI_NOINIT_NOERR /* Check for 'get_object' callback in connector */ - if (vol_obj->connector->cls->wrap_cls.get_object) - ret_value = (vol_obj->connector->cls->wrap_cls.get_object)(vol_obj->data); + if (vol_obj->connector->cls->wrap_cls.get_object) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB_NOERR(NULL) + { + ret_value = (vol_obj->connector->cls->wrap_cls.get_object)(vol_obj->data); + } + H5_AFTER_USER_CB_NOERR(NULL) + } else ret_value = vol_obj->data; @@ -2221,11 +2245,19 @@ H5VL__free_vol_wrapper(H5VL_wrap_ctx_t *vol_wrap_ctx) assert(vol_wrap_ctx->connector->cls); /* If there is a VOL connector object wrapping context, release it */ - if (vol_wrap_ctx->obj_wrap_ctx) - /* Release the VOL connector's object wrapping context */ - if ((*vol_wrap_ctx->connector->cls->wrap_cls.free_wrap_ctx)(vol_wrap_ctx->obj_wrap_ctx) < 0) + if (vol_wrap_ctx->obj_wrap_ctx) { + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Release the VOL connector's object wrapping context */ + ret_value = + (*vol_wrap_ctx->connector->cls->wrap_cls.free_wrap_ctx)(vol_wrap_ctx->obj_wrap_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTRELEASE, FAIL, "unable to release connector's object wrapping context"); + } /* Decrement refcount on connector */ if (H5VL_conn_dec_rc(vol_wrap_ctx->connector) < 0) @@ -2275,8 +2307,15 @@ H5VL_set_vol_wrapper(const H5VL_object_t *vol_obj) /* Sanity check */ assert(vol_obj->connector->cls->wrap_cls.free_wrap_ctx); - /* Get the wrap context from the connector */ - if ((vol_obj->connector->cls->wrap_cls.get_wrap_ctx)(vol_obj->data, &obj_wrap_ctx) < 0) + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Get the wrap context from the connector */ + ret_value = + (vol_obj->connector->cls->wrap_cls.get_wrap_ctx)(vol_obj->data, &obj_wrap_ctx); + } + H5_AFTER_USER_CB(FAIL) + if (ret_value < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTGET, FAIL, "can't retrieve VOL connector's object wrap context"); } /* end if */ diff --git a/src/H5Z.c b/src/H5Z.c index 2f9b5f1dc91..749652ce451 100644 --- a/src/H5Z.c +++ b/src/H5Z.c @@ -797,8 +797,15 @@ H5Z__prelude_callback(const H5O_pline_t *pline, hid_t dcpl_id, hid_t type_id, hi /* Check if there is a "can apply" callback */ if (fclass->can_apply) { - /* Make callback to filter's "can apply" function */ - htri_t status = (fclass->can_apply)(dcpl_id, type_id, space_id); + htri_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Make callback to filter's "can apply" function */ + status = (fclass->can_apply)(dcpl_id, type_id, space_id); + } + H5_AFTER_USER_CB(FAIL) /* Indicate error during filter callback */ if (status < 0) @@ -814,9 +821,18 @@ H5Z__prelude_callback(const H5O_pline_t *pline, hid_t dcpl_id, hid_t type_id, hi case H5Z_PRELUDE_SET_LOCAL: /* Check if there is a "set local" callback */ if (fclass->set_local) { - /* Make callback to filter's "set local" function */ - if ((fclass->set_local)(dcpl_id, type_id, space_id) < 0) - /* Indicate error during filter callback */ + herr_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + /* Make callback to filter's "set local" function */ + status = (fclass->set_local)(dcpl_id, type_id, space_id); + } + H5_AFTER_USER_CB(FAIL) + + /* Indicate error during filter callback */ + if (status < 0) HGOTO_ERROR(H5E_PLINE, H5E_SETLOCAL, FAIL, "error during user callback"); } /* end if */ break; @@ -1373,6 +1389,8 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i assert(buf && *buf); assert(!pline || pline->nused < H5Z_MAX_NFILTERS); + /* clang-format off */ + #ifdef H5Z_DEBUG H5_timer_init(&timer); #endif @@ -1430,11 +1448,16 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i tmp_flags = flags | (pline->filter[idx].flags); tmp_flags |= (edc_read == H5Z_DISABLE_EDC) ? H5Z_FLAG_SKIP_EDC : 0; + H5E_PAUSE_ERRORS - { - new_nbytes = (fclass->filter)(tmp_flags, pline->filter[idx].cd_nelmts, - pline->filter[idx].cd_values, *nbytes, buf_size, buf); - } + {/* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + new_nbytes = (fclass->filter)(tmp_flags, pline->filter[idx].cd_nelmts, + pline->filter[idx].cd_values, *nbytes, buf_size, buf); + } + H5_AFTER_USER_CB(FAIL) + } H5E_RESUME_ERRORS #ifdef H5Z_DEBUG @@ -1450,9 +1473,19 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i #endif if (0 == new_nbytes) { - if ((cb_struct.func && (H5Z_CB_FAIL == cb_struct.func(pline->filter[idx].id, *buf, *buf_size, - cb_struct.op_data))) || - !cb_struct.func) + if (cb_struct.func) { + H5Z_cb_return_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = cb_struct.func(pline->filter[idx].id, *buf, *buf_size, cb_struct.op_data); + } + H5_AFTER_USER_CB(FAIL) + if (H5Z_CB_FAIL == status) + HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "filter returned failure during read"); + } + else HGOTO_ERROR(H5E_PLINE, H5E_READERROR, FAIL, "filter returned failure during read"); *nbytes = *buf_size; @@ -1462,7 +1495,8 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i *nbytes = new_nbytes; } } - else if (pline) { /* Write */ + else if (pline) + { /* Write */ for (idx = 0; idx < pline->nused; idx++) { if (*filter_mask & ((unsigned)1 << idx)) { failed |= (unsigned)1 << idx; @@ -1484,10 +1518,14 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i #endif H5E_PAUSE_ERRORS - { - new_nbytes = (fclass->filter)(flags | pline->filter[idx].flags, pline->filter[idx].cd_nelmts, - pline->filter[idx].cd_values, *nbytes, buf_size, buf); - } + {/* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + new_nbytes = (fclass->filter)(flags | (pline->filter[idx].flags), pline->filter[idx].cd_nelmts, + pline->filter[idx].cd_values, *nbytes, buf_size, buf); + } + H5_AFTER_USER_CB(FAIL) + } H5E_RESUME_ERRORS #ifdef H5Z_DEBUG @@ -1504,9 +1542,19 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i if (0 == new_nbytes) { if (0 == (pline->filter[idx].flags & H5Z_FLAG_OPTIONAL)) { - if ((cb_struct.func && (H5Z_CB_FAIL == cb_struct.func(pline->filter[idx].id, *buf, - *nbytes, cb_struct.op_data))) || - !cb_struct.func) + if (cb_struct.func) { + H5Z_cb_return_t status; + + /* Prepare & restore library for user callback */ + H5_BEFORE_USER_CB(FAIL) + { + status = cb_struct.func(pline->filter[idx].id, *buf, *nbytes, cb_struct.op_data); + } + H5_AFTER_USER_CB(FAIL) + if (H5Z_CB_FAIL == status) + HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "filter returned failure"); + } + else HGOTO_ERROR(H5E_PLINE, H5E_WRITEERROR, FAIL, "filter returned failure"); *nbytes = *buf_size; @@ -1522,6 +1570,8 @@ H5Z_pipeline(const H5O_pline_t *pline, unsigned flags, unsigned *filter_mask /*i done: FUNC_LEAVE_NOAPI(ret_value) + +/* clang-format on */ } /*------------------------------------------------------------------------- diff --git a/src/H5build_settings.autotools.c.in b/src/H5build_settings.autotools.c.in index 8fd583de62f..36547212e54 100644 --- a/src/H5build_settings.autotools.c.in +++ b/src/H5build_settings.autotools.c.in @@ -95,6 +95,7 @@ const char H5build_settings[]= " Build HDF5 Tools: @HDF5_TOOLS@\n" " Threads: @THREADS@\n" " Threadsafety: @THREADSAFE@\n" + " Concurrency: @CONCURRENCY@\n" " Default API mapping: @DEFAULT_API_VERSION@\n" " With deprecated public symbols: @DEPRECATED_SYMBOLS@\n" " I/O filters (external): @EXTERNAL_FILTERS@\n" diff --git a/src/H5build_settings.cmake.c.in b/src/H5build_settings.cmake.c.in index 9530fbc822e..ecbd08eb666 100644 --- a/src/H5build_settings.cmake.c.in +++ b/src/H5build_settings.cmake.c.in @@ -94,6 +94,7 @@ const char H5build_settings[]= " Build HDF5 Tests: @BUILD_TESTING@\n" " Build HDF5 Tools: @HDF5_BUILD_TOOLS@\n" " Threadsafety: @HDF5_ENABLE_THREADSAFE@\n" + " Concurrency: @HDF5_ENABLE_CONCURRENCY@\n" " Default API mapping: @HDF5_DEFAULT_API_VERSION@\n" " With deprecated public symbols: @HDF5_ENABLE_DEPRECATED_SYMBOLS@\n" " I/O filters (external): @EXTERNAL_FILTERS@\n" diff --git a/src/H5private.h b/src/H5private.h index cff6b37390c..8950b541bed 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1000,6 +1000,48 @@ extern H5_debug_t H5_debug_g; /* Embedded build information */ extern const char H5build_settings[]; +/* Prepare to call / return from user callback */ +#include "H5Eprivate.h" +typedef struct H5_user_cb_state_t { + H5E_user_cb_state_t h5e_state; /* State for H5E package */ +} H5_user_cb_state_t; + +#define H5_BEFORE_USER_CB(err) \ + { \ + H5_user_cb_state_t state; \ + \ + if (H5_user_cb_prepare(&state) < 0) \ + HGOTO_ERROR(H5E_LIB, H5E_CANTSET, (err), "preparation for user callback failed"); + +#define H5_AFTER_USER_CB(err) \ + if (H5_user_cb_restore(&state) < 0) \ + HGOTO_ERROR(H5E_LIB, H5E_CANTRESTORE, (err), "preparation for user callback failed"); \ + } + +#define H5_BEFORE_USER_CB_NOERR(err) \ + { \ + H5_user_cb_state_t state; \ + \ + if (H5_user_cb_prepare(&state) < 0) \ + ret_value = (err); \ + else { + +#define H5_AFTER_USER_CB_NOERR(err) \ + if (H5_user_cb_restore(&state) < 0) \ + ret_value = (err); \ + } /* end else */ \ + } + +#define H5_BEFORE_USER_CB_NOCHECK \ + { \ + H5_user_cb_state_t state; \ + \ + H5_user_cb_prepare(&state); + +#define H5_AFTER_USER_CB_NOCHECK \ + H5_user_cb_restore(&state); \ + } + /*------------------------------------------------------------------------- * Purpose: These macros are used to track arguments in event sets and are * inserted automatically into H5ES_insert() by the bin/trace script @@ -1056,7 +1098,14 @@ 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[]; -#ifdef H5_HAVE_THREADSAFE +/* Both the 'threadsafe' and 'concurrency' options provide threadsafely for + * API calls. + */ +#if defined(H5_HAVE_THREADSAFE) || defined(H5_HAVE_CONCURRENCY) +#define H5_HAVE_THREADSAFE_API +#endif + +#ifdef H5_HAVE_THREADSAFE_API /* Lock headers */ #include "H5TSprivate.h" @@ -1078,13 +1127,21 @@ extern char H5_lib_vers_info_g[]; } while (0) #else /* Local variable for saving cancellation state */ -#define H5CANCEL_DECL /* */ +#define H5CANCEL_DECL /* */ /* Disable & restore canceling the thread */ -#define H5TS_DISABLE_CANCEL /* */ -#define H5TS_RESTORE_CANCEL /* */ +#define H5TS_DISABLE_CANCEL \ + do { \ + } while (0) /* no-op */ +#define H5TS_RESTORE_CANCEL \ + do { \ + } while (0) /* no-op */ #endif +#ifdef H5_HAVE_THREADSAFE +/* Local variable for 'disable locking for this thread' (DLFTT) state */ +#define H5DLFTT_DECL /* */ + /* Macros for entering & leaving an API routine in a threadsafe manner */ #define H5_API_LOCK \ /* Acquire the API lock */ \ @@ -1098,16 +1155,40 @@ extern char H5_lib_vers_info_g[]; \ /* Restore previous thread cancellation state */ \ H5TS_RESTORE_CANCEL; -#else /* H5_HAVE_THREADSAFE */ +#else /* H5_HAVE_CONCURRENCY */ +/* Local variable for 'disable locking for this thread' (DLFTT) state */ +#define H5DLFTT_DECL unsigned dlftt = 0; + +/* Macros for entering & leaving an API routine in a threadsafe manner */ +#define H5_API_LOCK \ + /* Acquire the API lock */ \ + H5TS_api_lock(&dlftt); \ + \ + /* Set thread cancellation state to 'disable', and remember previous state */ \ + if (0 == dlftt) \ + H5TS_DISABLE_CANCEL; +#define H5_API_UNLOCK \ + if (0 == dlftt) { \ + /* Release the API lock */ \ + H5TS_api_unlock(); \ + \ + /* Restore previous thread cancellation state */ \ + H5TS_RESTORE_CANCEL; \ + } +#endif +#else /* H5_HAVE_THREADSAFE_API */ /* Local variable for saving cancellation state */ #define H5CANCEL_DECL /* */ +/* Local variable for 'disable locking for this thread' (DLFTT) state */ +#define H5DLFTT_DECL /* */ + /* No locks (non-threadsafe builds) */ -#define H5_API_LOCK /* */ -#define H5_API_UNLOCK /* */ +#define H5_API_LOCK /* no-op */ +#define H5_API_UNLOCK /* no-op */ -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* Macros for accessing the global variables */ #define H5_INIT_GLOBAL (H5_libinit_g) @@ -1239,7 +1320,8 @@ extern char H5_lib_vers_info_g[]; /* Entry setup for public API call variables */ #define H5_API_SETUP_PUBLIC_API_VARS \ - H5CANCEL_DECL /* thread cancellation */ + H5CANCEL_DECL /* thread cancellation */ \ + H5DLFTT_DECL /* user callback protection */ /* Macro to initialize the library, if some other package hasn't already done that */ #define H5_API_SETUP_INIT_LIBRARY(err) \ @@ -1329,7 +1411,7 @@ extern char H5_lib_vers_info_g[]; /* * Use this macro for public API functions that shouldn't perform _any_ * initialization of the library or an interface or push themselves on the - * function stack, just perform tracing, etc. Examples are: H5close, + * function stack, just perform tracing, etc. Examples are: H5dont_atexit, * H5check_version, etc. */ #define FUNC_ENTER_API_NOINIT_NOERR \ @@ -1791,4 +1873,7 @@ H5_DLL herr_t H5_mpio_get_file_sync_required(MPI_File fh, bool *file_sync_requi H5_DLL herr_t H5_buffer_dump(FILE *stream, int indent, const uint8_t *buf, const uint8_t *marker, size_t buf_offset, size_t buf_size); +/* Functions for preparing for / returning from user callbacks */ +H5_DLL herr_t H5_user_cb_prepare(H5_user_cb_state_t *state); +H5_DLL herr_t H5_user_cb_restore(const H5_user_cb_state_t *state); #endif /* H5private_H */ diff --git a/src/libhdf5.settings.autotools.in b/src/libhdf5.settings.autotools.in index e7900a19dfc..77c1b986eb2 100644 --- a/src/libhdf5.settings.autotools.in +++ b/src/libhdf5.settings.autotools.in @@ -77,6 +77,7 @@ Dimension scales w/ new references: @DIMENSION_SCALES_WITH_NEW_REF@ Build HDF5 Tools: @HDF5_TOOLS@ Threads: @THREADS@ Threadsafety: @THREADSAFE@ + Concurrency: @CONCURRENCY@ Default API mapping: @DEFAULT_API_VERSION@ With deprecated public symbols: @DEPRECATED_SYMBOLS@ I/O filters (external): @EXTERNAL_FILTERS@ diff --git a/src/libhdf5.settings.cmake.in b/src/libhdf5.settings.cmake.in index 236e1ebb7f7..e6c8d3a7903 100644 --- a/src/libhdf5.settings.cmake.in +++ b/src/libhdf5.settings.cmake.in @@ -75,6 +75,7 @@ Dimension scales w/ new references: @DIMENSION_SCALES_WITH_NEW_REF@ Build HDF5 Tools: @HDF5_BUILD_TOOLS@ Threads: @HDF5_ENABLE_THREADS@ Threadsafety: @HDF5_ENABLE_THREADSAFE@ + Concurrency: @HDF5_ENABLE_CONCURRENCY@ Default API mapping: @HDF5_DEFAULT_API_VERSION@ With deprecated public symbols: @HDF5_ENABLE_DEPRECATED_SYMBOLS@ I/O filters (external): @EXTERNAL_FILTERS@ diff --git a/test/h5test.c b/test/h5test.c index e3bd8997b05..15e405b213c 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -959,7 +959,7 @@ h5_show_hostname(void) #ifdef H5_HAVE_PARALLEL int mpi_rank, mpi_initialized, mpi_finalized; #endif -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API uint64_t thread_id = 0; /* ID of thread */ if (H5TS_thread_id(&thread_id) < 0) @@ -977,12 +977,12 @@ h5_show_hostname(void) MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); printf("MPI-process %d.", mpi_rank); } -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API else printf("thread %" PRIu64 ".", thread_id); #endif #else -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API printf("thread %" PRIu64 ".", thread_id); #endif #endif diff --git a/test/hdfs.c b/test/hdfs.c index c09d75bd33e..6f5bfe4dd29 100644 --- a/test/hdfs.c +++ b/test/hdfs.c @@ -1062,9 +1062,10 @@ test_H5FDread_without_eoa_set_fails(void) * TEST * ********/ - H5E_BEGIN_TRY{/* mute stack trace on expected failure */ - JSVERIFY(FAIL, H5FDread(file_shakespeare, H5FD_MEM_DRAW, H5P_DEFAULT, 1200699, 102, buffer), - "cannot read before eoa is set")} H5E_END_TRY + H5E_BEGIN_TRY + {/* mute stack trace on expected failure */ + JSVERIFY(FAIL, H5FDread(file_shakespeare, H5FD_MEM_DRAW, H5P_DEFAULT, 1200699, 102, buffer), + "cannot read before eoa is set")} H5E_END_TRY for (i = 0; i < HDFS_TEST_MAX_BUF_SIZE; i++) { JSVERIFY(0, (unsigned)buffer[i], "buffer was modified by write!") } @@ -1376,13 +1377,15 @@ test_noops_and_autofails(void) /* auto-fail calls to write and truncate */ - H5E_BEGIN_TRY{JSVERIFY(FAIL, H5FDwrite(file, H5FD_MEM_DRAW, H5P_DEFAULT, 1000, 35, data), - "write must fail")} H5E_END_TRY + H5E_BEGIN_TRY + {JSVERIFY(FAIL, H5FDwrite(file, H5FD_MEM_DRAW, H5P_DEFAULT, 1000, 35, data), + "write must fail")} H5E_END_TRY - H5E_BEGIN_TRY{JSVERIFY(FAIL, H5FDtruncate(file, H5P_DEFAULT, false), "truncate must fail")} H5E_END_TRY + H5E_BEGIN_TRY + {JSVERIFY(FAIL, H5FDtruncate(file, H5P_DEFAULT, false), "truncate must fail")} H5E_END_TRY - H5E_BEGIN_TRY{ - JSVERIFY(FAIL, H5FDtruncate(file, H5P_DEFAULT, true), "truncate must fail (closing)")} H5E_END_TRY + H5E_BEGIN_TRY + {JSVERIFY(FAIL, H5FDtruncate(file, H5P_DEFAULT, true), "truncate must fail (closing)")} H5E_END_TRY /************ * TEARDOWN * @@ -1504,11 +1507,13 @@ test_H5F_integration(void) /* Read-Write Open access is not allowed with this file driver. */ - H5E_BEGIN_TRY{FAIL_IF(0 <= H5Fopen(filename_example_h5, H5F_ACC_RDWR, fapl_id))} H5E_END_TRY + H5E_BEGIN_TRY + {FAIL_IF(0 <= H5Fopen(filename_example_h5, H5F_ACC_RDWR, fapl_id))} H5E_END_TRY /* H5Fcreate() is not allowed with this file driver. */ - H5E_BEGIN_TRY{FAIL_IF(0 <= H5Fcreate(filename_missing, H5F_ACC_RDONLY, H5P_DEFAULT, fapl_id))} H5E_END_TRY + H5E_BEGIN_TRY + {FAIL_IF(0 <= H5Fcreate(filename_missing, H5F_ACC_RDONLY, H5P_DEFAULT, fapl_id))} H5E_END_TRY /* Successful open. */ diff --git a/test/hyperslab.c b/test/hyperslab.c index c407facf18a..3a84f9758bc 100644 --- a/test/hyperslab.c +++ b/test/hyperslab.c @@ -1150,9 +1150,9 @@ main(int argc, char *argv[]) * Open the library explicitly for thread-safe builds, so per-thread * things are initialized correctly. */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API H5open(); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ /* *------------------------------ @@ -1353,9 +1353,9 @@ main(int argc, char *argv[]) printf("All hyperslab tests passed.\n"); -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API H5close(); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ exit(EXIT_SUCCESS); } diff --git a/test/ttsafe.c b/test/ttsafe.c index 04f30c15138..2a172ee8a30 100644 --- a/test/ttsafe.c +++ b/test/ttsafe.c @@ -56,13 +56,13 @@ tts_is_threadsafe(const void H5_ATTR_UNUSED *params) bool is_ts; bool should_be; -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API is_ts = false; should_be = true; -#else /* H5_HAVE_THREADSAFE */ +#else /* H5_HAVE_THREADSAFE_API */ is_ts = true; should_be = false; -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ if (H5is_library_threadsafe(&is_ts) != SUCCEED) TestErrPrintf("H5_is_library_threadsafe() call failed - test failed\n"); @@ -117,7 +117,7 @@ main(int argc, char *argv[]) #ifdef H5_HAVE_STDATOMIC_H MESSAGE(2, ("\tC11 atomics enabled\n")); #endif -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API MESSAGE(2, ("\tThreadsafe API enabled\n")); #endif #endif @@ -144,11 +144,9 @@ main(int argc, char *argv[]) #endif /* !H5_HAVE_WIN_THREADS */ AddTest("semaphore", tts_semaphore, NULL, NULL, NULL, 0, "lightweight system semaphores"); -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API AddTest("thread_id", tts_thread_id, NULL, NULL, NULL, 0, "thread IDs"); - /* Error stack test must be done after thread_id test to not mess up expected IDs */ - AddTest("error_stacks", tts_error_stacks, NULL, NULL, NULL, 0, "error stack tests"); AddTest("dcreate", tts_dcreate, NULL, cleanup_dcreate, NULL, 0, "multi-dataset creation"); AddTest("error", tts_error, NULL, cleanup_error, NULL, 0, "per-thread error stacks"); #ifdef H5_HAVE_PTHREAD_H @@ -158,14 +156,17 @@ main(int argc, char *argv[]) AddTest("acreate", tts_acreate, NULL, cleanup_acreate, NULL, 0, "multi-attribute creation"); AddTest("attr_vlen", tts_attr_vlen, NULL, cleanup_attr_vlen, NULL, 0, "multi-file-attribute-vlen read"); + /* Error stack test must be done after thread_id test to not mess up expected IDs */ + AddTest("error_stacks", tts_error_stacks, NULL, NULL, NULL, 0, "error stack tests"); + /* Developer API routine tests */ AddTest("developer", tts_develop_api, NULL, NULL, NULL, 0, "developer API routines"); -#else /* H5_HAVE_THREADSAFE */ +#else /* H5_HAVE_THREADSAFE_API */ printf("Most thread-safety tests skipped because THREADSAFE not enabled\n"); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #else /* H5_HAVE_THREADS */ diff --git a/test/ttsafe.h b/test/ttsafe.h index 87b41d83bc6..3d81c5fc063 100644 --- a/test/ttsafe.h +++ b/test/ttsafe.h @@ -37,7 +37,10 @@ extern char *gen_name(int); void tts_is_threadsafe(const void *); #ifdef H5_HAVE_THREADS void tts_thread_pool(const void *); +#ifndef H5_HAVE_STDATOMIC_H +/* C11 atomics only tested when emulated */ void tts_atomics(const void *); +#endif /* H5_HAVE_STDATOMIC_H */ void tts_rwlock(const void *); void tts_semaphore(const void *); #ifndef H5_HAVE_WIN_THREADS @@ -46,7 +49,7 @@ void tts_rec_rwlock_smoke_check_2(const void *); void tts_rec_rwlock_smoke_check_3(const void *); void tts_rec_rwlock_smoke_check_4(const void *); #endif /* !H5_HAVE_WIN_THREADS */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API void tts_dcreate(const void *); void tts_error(const void *); void tts_cancel(const void *); @@ -63,6 +66,6 @@ void cleanup_cancel(void *); void cleanup_acreate(void *); void cleanup_attr_vlen(void *); -#endif /* H5_HAVE_THREADSAFE */ +#endif /* H5_HAVE_THREADSAFE_API */ #endif /* H5_HAVE_THREADS */ #endif /* TTSAFE_H */ diff --git a/test/ttsafe_acreate.c b/test/ttsafe_acreate.c index 98533203ac5..4f667f12f7f 100644 --- a/test/ttsafe_acreate.c +++ b/test/ttsafe_acreate.c @@ -29,7 +29,7 @@ #include "ttsafe.h" -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #define FILENAME "ttsafe_acreate.h5" #define DATASETNAME "IntData" @@ -189,4 +189,4 @@ cleanup_acreate(void H5_ATTR_UNUSED *params) } } -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/test/ttsafe_atomic.c b/test/ttsafe_atomic.c index 6dc294ea8ca..49879e4c959 100644 --- a/test/ttsafe_atomic.c +++ b/test/ttsafe_atomic.c @@ -18,7 +18,7 @@ #include "ttsafe.h" -#ifdef H5_HAVE_THREADS +#if defined(H5_HAVE_THREADS) && !defined(H5_HAVE_STDATOMIC_H) #define NUM_THREADS 16 @@ -176,4 +176,4 @@ tts_atomics(const void H5_ATTR_UNUSED *params) } /* end tts_atomics() */ -#endif /* H5_HAVE_THREADS */ +#endif /* defined(H5_HAVE_THREADS) && !defined(H5_HAVE_STDATOMIC_H) */ diff --git a/test/ttsafe_attr_vlen.c b/test/ttsafe_attr_vlen.c index 13240e26ee9..d537c49fecb 100644 --- a/test/ttsafe_attr_vlen.c +++ b/test/ttsafe_attr_vlen.c @@ -42,7 +42,7 @@ #include "ttsafe.h" -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #define FILENAME "ttsafe_attr_vlen.h5" #define ATTR_NAME "root_attr" @@ -187,4 +187,4 @@ cleanup_attr_vlen(void H5_ATTR_UNUSED *params) } } -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/test/ttsafe_cancel.c b/test/ttsafe_cancel.c index 0a5dbabcc98..54e671ab8c0 100644 --- a/test/ttsafe_cancel.c +++ b/test/ttsafe_cancel.c @@ -29,14 +29,13 @@ ********************************************************************/ #include "ttsafe.h" -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #ifdef H5_HAVE_PTHREAD_H #define FILENAME "ttsafe_cancel.h5" #define DATASETNAME "commonname" void *tts_cancel_thread(void *); -void tts_cancel_barrier(void); herr_t tts_cancel_callback(void *, hid_t, unsigned, const hsize_t *, void *); void cancellation_cleanup(void *); @@ -210,5 +209,5 @@ cleanup_cancel(void H5_ATTR_UNUSED *params) } } -#endif /*H5_HAVE_PTHREAD_H*/ -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_PTHREAD_H */ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/test/ttsafe_dcreate.c b/test/ttsafe_dcreate.c index 14f751055f8..ebea5be03d5 100644 --- a/test/ttsafe_dcreate.c +++ b/test/ttsafe_dcreate.c @@ -25,7 +25,7 @@ ********************************************************************/ #include "ttsafe.h" -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #define FILENAME "ttsafe_dcreate.h5" #define NUM_THREAD 16 @@ -158,4 +158,4 @@ cleanup_dcreate(void H5_ATTR_UNUSED *params) HDunlink(FILENAME); } } -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/test/ttsafe_develop.c b/test/ttsafe_develop.c index fbe91949486..3f9c023b2ff 100644 --- a/test/ttsafe_develop.c +++ b/test/ttsafe_develop.c @@ -16,9 +16,13 @@ * ********************************************************************/ +#define H5VL_FRIEND /* Suppress error about including H5VLpkg */ +#define H5VL_TESTING + #include "ttsafe.h" +#include "H5VLpkg.h" /* Virtual Object Layer */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API typedef struct { H5TS_barrier_t *barrier; @@ -99,26 +103,42 @@ tts_develop_api_thr_2(void *_udata) void tts_develop_api(const void H5_ATTR_UNUSED *params) { + hid_t def_fapl = H5I_INVALID_HID; + hid_t vol_id = H5I_INVALID_HID; 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; + int is_native; 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"); + def_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(def_fapl, H5I_INVALID_HID, "H5Pcreate"); + + result = H5Pget_vol_id(def_fapl, &vol_id); + CHECK(result, FAIL, "H5Pget_vol_id"); + + is_native = H5VL__is_native_connector_test(vol_id); + CHECK(is_native, FAIL, "H5VL__is_native_connector_test"); + + if (is_native) { + /* 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"); + /* 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"); + 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"); + VERIFY(api_count_2, (api_count_1 + 1), "H5TSmutex_get_attempt_count"); + } /* end if */ + else + printf("Non-native VOL connector used, skipping mutex attempt count test\n"); /* Check H5TSmutex_acquire & H5TSmutex_release in thread callbacks */ @@ -162,4 +182,4 @@ tts_develop_api(const void H5_ATTR_UNUSED *params) } /* end tts_develop_api() */ -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/test/ttsafe_error.c b/test/ttsafe_error.c index 9322bf460ca..87320d63461 100644 --- a/test/ttsafe_error.c +++ b/test/ttsafe_error.c @@ -30,7 +30,7 @@ #define H5VL_TESTING #include "H5VLpkg.h" /* Virtual Object Layer */ -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #define NUM_THREAD 16 #define FILENAME "ttsafe_error.h5" @@ -265,4 +265,4 @@ cleanup_error(void H5_ATTR_UNUSED *params) } } -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/test/ttsafe_error_stacks.c b/test/ttsafe_error_stacks.c index 6edca5b5fe2..96dae962ff7 100644 --- a/test/ttsafe_error_stacks.c +++ b/test/ttsafe_error_stacks.c @@ -11,7 +11,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "ttsafe.h" -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #define ERR_CLS_NAME "Custom error class" #define ERR_CLS_LIB_NAME "example_lib" diff --git a/test/ttsafe_thread_id.c b/test/ttsafe_thread_id.c index 540857cae71..f75c6cde8a7 100644 --- a/test/ttsafe_thread_id.c +++ b/test/ttsafe_thread_id.c @@ -18,7 +18,7 @@ #include "ttsafe.h" -#ifdef H5_HAVE_THREADSAFE +#ifdef H5_HAVE_THREADSAFE_API #define CYCLE_COUNT 2 #define NTHREADS 5 @@ -135,4 +135,4 @@ tts_thread_id(const void H5_ATTR_UNUSED *params) } /* end tts_thread_id() */ -#endif /*H5_HAVE_THREADSAFE*/ +#endif /* H5_HAVE_THREADSAFE_API */ diff --git a/tools/lib/h5tools_error.h b/tools/lib/h5tools_error.h index 2496d585419..c7361345af6 100644 --- a/tools/lib/h5tools_error.h +++ b/tools/lib/h5tools_error.h @@ -16,7 +16,7 @@ #ifndef H5TOOLS_ERROR_H #define H5TOOLS_ERROR_H -#include "H5Epublic.h" +#include "H5private.h" #include "H5Eprivate.h" /* Error handling */ /* tools-HDF5 Error variables */