From 7f93e90c8ec2c8cfb55330771f5562c422750500 Mon Sep 17 00:00:00 2001 From: Matt L <124107509+mattjala@users.noreply.github.com> Date: Tue, 17 Dec 2024 10:44:42 -0600 Subject: [PATCH 1/5] Re-enable zlib in LOG VOL CI (#5181) --- .github/workflows/vol_log.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/vol_log.yml b/.github/workflows/vol_log.yml index 287cf6c1ffb..5dadbe6e8c5 100644 --- a/.github/workflows/vol_log.yml +++ b/.github/workflows/vol_log.yml @@ -41,7 +41,7 @@ jobs: -DHDF5_ENABLE_PARALLEL:BOOL=ON \ -DHDF5_ENABLE_THREADSAFE:BOOL=ON \ -DHDF5_ALLOW_UNSUPPORTED:BOOL=ON \ - -DHDF5_ENABLE_ZLIB_SUPPORT:BOOL=OFF \ + -DHDF5_ENABLE_ZLIB_SUPPORT:BOOL=ON \ -DHDF5_ENABLE_SZIP_SUPPORT:BOOL=OFF \ ${{ github.workspace }}/hdf5 cat src/libhdf5.settings From 74e7f1f56a1e37693024edbbb275beb491edd207 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 02:45:06 +0000 Subject: [PATCH 2/5] Committing clang-format changes --- src/H5Iint.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/H5Iint.c b/src/H5Iint.c index a3869a7453e..05f68f9adfe 100644 --- a/src/H5Iint.c +++ b/src/H5Iint.c @@ -460,10 +460,10 @@ H5I__clear_type(H5I_type_info_t *type_info, bool force, bool app_ref) if (item->is_future) { /* Prepare & restore library for user callback */ H5_BEFORE_USER_CB_NOCHECK - { - /* Discard the future object */ - status = (item->discard_cb)(item->u.object); - } + { + /* Discard the future object */ + status = (item->discard_cb)(item->u.object); + } H5_AFTER_USER_CB_NOCHECK if (status < 0) { if (force) @@ -479,9 +479,9 @@ H5I__clear_type(H5I_type_info_t *type_info, bool force, bool app_ref) if (type_info->cls->free_func) { /* Prepare & restore library for user callback */ H5_BEFORE_USER_CB_NOCHECK - { - status = (type_info->cls->free_func)(item->u.object, H5_REQUEST_NULL); - } + { + status = (type_info->cls->free_func)(item->u.object, H5_REQUEST_NULL); + } H5_AFTER_USER_CB_NOCHECK if (status < 0) { if (force) From 7dfd9b4392a2efeeb911dbd4657003eea245a190 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 18 Dec 2024 07:35:57 -0600 Subject: [PATCH 3/5] There is no need to request libcurses for the CMake CI (#5180) * Do not use CXX env var for intel builds --- .github/workflows/cmake-analysis.yml | 8 ++++---- .github/workflows/cmake-ctest.yml | 3 +-- .github/workflows/cmake-script.yml | 4 +--- .github/workflows/intel-auto.yml | 5 ----- .github/workflows/intel-cmake.yml | 6 ------ 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/cmake-analysis.yml b/.github/workflows/cmake-analysis.yml index aeddcc245a5..9fc9ed998d4 100644 --- a/.github/workflows/cmake-analysis.yml +++ b/.github/workflows/cmake-analysis.yml @@ -32,7 +32,7 @@ jobs: - name: Install CMake Dependencies (Linux_coverage) run: | sudo apt update - sudo apt-get install ninja-build doxygen graphviz curl libncurses5 build-essential + sudo apt-get install ninja-build doxygen graphviz curl build-essential sudo apt install libssl3 libssl-dev libcurl4 libcurl4-openssl-dev sudo apt-get install lcov -q -y @@ -127,7 +127,7 @@ jobs: - name: Install CMake Dependencies (Linux_Leak) run: | sudo apt update - sudo apt-get install ninja-build doxygen graphviz curl libncurses5 + sudo apt-get install ninja-build doxygen graphviz curl - name: add clang to env uses: KyleMayes/install-llvm-action@v2.0.5 @@ -227,7 +227,7 @@ jobs: - name: Install CMake Dependencies (Linux_Address) run: | sudo apt update - sudo apt-get install ninja-build doxygen graphviz curl libncurses5 + sudo apt-get install ninja-build doxygen graphviz curl - name: add clang to env uses: KyleMayes/install-llvm-action@v2.0.5 @@ -327,7 +327,7 @@ jobs: - name: Install CMake Dependencies (Linux_UndefinedBehavior) run: | sudo apt update - sudo apt-get install ninja-build doxygen graphviz curl libncurses5 + sudo apt-get install ninja-build doxygen graphviz curl - name: add clang to env uses: KyleMayes/install-llvm-action@v2.0.5 diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index cb67868305c..7941528c2ba 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -680,7 +680,7 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} + BINSIGN: ${{ needs.check-secret.outputs.sign-state }} SIGNTOOLDIR: ${{ github.workspace }}/Microsoft.Windows.SDK.BuildTools/bin/10.0.22621.0/x64 run: | @@ -796,7 +796,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | cd "${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}" cmake --workflow --preset=${{ inputs.preset_name }}-Intel --fresh diff --git a/.github/workflows/cmake-script.yml b/.github/workflows/cmake-script.yml index 4b76dfc0ce8..f4e1acaa000 100644 --- a/.github/workflows/cmake-script.yml +++ b/.github/workflows/cmake-script.yml @@ -500,7 +500,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cc }} run: | cd "${{ runner.workspace }}/hdf5" ctest -S HDF5config.cmake,CTEST_SITE_EXT=GH-${{ github.event.repository.full_name }}-Intel,LOCAL_SUBMIT=ON,NINJA=TRUE,BUILD_GENERATOR=VS202264,CTEST_SOURCE_NAME=${{ steps.set-file-base.outputs.SOURCE_BASE }} -C Release -VV -O hdf5.log @@ -597,7 +596,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | cd "${{ runner.workspace }}/hdf5" ctest -S HDF5config.cmake,CTEST_SITE_EXT=GH-${{ github.event.repository.full_name }}-Intel,LOCAL_SUBMIT=ON,NINJA=TRUE,BUILD_GENERATOR=Unix,CTEST_SOURCE_NAME=${{ steps.set-file-base.outputs.SOURCE_BASE }} -C Release -VV -O hdf5.log @@ -622,7 +620,7 @@ jobs: - name: Install CMake Dependencies (Linux_clang) run: | sudo apt-get update - sudo apt-get install ninja-build doxygen graphviz curl libncurses5 + sudo apt-get install ninja-build doxygen graphviz curl - name: add clang to env uses: KyleMayes/install-llvm-action@v2.0.5 diff --git a/.github/workflows/intel-auto.yml b/.github/workflows/intel-auto.yml index 6f80a79eebc..2f0c01847bc 100644 --- a/.github/workflows/intel-auto.yml +++ b/.github/workflows/intel-auto.yml @@ -38,7 +38,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | sh ./autogen.sh mkdir "${{ runner.workspace }}/build" @@ -54,7 +53,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | make -j3 working-directory: ${{ runner.workspace }}/build @@ -64,7 +62,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | make check -j2 working-directory: ${{ runner.workspace }}/build @@ -74,7 +71,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | make install working-directory: ${{ runner.workspace }}/build @@ -84,7 +80,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | make check-install working-directory: ${{ runner.workspace }}/build diff --git a/.github/workflows/intel-cmake.yml b/.github/workflows/intel-cmake.yml index 8cfdcdc1e86..3fc37359065 100644 --- a/.github/workflows/intel-cmake.yml +++ b/.github/workflows/intel-cmake.yml @@ -39,7 +39,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | mkdir "${{ runner.workspace }}/build" cd "${{ runner.workspace }}/build" @@ -56,7 +55,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | cmake --build . --parallel 3 --config ${{ inputs.build_mode }} working-directory: ${{ runner.workspace }}/build @@ -66,7 +64,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | ctest . --parallel 2 -C ${{ inputs.build_mode }} -V working-directory: ${{ runner.workspace }}/build @@ -93,7 +90,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | mkdir "${{ runner.workspace }}/build" Set-Location -Path "${{ runner.workspace }}\\build" @@ -104,7 +100,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | cmake --build . --parallel 3 --config ${{ inputs.build_mode }} working-directory: ${{ runner.workspace }}/build @@ -114,7 +109,6 @@ jobs: env: FC: ${{ steps.setup-fortran.outputs.fc }} CC: ${{ steps.setup-fortran.outputs.cc }} - CXX: ${{ steps.setup-fortran.outputs.cxx }} run: | ctest . --parallel 2 -C ${{ inputs.build_mode }} -V -E tfloatsattrs working-directory: ${{ runner.workspace }}/build From f9d60b5ac166466dd36fdd6d0c559fb56e819f2e Mon Sep 17 00:00:00 2001 From: John Donners <40058074+donners-atos@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:03:25 +0100 Subject: [PATCH 4/5] Update file-locking.md (#5185) Changed the "writer process" to the "reader process" that can crash. --- doc/file-locking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/file-locking.md b/doc/file-locking.md index 4f7fb39c031..067f7ab3993 100644 --- a/doc/file-locking.md +++ b/doc/file-locking.md @@ -248,7 +248,7 @@ setting AND check the environment variable, which can override the fapl. Disabling the file locks is at your own risk. If more than one writer process modifies an HDF5 file at the same time, the file could be corrupted. If a -reader process reads a file that is being modified by a writer, the writer +reader process reads a file that is being modified by a writer, the reader process might attempt to read garbage and encounter errors or even crash. In the case of: From 331193f357278a91d195fb5387b8240fb0aa81ec Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Thu, 19 Dec 2024 03:35:21 -0600 Subject: [PATCH 5/5] Add new multithreaded concurrency configuration (#5015) Added infrastructure support for multithreaded concurrency by adding an optional way to switch to using a non-recursive R/W lock for the global API lock. This is enabled with a new 'concurrency' configuration flag for the autotools & CMake builds, which is disabled by default. When the 'concurrency' build option is chosen, the global API lock will use the R/W lock and all API calls currently will acquire a write lock, ensuring exclusive access by one thread. Over time, the API routines that are converted to support multithreaded concurrency will switch to acquiring a read lock instead. Reentering the library from application callbacks is managed by the 'disable locking for this thread' (DLFTT) threadsafety protocol. This is internally handled within the H5_API_LOCK / H5_API_UNLOCK macros in H5private.h (as before), which invoke the 'dlftt' routines in H5TSint.c. To support this change, the threadsafety configuration macros for the library have been updated: - --enable-threadsafe now defines the H5_HAVE_THREADSAFE macro - --enable-concurrency defines the H5_HAVE_CONCURRENCY macro The new H5_HAVE_THREADSAFE_API macro is set if either H5_HAVE_THREADSAFE or H5_HAVE_CONCURRENCY is enabled. New Github actions are added to include the concurrency configuration in the CI for the develop branch. To support the new non-recursive R/W locking for API routines, some other changes are necessary: Added macro wrappers around all callback invocations that could call an application function, and therefore re-enter the library: H5_BEFORE_USER_CB* / H5_AFTER_USER_CB* Added H5_user_cb_prepare / H5_user_cb_restore routines that save the state of the library when callback leaves the library. Includes error stack and threadsafe reentry state currently. There's also some small cleanups to various places in the library: Moved the H5E_mpi_error_str / H5E_mpi_error_str_len globals to be local for pushing MPI errors, so that multiple threads can't interfere with each other. Added H5TS_rwlock_trywrlock() routine to R/W lock interface. Emulate R/W locks on MacOS because its implementation of pthread_rwlock_wrlock() does not conform to the POSIX standard. Don't acquire the global API lock in H5close, since it's acquired in H5_term_library, which is necessary because H5_term_library is invoked via other code paths that don't hold the global API lock. Don't call H5Eget_auto2 API routine within H5_term_library. Switched 'return NULL' in H5allocate_memory to HGOTO_DONE(NULL). Switched H5Pget_file_space_strategy / H5Pset_file_space_strategy to use internal routines instead of API routines. Switched H5Oopen_by_addr & H5Ovisit1 to use internal routines instead of API routines. Fixed a few places in src/H5Odeprec.c where a major error ID was passed as a minor ID. --- .clang-format | 7 +- .github/workflows/autotools.yml | 20 + .github/workflows/cmake.yml | 20 + .github/workflows/main-auto.yml | 31 +- .github/workflows/main-cmake.yml | 53 +- CMakeLists.txt | 53 ++ LICENSE | 112 ++-- config/cmake/H5pubconf.h.in | 8 + configure.ac | 82 +++ release_docs/INSTALL_Autotools.txt | 23 +- release_docs/INSTALL_CMake.txt | 20 +- release_docs/RELEASE.txt | 28 +- src/H5.c | 89 +++- src/H5Adense.c | 22 +- src/H5Aint.c | 19 +- src/H5CX.c | 10 +- src/H5D.c | 22 +- src/H5Dchunk.c | 21 +- src/H5Dfill.c | 89 +++- src/H5ESint.c | 31 +- src/H5Eint.c | 209 ++++++-- src/H5Epkg.h | 8 +- src/H5Eprivate.h | 44 +- src/H5FD.c | 219 ++++++-- src/H5FDcore.c | 79 ++- src/H5FDfamily.c | 6 +- src/H5FDint.c | 463 +++++++++-------- src/H5FDspace.c | 88 +++- src/H5FO.c | 13 +- src/H5Fint.c | 13 +- src/H5Fsuper.c | 6 +- src/H5Gint.c | 27 +- src/H5Glink.c | 16 +- src/H5Gnode.c | 6 +- src/H5Gstab.c | 12 +- src/H5Gtraverse.c | 33 +- src/H5I.c | 22 +- src/H5Iint.c | 90 +++- src/H5Lexternal.c | 11 +- src/H5Lint.c | 42 +- src/H5Ocopy.c | 11 +- src/H5Odeprec.c | 46 +- src/H5Oint.c | 9 +- src/H5Olink.c | 10 +- src/H5Pdeprec.c | 65 ++- src/H5Pencdec.c | 20 +- src/H5Pfapl.c | 201 +++++--- src/H5Pfcpl.c | 100 +++- src/H5Pint.c | 183 +++++-- src/H5Ppkg.h | 6 + src/H5SMcache.c | 5 +- src/H5Sselect.c | 10 +- src/H5T.c | 51 +- src/H5TS.c | 4 +- src/H5TSc11.c | 6 +- src/H5TSint.c | 321 +++++++++++- src/H5TSmodule.h | 2 +- src/H5TSpkg.h | 23 +- src/H5TSprivate.h | 64 ++- src/H5TSpthread.c | 6 +- src/H5TSrwlock.c | 83 +++ src/H5TSrwlock.h | 321 ++++++++++++ src/H5TSwin.c | 6 +- src/H5Tconv_bitfield.c | 16 +- src/H5Tconv_complex.c | 57 ++- src/H5Tconv_enum.c | 36 +- src/H5Tconv_float.c | 154 ++++-- src/H5Tconv_integer.c | 128 +++-- src/H5Tconv_macros.h | 341 ++++++++++--- src/H5Tvlen.c | 17 +- src/H5UC.c | 3 +- src/H5VLcallback.c | 763 ++++++++++++++++++++++------ src/H5VLint.c | 61 ++- src/H5Z.c | 90 +++- src/H5build_settings.autotools.c.in | 1 + src/H5build_settings.cmake.c.in | 1 + src/H5private.h | 105 +++- src/libhdf5.settings.autotools.in | 1 + src/libhdf5.settings.cmake.in | 1 + test/h5test.c | 6 +- test/hdfs.c | 25 +- test/hyperslab.c | 8 +- test/ttsafe.c | 19 +- test/ttsafe.h | 7 +- test/ttsafe_acreate.c | 4 +- test/ttsafe_atomic.c | 4 +- test/ttsafe_attr_vlen.c | 4 +- test/ttsafe_cancel.c | 7 +- test/ttsafe_dcreate.c | 4 +- test/ttsafe_develop.c | 42 +- test/ttsafe_error.c | 4 +- test/ttsafe_error_stacks.c | 2 +- test/ttsafe_thread_id.c | 4 +- tools/lib/h5tools_error.h | 2 +- 94 files changed, 4385 insertions(+), 1252 deletions(-) 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 */