From 67ff153e3cab0da12843f13470c9b5c66f11533c Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Tue, 13 Aug 2024 07:42:51 -0500 Subject: [PATCH 01/94] Replace Visual Studio ???? with 2022 in MSI README file (#4709) --- config/cmake/HDFMacros.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/cmake/HDFMacros.cmake b/config/cmake/HDFMacros.cmake index 3545d4e9ff2..3be3e6a6a60 100644 --- a/config/cmake/HDFMacros.cmake +++ b/config/cmake/HDFMacros.cmake @@ -327,8 +327,10 @@ macro (HDF_README_PROPERTIES target_fortran) set (BINARY_PLATFORM "${BINARY_PLATFORM}, using VISUAL STUDIO 2019") elseif (${CMAKE_C_COMPILER_VERSION} MATCHES "^19.3.*") set (BINARY_PLATFORM "${BINARY_PLATFORM}, using VISUAL STUDIO 2022") + elseif (${CMAKE_C_COMPILER_VERSION} MATCHES "^19.4.*") + set (BINARY_PLATFORM "${BINARY_PLATFORM}, using VISUAL STUDIO 2022") else () - set (BINARY_PLATFORM "${BINARY_PLATFORM}, using VISUAL STUDIO ???") + set (BINARY_PLATFORM "${BINARY_PLATFORM}, using VISUAL STUDIO ????") endif () else () set (BINARY_PLATFORM "${BINARY_PLATFORM}, using VISUAL STUDIO ${CMAKE_C_COMPILER_VERSION}") From 9824e7f7e7ce045127f9a7424c25b3ef2ca06699 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:28:34 -0500 Subject: [PATCH 02/94] Change logic for checking secrets exists (#4711) --- .github/workflows/cmake-ctest.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 04dc2b664fc..54df049102d 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -59,14 +59,12 @@ jobs: - name: Check Secrets exists id: set-signing-state - env: - super_secret: ${{ secrets.AZURE_ENDPOINT }} run: | - if [[ '${{ env.super_secret }}' == '' ]] + if [ '${{ secrets.AZURE_ENDPOINT }}' != '' ]; then - SIGN_VAL=$(echo "false") + SIGN_VAL=$(echo "true"); else - SIGN_VAL=$(echo "true") + SIGN_VAL=$(echo "false"); fi echo "BINSIGN=$SIGN_VAL" >> $GITHUB_OUTPUT shell: bash @@ -493,14 +491,12 @@ jobs: - name: Check Secrets exists id: set-signing-state - env: - super_secret: ${{ secrets.AZURE_ENDPOINT }} run: | - if [[ '${{ env.super_secret }}' == '' ]] + if [ '${{ secrets.AZURE_ENDPOINT }}' != '' ]; then - SIGN_VAL=$(echo "false") + SIGN_VAL=$(echo "true"); else - SIGN_VAL=$(echo "true") + SIGN_VAL=$(echo "false"); fi echo "BINSIGN=$SIGN_VAL" >> $GITHUB_OUTPUT shell: bash From d7e0ad5200744d0cb947df0b09e22b6b8d2f15ad Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:43:28 -0500 Subject: [PATCH 03/94] Change osx refs to macos (#4707) --- .github/workflows/cmake-bintest.yml | 4 ++-- .github/workflows/cmake-ctest.yml | 14 +++++++------- .github/workflows/daily-build.yml | 2 +- .github/workflows/main-cmake.yml | 4 ++-- .github/workflows/release-files.yml | 16 ++++++++-------- .github/workflows/remove-files.yml | 4 ++-- CMakePresets.json | 6 +++--- HDF5Examples/CMakePresets.json | 6 +++--- bin/cmakehdf5 | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/cmake-bintest.yml b/.github/workflows/cmake-bintest.yml index 73d66f2414d..84f66007213 100644 --- a/.github/workflows/cmake-bintest.yml +++ b/.github/workflows/cmake-bintest.yml @@ -161,7 +161,7 @@ jobs: - name: Get published binary (MacOS_latest) uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - name: tgz-osx-${{ inputs.build_mode }}-binary + name: tgz-macos14_clang-${{ inputs.build_mode }}-binary path: ${{ github.workspace }} - name: Uncompress hdf5 binary (MacOS_latest) @@ -201,6 +201,6 @@ jobs: HDF5_PLUGIN_PATH: ${{ steps.set-hdf5lib-name.outputs.HDF5_PLUGIN_PATH }} run: | cd "${{ steps.set-hdf5lib-name.outputs.HDF5_ROOT }}/share/HDF5Examples" - cmake --workflow --preset=ci-StdShar-OSX-Clang --fresh + cmake --workflow --preset=ci-StdShar-MACOS-Clang --fresh shell: bash diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 54df049102d..eb75076ed65 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -358,7 +358,7 @@ jobs: id: run-ctest run: | cd "${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}" - cmake --workflow --preset=${{ inputs.preset_name }}-OSX-Clang --fresh + cmake --workflow --preset=${{ inputs.preset_name }}-MACOS-Clang --fresh shell: bash - name: Publish binary (MacOS_latest) @@ -371,7 +371,7 @@ jobs: cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/README.md ${{ runner.workspace }}/build/hdf5 cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/*.tar.gz ${{ runner.workspace }}/build/hdf5 cd "${{ runner.workspace }}/build" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-osx.tar.gz hdf5 + tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz hdf5 shell: bash - name: Publish dmg binary (MacOS_latest) @@ -384,7 +384,7 @@ jobs: cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/README.md ${{ runner.workspace }}/builddmg/hdf5 cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/*.dmg ${{ runner.workspace }}/builddmg/hdf5 cd "${{ runner.workspace }}/builddmg" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-osx.dmg.tar.gz hdf5 + tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz hdf5 shell: bash - name: List files in the space (MacOS_latest) @@ -396,15 +396,15 @@ jobs: - name: Save published binary (MacOS_latest) uses: actions/upload-artifact@v4 with: - name: tgz-osx-binary - path: ${{ runner.workspace }}/build/${{ steps.set-file-base.outputs.FILE_BASE }}-osx.tar.gz + name: tgz-macos14_clang-binary + path: ${{ runner.workspace }}/build/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` - name: Save published dmg binary (MacOS_latest) uses: actions/upload-artifact@v4 with: - name: tgz-osx-dmg-binary - path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-osx.dmg.tar.gz + name: tgz-macos14_clang-dmg-binary + path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` build_and_test_S3_linux: diff --git a/.github/workflows/daily-build.yml b/.github/workflows/daily-build.yml index ad53474b91c..1fd6435110c 100644 --- a/.github/workflows/daily-build.yml +++ b/.github/workflows/daily-build.yml @@ -64,7 +64,7 @@ jobs: if: ${{ needs.call-workflow-tarball.outputs.has_changes == 'true' }} call-workflow-release: - needs: [call-workflow-tarball, call-workflow-ctest, call-workflow-abi] + needs: [get-old-names, call-workflow-tarball, call-workflow-ctest, call-workflow-abi] permissions: contents: write # In order to allow tag creation uses: ./.github/workflows/release-files.yml diff --git a/.github/workflows/main-cmake.yml b/.github/workflows/main-cmake.yml index 50f3400a225..abc4140831b 100644 --- a/.github/workflows/main-cmake.yml +++ b/.github/workflows/main-cmake.yml @@ -266,7 +266,7 @@ jobs: - name: Save published binary (Mac_latest) uses: actions/upload-artifact@v4 with: - name: tgz-osx-${{ inputs.build_mode }}-binary + 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') }} @@ -274,7 +274,7 @@ jobs: - name: Save published dmg binary (Mac_latest) uses: actions/upload-artifact@v4 with: - name: tgz-osx-${{ inputs.build_mode }}-dmg-binary + name: tgz-macos14_clang-${{ inputs.build_mode }}-dmg-binary path: ${{ runner.workspace }}/build/HDF5-*-Darwin.dmg if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` if: ${{ (matrix.os == 'macos-latest') && (inputs.thread_safety != 'TS') }} diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index b9d76d26dba..2eea38fceb4 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -109,13 +109,13 @@ jobs: - name: Get published binary (MacOS) uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - name: tgz-osx-binary + name: tgz-macos14_clang-binary path: ${{ github.workspace }} - name: Get published dmg binary (MacOS) uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - name: tgz-osx-dmg-binary + name: tgz-macos14_clang-dmg-binary path: ${{ github.workspace }} - name: Get published binary (Linux) @@ -185,8 +185,8 @@ jobs: sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen.zip > ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt @@ -231,8 +231,8 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen.zip ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz @@ -260,8 +260,8 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.zip hdf5.tar.gz hdf5.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz diff --git a/.github/workflows/remove-files.yml b/.github/workflows/remove-files.yml index e34cc131414..643f2c1cf49 100644 --- a/.github/workflows/remove-files.yml +++ b/.github/workflows/remove-files.yml @@ -50,8 +50,8 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen.zip ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-osx.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz diff --git a/CMakePresets.json b/CMakePresets.json index ac436e2c9e6..fc323af2dc2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -250,7 +250,7 @@ ] }, { - "name": "ci-StdShar-OSX-Clang", + "name": "ci-StdShar-MACOS-Clang", "configurePreset": "ci-StdShar-Clang", "inherits": [ "ci-x64-Release-Clang" @@ -352,11 +352,11 @@ ] }, { - "name": "ci-StdShar-OSX-Clang", + "name": "ci-StdShar-MACOS-Clang", "steps": [ {"type": "configure", "name": "ci-StdShar-Clang"}, {"type": "build", "name": "ci-StdShar-Clang"}, - {"type": "test", "name": "ci-StdShar-OSX-Clang"}, + {"type": "test", "name": "ci-StdShar-MACOS-Clang"}, {"type": "package", "name": "ci-StdShar-Clang"} ] }, diff --git a/HDF5Examples/CMakePresets.json b/HDF5Examples/CMakePresets.json index 1dc335ea715..2dbf304111d 100644 --- a/HDF5Examples/CMakePresets.json +++ b/HDF5Examples/CMakePresets.json @@ -137,7 +137,7 @@ ] }, { - "name": "ci-StdShar-OSX-Clang", + "name": "ci-StdShar-MACOS-Clang", "configurePreset": "ci-StdShar-Clang", "inherits": [ "ci-x64-Release-Clang" @@ -203,11 +203,11 @@ ] }, { - "name": "ci-StdShar-OSX-Clang", + "name": "ci-StdShar-MACOS-Clang", "steps": [ {"type": "configure", "name": "ci-StdShar-Clang"}, {"type": "build", "name": "ci-StdShar-Clang"}, - {"type": "test", "name": "ci-StdShar-OSX-Clang"} + {"type": "test", "name": "ci-StdShar-MACOS-Clang"} ] }, { diff --git a/bin/cmakehdf5 b/bin/cmakehdf5 index bdd724f4a14..2ce05d12b81 100755 --- a/bin/cmakehdf5 +++ b/bin/cmakehdf5 @@ -150,7 +150,7 @@ INSTALL_HDF5() install_file=./HDF5-${version}-Linux.sh $install_file --skip-license $* ;; - Darwin) # Mac OSX DMG file + Darwin) # MacOS DMG file # These steps were a kludge. Need proper support from Cmake engineering. echo Darwin install step needs proper implementation. Quit. return 1 From 70c6a7a90129d66fd9580011f3bf9e7199b7d1d1 Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:54:44 -0400 Subject: [PATCH 04/94] Replace alias \Code with \TText (#4714) Fixed GH-2151 --- doxygen/aliases | 4 +- doxygen/dox/About.dox | 12 +- doxygen/dox/H5AC_cache_config_t.dox | 26 +- doxygen/dox/MetadataCachingInHDF5.dox | 26 +- doxygen/dox/ReferenceManual.dox | 8 +- doxygen/dox/api-compat-macros.dox | 390 +++++++++++++------------- doxygen/dox/cookbook/Files.dox | 8 +- doxygen/dox/rm-template.dox | 4 +- src/H5Dpublic.h | 2 +- src/H5Emodule.h | 2 +- src/H5FDlog.h | 64 ++--- src/H5FDmulti.h | 22 +- src/H5Fpublic.h | 28 +- src/H5Gpublic.h | 18 +- src/H5Lpublic.h | 4 +- src/H5Ppublic.h | 200 ++++++------- src/H5Tmodule.h | 6 +- src/H5Tpublic.h | 28 +- src/H5public.h | 10 +- 19 files changed, 431 insertions(+), 431 deletions(-) diff --git a/doxygen/aliases b/doxygen/aliases index da412d5c8f1..4bb6e8c0792 100644 --- a/doxygen/aliases +++ b/doxygen/aliases @@ -29,7 +29,7 @@ ALIASES += PLURL="github.com/HDFGroup/hdf5_plugins/blob/master" ALIASES += Bold{1}="\1" ALIASES += Emph{1}="\1" -ALIASES += Code{1}="\1" +ALIASES += TText{1}="\1" ################################################################################ # Return values @@ -249,7 +249,7 @@ ALIASES += es_id{1}="\param[in] \1 Event set identifier" # Others ################################################################################ -ALIASES += cpp_c_api_note="\attention \Bold{C++ Developers using HDF5 C-API functions beware:}\n Several functions in this C-API take function pointers or callbacks as arguments. Examples include H5Pset_elink_cb(), H5Pset_type_conv_cb(), H5Tconvert(), and H5Ewalk2(). Application code must ensure that those callback functions return normally such to allow the HDF5 to manage its resources and maintain a consistent state. For instance, those functions must not use the C \c setjmp / \c longjmp mechanism to leave those callback functions. Within the context of C++, any exceptions thrown within the callback function must be caught, such as with a \Code{catch(…)} statement. Any exception state can be placed within the provided user data function call arguments, and may be thrown again once the calling function has returned. Exceptions raised and not handled inside the callback are not supported as it might leave the HDF5 library in an inconsistent state. Similarly, using C++20 coroutines cannot be used as callbacks, since they do not support plain return statements. If a callback function yields execution to another C++20 coroutine calling HDF5 functions as well, this may lead to undefined behavior." +ALIASES += cpp_c_api_note="\attention \Bold{C++ Developers using HDF5 C-API functions beware:}\n Several functions in this C-API take function pointers or callbacks as arguments. Examples include H5Pset_elink_cb(), H5Pset_type_conv_cb(), H5Tconvert(), and H5Ewalk2(). Application code must ensure that those callback functions return normally such to allow the HDF5 to manage its resources and maintain a consistent state. For instance, those functions must not use the C \c setjmp / \c longjmp mechanism to leave those callback functions. Within the context of C++, any exceptions thrown within the callback function must be caught, such as with a \TText{catch(…)} statement. Any exception state can be placed within the provided user data function call arguments, and may be thrown again once the calling function has returned. Exceptions raised and not handled inside the callback are not supported as it might leave the HDF5 library in an inconsistent state. Similarly, using C++20 coroutines cannot be used as callbacks, since they do not support plain return statements. If a callback function yields execution to another C++20 coroutine calling HDF5 functions as well, this may lead to undefined behavior." ALIASES += par_compr_note="\attention If you are planning to use compression with parallel HDF5, ensure that calls to H5Dwrite() occur in collective mode. In other words, all MPI ranks (in the relevant communicator) call H5Dwrite() and pass a dataset transfer property list with the MPI-IO collective option property set to #H5FD_MPIO_COLLECTIVE_IO.\n Note that data transformations are currently \Bold{not} supported when writing to datasets in parallel and with compression enabled." ALIASES += sa_metadata_ops="\sa \li H5Pget_all_coll_metadata_ops() \li H5Pget_coll_metadata_write() \li H5Pset_all_coll_metadata_ops() \li H5Pset_coll_metadata_write() \li \ref maybe_metadata_reads" diff --git a/doxygen/dox/About.dox b/doxygen/dox/About.dox index d4a1db2bc62..e145516a30e 100644 --- a/doxygen/dox/About.dox +++ b/doxygen/dox/About.dox @@ -33,8 +33,8 @@ Please refer to the \ref RMT for guidance on how to create a new reference manua \subsubsection new_example Adding and Referencing API Examples -For each HDF5 module, such as \Code{H5F}, there is an examples source file called -\Code{H5*_examples.c}. For example, the \Code{H5F} API examples are located in +For each HDF5 module, such as \TText{H5F}, there is an examples source file called +\TText{H5*_examples.c}. For example, the \TText{H5F} API examples are located in H5F_examples.c. Examples are code blocks marked as Doxygen snippets. @@ -94,7 +94,7 @@ ask for help if unsure! For ease of reference, we define custom commands for each RFC in the RFCs section of the aliases -file. For example the custom command \Code{ref_rfc20141210} can be used to insert a +file. For example the custom command \TText{ref_rfc20141210} can be used to insert a reference to "RFC: Virtual Object Layer". In other words, the markup \verbatim \ref_rfc20141210 @@ -105,8 +105,8 @@ yields a clickable link: To add a new RFC, add a custom command for the RFC to the aliases -file. The naming convention for the custom command is \Code{ref_rfcYYYYMMDD}, -where \Code{YYYYMMDD} is the ID of the RFC. The URL is composed of the prefix +file. The naming convention for the custom command is \TText{ref_rfcYYYYMMDD}, +where \TText{YYYYMMDD} is the ID of the RFC. The URL is composed of the prefix \verbatim https://\RFCURL/ \endverbatim @@ -116,4 +116,4 @@ be https://\RFCURL/my_great_rfc_name.pdf \endverbatim -*/ \ No newline at end of file +*/ diff --git a/doxygen/dox/H5AC_cache_config_t.dox b/doxygen/dox/H5AC_cache_config_t.dox index 3faecd5d185..40d83301b2b 100644 --- a/doxygen/dox/H5AC_cache_config_t.dox +++ b/doxygen/dox/H5AC_cache_config_t.dox @@ -24,7 +24,7 @@ * Boolean field indicating whether the trace_file_name * field should be used to open a trace file for the cache. * - * \Emph{*** DEPRECATED ***} Use \Code{H5Fstart/stop} logging functions instead + * \Emph{*** DEPRECATED ***} Use \TText{H5Fstart/stop} logging functions instead * * The trace file is a debugging feature that allow the capture of * top level metadata cache requests for purposes of debugging and/or @@ -42,7 +42,7 @@ * Boolean field indicating whether the current trace * file (if any) should be closed. * - * \Emph{*** DEPRECATED ***} Use \Code{H5Fstart/stop} logging functions instead + * \Emph{*** DEPRECATED ***} Use \TText{H5Fstart/stop} logging functions instead * * See the above comments on the open_trace_file field. This field * should be set to \c FALSE unless there is an open trace file on the @@ -54,7 +54,7 @@ * Full path of the trace file to be opened if the * open_trace_file field is \c TRUE. * - * \Emph{*** DEPRECATED ***} Use \Code{H5Fstart/stop} logging functions instead + * \Emph{*** DEPRECATED ***} Use \TText{H5Fstart/stop} logging functions instead * * In the parallel case, an ascii representation of the mpi rank of * the process will be appended to the file name to yield a unique @@ -78,7 +78,7 @@ * soon as possible and monitor cache size. * * At present, evictions can only be disabled if automatic - * cache resizing is also disabled (that is, \Code{(incr_mode == + * cache resizing is also disabled (that is, \TText{(incr_mode == * H5C_incr__off ) && ( decr_mode == H5C_decr__off )}). There * is no logical reason why this should be so, but it simplifies * implementation and testing, and I can't think of any reason @@ -95,7 +95,7 @@ * \par initial_size * If enabled, this field contain the size the cache is * to be set to upon receipt of this structure. Needless to say, - * initial_size must lie in the closed interval \Code{[min_size, max_size]}. + * initial_size must lie in the closed interval \TText{[min_size, max_size]}. * * \par min_clean_fraction * \c double in the range 0 to 1 indicating the fraction @@ -105,13 +105,13 @@ * \par max_size * Maximum size to which the cache can be adjusted. The * supplied value must fall in the closed interval - * \Code{[MIN_MAX_CACHE_SIZE, MAX_MAX_CACHE_SIZE]}. Also, \c max_size must + * \TText{[MIN_MAX_CACHE_SIZE, MAX_MAX_CACHE_SIZE]}. Also, \c max_size must * be greater than or equal to \c min_size. * * \par min_size * Minimum size to which the cache can be adjusted. The * supplied value must fall in the closed interval - * \Code{[H5C__MIN_MAX_CACHE_SIZE, H5C__MAX_MAX_CACHE_SIZE]}. Also, \c min_size + * \TText{[H5C__MIN_MAX_CACHE_SIZE, H5C__MAX_MAX_CACHE_SIZE]}. Also, \c min_size * must be less than or equal to \c max_size. * * \par epoch_length @@ -122,7 +122,7 @@ * * At the end of an epoch, we discard prior hit rate data and start * collecting afresh. The epoch_length must lie in the closed - * interval \Code{[H5C__MIN_AR_EPOCH_LENGTH, H5C__MAX_AR_EPOCH_LENGTH]}. + * interval \TText{[H5C__MIN_AR_EPOCH_LENGTH, H5C__MAX_AR_EPOCH_LENGTH]}. * \endparblock * * @@ -201,8 +201,8 @@ * \li \c H5C_flash_incr__add_space: Let \c x be either the size of a newly * newly inserted entry, or the number of bytes by which the * size of an existing entry has been increased.\n - * If \Code{x > flash_threshold * current max cache size}, - * increase the current maximum cache size by \Code{x * flash_multiple} + * If \TText{x > flash_threshold * current max cache size}, + * increase the current maximum cache size by \TText{x * flash_multiple} * less any free space in the cache, and star a new epoch. For * now at least, pay no attention to the maximum increment. * @@ -213,7 +213,7 @@ * With a little thought, it should be obvious that the above flash * cache size increase algorithm is not sufficient for all circumstances * -- for example, suppose the user round robins through - * \Code{(1/flash_threshold) +1} groups, adding one data set to each on each + * \TText{(1/flash_threshold) +1} groups, adding one data set to each on each * pass. Then all will increase in size at about the same time, requiring * the max cache size to at least double to maintain acceptable * performance, however the above flash increment algorithm will not be @@ -319,7 +319,7 @@ * This field contains the number of epochs an entry must remain * unaccessed before it is evicted in an attempt to reduce the * cache size. If applicable, this field must lie in the range - * \Code{[1, H5C__MAX_EPOCH_MARKERS]}. + * \TText{[1, H5C__MAX_EPOCH_MARKERS]}. * \endparblock * * \par apply_empty_reserve @@ -412,4 +412,4 @@ * received from process zero.\n * To avoid possible messages from the past/future, all caches must * wait until all caches are done before leaving the sync point. - */ \ No newline at end of file + */ diff --git a/doxygen/dox/MetadataCachingInHDF5.dox b/doxygen/dox/MetadataCachingInHDF5.dox index d522456483c..81c7b0bffc3 100644 --- a/doxygen/dox/MetadataCachingInHDF5.dox +++ b/doxygen/dox/MetadataCachingInHDF5.dox @@ -508,7 +508,7 @@ The \ref H5AC_cache_config_t.min_clean_fraction "min_clean_fraction" sets the current minimum clean size as a fraction of the current max cache size. While this field was originally used only in the parallel version of the library, it now applies to the serial version as well. Its value must lie in the range -\Code{[0.0, 1.0]}. 0.01 is reasonable in the serial case, and 0.3 in the +\TText{[0.0, 1.0]}. 0.01 is reasonable in the serial case, and 0.3 in the parallel. A potential interaction, discovered at release 1.8.3, between the enforcement of @@ -524,15 +524,15 @@ H5AC_cache_config_t.min_size "min_size" fields specify the range of maximum sizes that may be set for the cache by the automatic resize code. \ref H5AC_cache_config_t.min_size "min_size" must be less than or equal to \ref H5AC_cache_config_t.max_size "max_size", and both must lie in the range -\Code{[H5C__MIN_MAX_CACHE_SIZE, H5C__MAX_MAX_CACHE_SIZE]} -- currently [1 KB, +\TText{[H5C__MIN_MAX_CACHE_SIZE, H5C__MAX_MAX_CACHE_SIZE]} -- currently [1 KB, 128 MB]. If you routinely run a cache size in the top half of this range, you should increase the hash table size. To do this, modify the \c -H5C__HASH_TABLE_LEN \Code{\#define} in \c H5Cpkg.h and re-compile. At present, +H5C__HASH_TABLE_LEN \TText{\#define} in \c H5Cpkg.h and re-compile. At present, \c H5C__HASH_TABLE_LEN must be a power of two. The \c epoch_length is the number of cache accesses between runs of the adaptive cache size control algorithms. It is ignored if these algorithms are turned -off. It must lie in the range \Code{[H5C__MIN_AR_EPOCH_LENGTH, +off. It must lie in the range \TText{[H5C__MIN_AR_EPOCH_LENGTH, H5C__MAX_AR_EPOCH_LENGTH]} -- currently [100, 1000000]. The above constants are defined in \c H5Cprivate.h. 50000 is a reasonable value. @@ -570,7 +570,7 @@ fields in the section are then used as follows: \ref H5AC_cache_config_t.lower_hr_threshold "lower_hr_threshold" is the threshold below which the hit rate must fall to trigger an increase. The value -must lie in the range \Code{[0.0 - 1.0]}. In my tests, a relatively high value +must lie in the range \TText{[0.0 - 1.0]}. In my tests, a relatively high value seems to work best -- 0.9 for example. \ref H5AC_cache_config_t.increment "increment" is the factor by which the old @@ -601,7 +601,7 @@ Let \c x be either the size of the newly inserted entry, the size of the newly loaded entry, or the number of bytes added to the size of the entry under consideration for triggering a flash cache size increase. -If \Code{t < x}, the basic condition for a flash cache size increase is met, and +If \TText{t < x}, the basic condition for a flash cache size increase is met, and we proceed as follows: Let \c space_needed equal \c x less the amount of free space in the cache. @@ -622,11 +622,11 @@ use. The use of the \ref H5AC_cache_config_t.flash_threshold "flash_threshold" field is discussed above. It must be a floating-point value in the range of -\Code{[0.1, 1.0]}. 0.25 is a reasonable value. +\TText{[0.1, 1.0]}. 0.25 is a reasonable value. The use of the \ref H5AC_cache_config_t.flash_multiple "flash_multiple" field is also discussed above. It must be a floating-point value in the range of -\Code{[0.1, 10.0]}. 1.4 is a reasonable value. +\TText{[0.1, 10.0]}. 1.4 is a reasonable value. \subsection decrement Decrement Configuration @@ -649,12 +649,12 @@ the decrement section are used as follows: \ref H5AC_cache_config_t.upper_hr_threshold "upper_hr_threshold" is the threshold above which the hit rate must rise to trigger cache size reduction. It -must be in the range \Code{[0.0, 1.0]}. In my synthetic tests, very high values +must be in the range \TText{[0.0, 1.0]}. In my synthetic tests, very high values like .9995 or .99995 seemed to work best. \ref H5AC_cache_config_t.decrement "decrement" is the factor by which the current maximum cache size is multiplied to obtain a tentative new maximum cache -size. It must lie in the range \Code{[0.0, 1.0]}. Relatively large values like +size. It must lie in the range \TText{[0.0, 1.0]}. Relatively large values like .9 seem to work best in my synthetic tests. Note that the actual size reduction may be smaller as required by \ref H5AC_cache_config_t.min_size "min_size" and \ref H5AC_cache_config_t.max_decrement "max_decrement" (discussed below). \ref @@ -676,7 +676,7 @@ decrement section are used as follows: \ref H5AC_cache_config_t.epochs_before_eviction "epochs_before_eviction" is the number of epochs an entry must reside unaccessed in the cache before it is -evicted. This value must lie in the range \Code{[1, H5C__MAX_EPOCH_MARKERS]}. \c +evicted. This value must lie in the range \TText{[1, H5C__MAX_EPOCH_MARKERS]}. \c H5C__MAX_EPOCH_MARKERS is defined in H5Cprivate.h, and is currently set to 10. \ref H5AC_cache_config_t.apply_max_decrement "apply_max_decrement" and \ref @@ -702,7 +702,7 @@ H5AC_cache_config_t.upper_hr_threshold "upper_hr_threshold". Here, \ref H5AC_cache_config_t.upper_hr_threshold "upper_hr_threshold" is the threshold above which the hit rate must rise to trigger cache size reduction. It -must be in the range \Code{[0.0, 1.0]}. In my synthetic tests, high values like +must be in the range \TText{[0.0, 1.0]}. In my synthetic tests, high values like .999 seemed to work well. \subsection parallel Parallel Configuration @@ -1017,4 +1017,4 @@ and the average successful and unsuccessful search depths in the hash table. If these latter figures are significantly above 1, you should increase the size of the hash table. - */ \ No newline at end of file + */ diff --git a/doxygen/dox/ReferenceManual.dox b/doxygen/dox/ReferenceManual.dox index a98bc3da52e..ac1a4f22904 100644 --- a/doxygen/dox/ReferenceManual.dox +++ b/doxygen/dox/ReferenceManual.dox @@ -151,18 +151,18 @@ Follow these simple rules and stay out of trouble: identifiers, which you typically obtain by creating new HDF5 items, copying items, or retrieving facets of items. Consequently, \Bold{and most importantly}, you are responsible for releasing the underlying - resources via the matching \Code{H5*close()} call, or deal with the consequences + resources via the matching \TText{H5*close()} call, or deal with the consequences of resource leakage. \li \Bold{Closed means closed:} Do not pass identifiers that were previously - \Code{H5*close()}-d to other API functions! It will generate an error. + \TText{H5*close()}-d to other API functions! It will generate an error. \li \Bold{Dynamic memory allocation:} The API contains a few functions in which the HDF5 library dynamically allocates memory on the caller's behalf. The caller owns this memory and eventually must free it by calling H5free_memory() and not language-explicit memory functions. \li \Bold{Don't modify while iterating:} Do not modify the underlying collection when an iteration is in progress! -\li \Bold{Use of locations:} Certain API functions, typically called \Code{H5***_by_name} +\li \Bold{Use of locations:} Certain API functions, typically called \TText{H5***_by_name} use a combination of identifiers and path names to refer to HDF5 objects. - If the identifier fully specifies the object in question, pass \Code{'.'} (a dot) + If the identifier fully specifies the object in question, pass \TText{'.'} (a dot) for the name! diff --git a/doxygen/dox/api-compat-macros.dox b/doxygen/dox/api-compat-macros.dox index 4a1578d7748..a899ef1165d 100644 --- a/doxygen/dox/api-compat-macros.dox +++ b/doxygen/dox/api-compat-macros.dox @@ -52,36 +52,36 @@ functions were retained and renamed to have an earlier number (for, e.g., '1') at the end of the original function name. - For example, consider the function \Code{H5Lvisit} in HDF5 release 1.10 + For example, consider the function \TText{H5Lvisit} in HDF5 release 1.10 as compared with 1.12:
Original function name and signature in 1.10.0 - \Code{herr_t H5Lvisit(hid_t grp_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op, void *op_data)} + \TText{herr_t H5Lvisit(hid_t grp_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterate_t op, void *op_data)}
Updated function and signature, introduced in release 1.12.0 - \Code{herr_t H5Lvisit2(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterate2_t op, void *op_data)} + \TText{herr_t H5Lvisit2(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterate2_t op, void *op_data)}
Original function and signature, renamed in release 1.12.0 - \Code{herr_t H5Lvisit1(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterate1_t op, void *op_data)} + \TText{herr_t H5Lvisit1(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterate1_t op, void *op_data)}
API compatibility macro, introduced in release 1.12.0 - \Code{H5Lvisit} -

The macro, \Code{H5Lvisit}, will be mapped to either \Code{H5Lvisit1} or - \Code{H5Lvisit2}. The mapping is determined by a combination of the + \TText{H5Lvisit} +

The macro, \TText{H5Lvisit}, will be mapped to either \TText{H5Lvisit1} or + \TText{H5Lvisit2}. The mapping is determined by a combination of the configuration options use to build the HDF5 library and compile-time options used to build the application. The calling parameters used with the - \Code{H5Lvisit} compatibility macro should match the number and type of the - function the macros will be mapped to (\Code{H5Lvisit1} or \Code{H5Lvisit2}). + \TText{H5Lvisit} compatibility macro should match the number and type of the + function the macros will be mapped to (\TText{H5Lvisit1} or \TText{H5Lvisit2}).

The function names ending in '1' or '2' are referred to as \Emph{versioned names}, and the corresponding functions are referred to as \Emph{versioned functions}. @@ -135,7 +135,7 @@

\subsection lib-options Library Mapping Options - When the HDF5 library is built, \Code{configure} flags can be used to control the API + When the HDF5 library is built, \TText{configure} flags can be used to control the API compatibility macro mapping behavior exhibited by the library. This behavior can be overridden by application and function mappings. One configure flag excludes deprecated functions from the HDF5 library, making them unavailable to applications linked with the @@ -144,85 +144,85 @@
Table 1: Library Mapping Options - - - + + + - - + + - - + + - - + + - - + + - - + +
\Code{configure} flagMacros map to release
(versioned function; \Code{H5Lvisit} shown)
Deprecated functions available?
(\Code{H5Lvisit1})
\TText{configure} flagMacros map to release
(versioned function; \TText{H5Lvisit} shown)
Deprecated functions available?
(\TText{H5Lvisit1})
\Code{--with-default-api-version=v112}
(the default in 1.12)
1.12.x (\Code{H5Lvisit2})\TText{--with-default-api-version=v112}
(the default in 1.12)
1.12.x (\TText{H5Lvisit2}) yes
\Code{--with-default-api-version=v110}1.10.x (\Code{H5Lvisit1})\TText{--with-default-api-version=v110}1.10.x (\TText{H5Lvisit1}) yes
\Code{--with-default-api-version=v18}1.8.x (\Code{H5Lvisit1})\TText{--with-default-api-version=v18}1.8.x (\TText{H5Lvisit1}) yes
\Code{--with-default-api-version=v16}1.6.x (\Code{H5Lvisit1})\TText{--with-default-api-version=v16}1.6.x (\TText{H5Lvisit1}) yes
\Code{--disable-deprecated-symbols}1.12.x (\Code{H5Lvisit2})\TText{--disable-deprecated-symbols}1.12.x (\TText{H5Lvisit2}) no
- Refer to the file \Code{libhdf5.settings} in the directory where the HDF5 library is - installed to determine the \Code{configure} flags used to build the library. In particular, + Refer to the file \TText{libhdf5.settings} in the directory where the HDF5 library is + installed to determine the \TText{configure} flags used to build the library. In particular, look for the two lines shown here under \Emph{Features}: - \Code{Default API mapping: v112} + \TText{Default API mapping: v112} - \Code{With deprecated public symbols: yes} + \TText{With deprecated public symbols: yes} \subsection app-options Application Mapping Options When an application using HDF5 APIs is built and linked with the HDF5 library, - compile-time options to \Code{h5cc} can be used to control the API compatibility + compile-time options to \TText{h5cc} can be used to control the API compatibility macro mapping behavior exhibited by the application. The application mapping overrides the behavior specified by the library mapping, and can be overridden on a function-by-function basis by the function mappings. - If the HDF5 library was configured with the \Code{--disable-deprecated-symbols} flag, then + If the HDF5 library was configured with the \TText{--disable-deprecated-symbols} flag, then the deprecated functions will not be available, regardless of the application mapping options.
Table 2: Application Mapping Options - - - + + + - - + + - - + + - - + + - - + + - - + +
\Code{h5cc} optionMacros map to release
(versioned function; \Code{H5Lvisit} shown)
Deprecated functions available?
(\Code{H5Lvisit1})
\TText{h5cc} optionMacros map to release
(versioned function; \TText{H5Lvisit} shown)
Deprecated functions available?
(\TText{H5Lvisit1})
\Code{-DH5_USE_112_API}
\Emph{(Default behavior if no option specified.)}
1.12.x (\Code{HLvisit2})\TText{-DH5_USE_112_API}
\Emph{(Default behavior if no option specified.)}
1.12.x (\TText{HLvisit2}) yes*
\Emph{*if available in library}
\Code{-DH5_USE_110_API}1.10.x (\Code{HLvisit1})\TText{-DH5_USE_110_API}1.10.x (\TText{HLvisit1}) yes*
\Emph{*if available in library}
\Code{-DH5_USE_18_API}1.8.x (\Code{H5Lvisit1})\TText{-DH5_USE_18_API}1.8.x (\TText{H5Lvisit1}) yes*
\Emph{*if available in library}
\Code{-DH5_USE_16_API}1.6.x (\Code{H5Lvisit1})\TText{-DH5_USE_16_API}1.6.x (\TText{H5Lvisit1}) yes*
\Emph{*if available in library}
\Code{-DH5_NO_DEPRECATED_SYMBOLS}1.10.x (\Code{H5Lvisit1})\TText{-DH5_NO_DEPRECATED_SYMBOLS}1.10.x (\TText{H5Lvisit1}) no
@@ -234,15 +234,15 @@ underlying functions on a function-by-function basis. The function mappings override the library and application mappings discussed earlier. - If the HDF5 library was configured with the \Code{--disable-deprecated-symbols} - flag, or \Code{-DH5_NO_DEPRECATED_SYMBOLS} is used to compile the application, + If the HDF5 library was configured with the \TText{--disable-deprecated-symbols} + flag, or \TText{-DH5_NO_DEPRECATED_SYMBOLS} is used to compile the application, then the deprecated functions will not be available, regardless of the function mapping options. For every function with multiple available versions, a compile-time version flag can be defined to selectively map the function macro to the desired versioned function. The function mapping consists of the function name followed by - "\Code{_vers}" which is mapped by number to a specific function or + "\TText{_vers}" which is mapped by number to a specific function or struct: @@ -250,33 +250,33 @@ - - - + + + - - + +
Function Mapping Mapped to function or struct
\Code{H5xxx}\Code{H5xxx_vers=1}\Code{H5xxx1}
\TText{H5xxx}\TText{H5xxx_vers=1}\TText{H5xxx1}
\Code{H5xxx_vers=2}\Code{H5xxx2}\TText{H5xxx_vers=2}\TText{H5xxx2}
- For example, in version 1.10 the \Code{H5Rreference} macro can be mapped to - either \Code{H5Rreference1} or \Code{H5Rreference2}. When used, the value of - the \Code{H5Rreference_vers} compile-time version flag determines which + For example, in version 1.10 the \TText{H5Rreference} macro can be mapped to + either \TText{H5Rreference1} or \TText{H5Rreference2}. When used, the value of + the \TText{H5Rreference_vers} compile-time version flag determines which function will be called: \warning Please be aware that some function mappings use mapped structures, as @@ -285,10 +285,10 @@ plus EVERY function that uses the mapped structure, whether or not that function is used in the application. \Emph{In 1.12, mappings of structures are used by the H5L and H5O function mappings.}\n\n - For example, an application \Code{application.c} only calls \Code{H5Lvisit}, - \Code{H5Ovisit}, and \Code{H5Oget_info_by_name}. To compile this application + For example, an application \TText{application.c} only calls \TText{H5Lvisit}, + \TText{H5Ovisit}, and \TText{H5Oget_info_by_name}. To compile this application with 1.10 APIs in 1.12 with the function specific mappings, then not only must - \Code{H5Lvisit_vers}, \Code{H5Ovisit_vers}, and \Code{H5Oget_info_by_name_vers} + \TText{H5Lvisit_vers}, \TText{H5Ovisit_vers}, and \TText{H5Oget_info_by_name_vers} be specified on the command line, but the mapped structures and every function that uses the mapped structures must be included, as well. The full compile line is shown below: @@ -303,26 +303,26 @@ \subsubsection fun-options-112 Function Mapping Options in Releases 1.12.x - + @@ -330,14 +330,14 @@ @@ -345,14 +345,14 @@ @@ -360,14 +360,14 @@ @@ -375,14 +375,14 @@ @@ -390,14 +390,14 @@ @@ -405,28 +405,28 @@ @@ -434,14 +434,14 @@ @@ -449,13 +449,13 @@ @@ -463,14 +463,14 @@ @@ -478,12 +478,12 @@ @@ -491,12 +491,12 @@ @@ -508,84 +508,84 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
Macro
(\Code{H5xxx})
Macro
(\TText{H5xxx})
Default function used if no macro specified -
  • Function/struct mapping:\Code{H5xxx_vers=N}
+
  • Function/struct mapping:\TText{H5xxx_vers=N}
Function used if specifying 1.10 -
  • Function/struct mapping: \Code{H5xxx_vers=1}
+
  • Function/struct mapping: \TText{H5xxx_vers=1}
H5Lget_info() H5Lget_info2()
    -
  • Function mapping:\Code{H5Lget_info_vers=2}
  • -
  • Struct mapping:\Code{H5L_info_t_vers=2}
  • +
  • Function mapping:\TText{H5Lget_info_vers=2}
  • +
  • Struct mapping:\TText{H5L_info_t_vers=2}
H5Lget_info1()
    -
  • Function mapping \Code{H5Lget_info_vers=1}
  • -
  • Struct mapping: \Code{H5L_info_t_vers=1}
  • +
  • Function mapping \TText{H5Lget_info_vers=1}
  • +
  • Struct mapping: \TText{H5L_info_t_vers=1}
H5Lget_info_by_idx() H5Lget_info_by_idx2()
    -
  • Function mapping: \Code{H5Lget_info_by_idx_vers=2}
  • -
  • Struct mapping: \Code{H5L_info_t_vers=2}
  • +
  • Function mapping: \TText{H5Lget_info_by_idx_vers=2}
  • +
  • Struct mapping: \TText{H5L_info_t_vers=2}
H5Lget_info_by_idx1()
    -
  • Function mapping: \Code{H5Lget_info_by_idx_vers=1}
  • -
  • Struct mapping: \Code{H5L_info_t_vers=1}
  • +
  • Function mapping: \TText{H5Lget_info_by_idx_vers=1}
  • +
  • Struct mapping: \TText{H5L_info_t_vers=1}
H5Literate() H5Literate2()
    -
  • Function mapping: \Code{H5Literate_vers=2}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=2}
  • +
  • Function mapping: \TText{H5Literate_vers=2}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=2}
H5Literate1()
    -
  • Function mapping: \Code{H5Literate_vers=1}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=1}
  • +
  • Function mapping: \TText{H5Literate_vers=1}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=1}
H5Literate_by_name() H5Literate_by_name2()
    -
  • Function mapping: \Code{H5Literate_by_name_vers=2}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=2}
  • +
  • Function mapping: \TText{H5Literate_by_name_vers=2}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=2}
H5Literate_by_name1()
    -
  • Function mapping: \Code{H5Literate_by_name_vers=1}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=1}
  • +
  • Function mapping: \TText{H5Literate_by_name_vers=1}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=1}
H5Lvisit() H5Lvisit2()
    -
  • Function mapping: \Code{H5Lvisit_vers=2}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=2}
  • +
  • Function mapping: \TText{H5Lvisit_vers=2}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=2}
H5Lvisit1()
    -
  • Function mapping: \Code{H5Lvisit_vers=1}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=1}
  • +
  • Function mapping: \TText{H5Lvisit_vers=1}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=1}
H5Lvisit_by_name() H5Lvisit_by_name2()
    -
  • Function mapping: \Code{H5Lvisit_by_name_vers=2}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=2}
  • +
  • Function mapping: \TText{H5Lvisit_by_name_vers=2}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=2}
H5Lvisit_by_name1()
    -
  • Function mapping: \Code{H5Lvisit_by_name_vers=1}
  • -
  • Struct mapping: \Code{H5L_iterate_t_vers=1}
  • +
  • Function mapping: \TText{H5Lvisit_by_name_vers=1}
  • +
  • Struct mapping: \TText{H5L_iterate_t_vers=1}
H5Oget_info() H5Oget_info3()
    -
  • Function mapping: \Code{H5Oget_info_vers=3}
  • -
  • Struct mapping: \Code{H5O_info_t_vers=2}
  • +
  • Function mapping: \TText{H5Oget_info_vers=3}
  • +
  • Struct mapping: \TText{H5O_info_t_vers=2}
H5Oget_info1()
    -
  • Function mapping: \Code{H5Oget_info_vers=1}
  • -
  • Struct mapping: \Code{H5O_info_t_vers=1}
  • +
  • Function mapping: \TText{H5Oget_info_vers=1}
  • +
  • Struct mapping: \TText{H5O_info_t_vers=1}
H5Oget_info_by_idx() H5Oget_info_by_idx3() -
  • Function mapping: \Code{H5Oget_info_by_idx_vers=3}
  • -
  • Struct mapping: \Code{H5O_info_t_vers=2}
  • +
    • Function mapping: \TText{H5Oget_info_by_idx_vers=3}
    • +
    • Struct mapping: \TText{H5O_info_t_vers=2}
H5Oget_info_by_idx1()
    -
  • Function mapping: \Code{H5Oget_info_by_idx_vers=1}
  • -
  • Struct mapping: \Code{H5O_info_t_vers=1}
  • +
  • Function mapping: \TText{H5Oget_info_by_idx_vers=1}
  • +
  • Struct mapping: \TText{H5O_info_t_vers=1}
H5Oget_info_by_name() H5Oget_info_by_name3()
    -
  • Function mapping: \Code{H5O_get_info_by_name_vers=3}
  • -
  • Struct mapping: \Code{H5O_info_t_vers=2}
  • +
  • Function mapping: \TText{H5O_get_info_by_name_vers=3}
  • +
  • Struct mapping: \TText{H5O_info_t_vers=2}
H5Oget_info_by_name1()
    -
  • Function mapping: \Code{H5O_get_info_by_name_vers=1}
  • -
  • Struct mapping: \Code{H5O_info_t_vers=1}
  • +
  • Function mapping: \TText{H5O_get_info_by_name_vers=1}
  • +
  • Struct mapping: \TText{H5O_info_t_vers=1}
H5Ovisit() H5Ovisit3()
    -
  • Function mapping: \Code{H5Ovisit_vers=3}
  • -
  • Struct mapping: \Code{H5O_iterate_t_vers=2}
  • +
  • Function mapping: \TText{H5Ovisit_vers=3}
  • +
  • Struct mapping: \TText{H5O_iterate_t_vers=2}
H5Ovisit1() -
  • Function mapping: \Code{H5Ovisit_vers=1}
  • -
  • Struct mapping: \Code{H5O_iterate_t_vers=1}
  • +
    • Function mapping: \TText{H5Ovisit_vers=1}
    • +
    • Struct mapping: \TText{H5O_iterate_t_vers=1}
H5Ovisit_by_name() H5Ovisit_by_name3()
    -
  • Function mapping: \Code{H5Ovisit_by_name_vers=3}
  • -
  • Struct mapping: \Code{H5O_iterate_t_vers=2}
  • +
  • Function mapping: \TText{H5Ovisit_by_name_vers=3}
  • +
  • Struct mapping: \TText{H5O_iterate_t_vers=2}
H5Ovisit_by_name1()
    -
  • Function mapping: \Code{H5Ovisit_by_name_vers=1}
  • -
  • Struct mapping: \Code{H5O_iterate_t_vers=1}
  • +
  • Function mapping: \TText{H5Ovisit_by_name_vers=1}
  • +
  • Struct mapping: \TText{H5O_iterate_t_vers=1}
H5Pencode() H5Pencode2()
    -
  • Function mapping: \Code{H5Pencode_vers=2}
  • +
  • Function mapping: \TText{H5Pencode_vers=2}
H5Pencode1()
    -
  • Function mapping: \Code{H5Pencode_vers=1}
  • +
  • Function mapping: \TText{H5Pencode_vers=1}
H5Sencode() H5Sencode2()
    -
  • Function mapping: \Code{H5Sencode_vers=2}
  • +
  • Function mapping: \TText{H5Sencode_vers=2}
H5Sencode1()
    -
  • Function mapping: \Code{H5Sencode_vers=1}
  • +
  • Function mapping: \TText{H5Sencode_vers=1}
Macro Default function used
(if no macro specified)
Introduced in\Code{h5cc} version flag and value\TText{h5cc} version flag and value Mapped to function or struct
H5Rdereference() H5Rdereference2() HDF5-1.10.0\Code{-DH5Rdereference_vers=1}\TText{-DH5Rdereference_vers=1} H5Rdereference1()
\Code{-DH5Rdereference_vers=2}\TText{-DH5Rdereference_vers=2} H5Rdereference2()
H5Fget_info() H5Fget_info2() HDF5-1.10.0\Code{-DH5Fget_info_vers=1}\TText{-DH5Fget_info_vers=1} H5Fget_info1() with struct \ref H5F_info1_t
\Code{-DH5Fget_info_vers=2}\TText{-DH5Fget_info_vers=2} H5Fget_info2() with struct \ref H5F_info2_t
H5Oget_info() H5Oget_info1() HDF5-1.10.3\Code{-DH5Oget_info_vers=1}\TText{-DH5Oget_info_vers=1} H5Oget_info1()
\Code{-DH5Oget_info_vers=2}\TText{-DH5Oget_info_vers=2} H5Oget_info2()
H5Oget_info_by_idx() H5Oget_info_by_idx1() HDF5-1.10.3\Code{-DH5Oget_info_by_idx_vers=1}\TText{-DH5Oget_info_by_idx_vers=1} H5Oget_info_by_idx1()
\Code{-DH5Oget_info_by_idx_vers=2}\TText{-DH5Oget_info_by_idx_vers=2} H5Oget_info_by_idx2()
H5Oget_info_by_name() H5Oget_info_by_name1() HDF5-1.10.3\Code{-DH5Oget_info_by_name_vers=1}\TText{-DH5Oget_info_by_name_vers=1} H5Oget_info_by_name1()
\Code{-DH5Oget_info_by_name_vers=2}\TText{-DH5Oget_info_by_name_vers=2} H5Oget_info_by_name2()
H5Ovisit() H5Ovisit1() HDF5-1.10.3\Code{-DH5Ovisit_vers=1}\TText{-DH5Ovisit_vers=1} H5Ovisit1()
\Code{-DH5Ovisit_vers=2}\TText{-DH5Ovisit_vers=2} H5Ovisit2()
H5Ovisit_by_name() H5Ovisit_by_name1() HDF5-1.10.3\Code{-DH5Ovisit_by_name_vers=1}\TText{-DH5Ovisit_by_name_vers=1} H5Ovisit_by_name1()
\Code{-DH5Ovisit_by_name_vers=2}\TText{-DH5Ovisit_by_name_vers=2} H5Ovisit_by_name2()
@@ -606,208 +606,208 @@ H5Acreate() - \Code{DH5Acreate_vers=1} + \TText{DH5Acreate_vers=1} H5Acreate1() - \Code{DH5Acreate_vers=2} + \TText{DH5Acreate_vers=2} H5Acreate2() H5Aiterate() - \Code{DH5Aiterate_vers=1} + \TText{DH5Aiterate_vers=1} H5Aiterate1()
with struct \ref H5A_operator1_t - \Code{DH5Aiterate_vers=2} + \TText{DH5Aiterate_vers=2} H5Aiterate2()
with struct \ref H5A_operator2_t H5Dcreate() - \Code{DH5Dcreate_vers=1} + \TText{DH5Dcreate_vers=1} H5Dcreate1() - \Code{DH5Dcreate_vers=2} + \TText{DH5Dcreate_vers=2} H5Dcreate2() H5Dopen() - \Code{DH5Dopen_vers=1} + \TText{DH5Dopen_vers=1} H5Dopen1() - \Code{DH5Dopen_vers=2} + \TText{DH5Dopen_vers=2} H5Dopen2() H5Eclear() - \Code{DH5Eclear_vers=1} + \TText{DH5Eclear_vers=1} H5Eclear1() - \Code{DH5Eclear_vers=2} + \TText{DH5Eclear_vers=2} H5Eclear2() H5Eprint() - \Code{DH5Eprint_vers=1} + \TText{DH5Eprint_vers=1} H5Eprint1() - \Code{DH5Eprint_vers=2} + \TText{DH5Eprint_vers=2} H5Eprint2() H5Epush() - \Code{DH5Epush_vers=1} + \TText{DH5Epush_vers=1} H5Epush1() - \Code{DH5Epush_vers=2} + \TText{DH5Epush_vers=2} H5Epush2() H5Eset_auto() - \Code{DH5Eset_auto_vers=1} + \TText{DH5Eset_auto_vers=1} H5Eset_auto1() - \Code{DH5Eset_auto_vers=2} + \TText{DH5Eset_auto_vers=2} H5Eset_auto2() H5Eget_auto() - \Code{DH5Eget_auto_vers=1} + \TText{DH5Eget_auto_vers=1} H5Eget_auto1() - \Code{DH5Eget_auto_vers=2} + \TText{DH5Eget_auto_vers=2} H5Eget_auto2() \ref H5E_auto_t
struct for H5Eset_auto()
and H5Eget_auto() - \Code{DH5E_auto_t_vers=1} + \TText{DH5E_auto_t_vers=1} \ref H5E_auto1_t - \Code{DH5E_auto_t_vers=2} + \TText{DH5E_auto_t_vers=2} \ref H5E_auto2_t H5Ewalk() - \Code{DH5Ewalk_vers=1} + \TText{DH5Ewalk_vers=1} H5Ewalk1()
with callback \ref H5E_walk1_t
and struct \ref H5E_error1_t - \Code{DH5Ewalk_vers=2} + \TText{DH5Ewalk_vers=2} H5Ewalk2()
with callback \ref H5E_walk2_t
and struct \ref H5E_error2_t H5Gcreate() - \Code{DH5Gcreate_vers=1} + \TText{DH5Gcreate_vers=1} H5Gcreate1() - \Code{DH5Gcreate_vers=2} + \TText{DH5Gcreate_vers=2} H5Gcreate2() H5Gopen() - \Code{DH5Gopen_vers=1} + \TText{DH5Gopen_vers=1} H5Gopen1() - \Code{DH5Gopen_vers=2} + \TText{DH5Gopen_vers=2} H5Gopen2() H5Pget_filter() - \Code{DH5Pget_filter_vers=1} + \TText{DH5Pget_filter_vers=1} H5Pget_filter1() - \Code{DH5Pget_filter_vers=2} + \TText{DH5Pget_filter_vers=2} H5Pget_filter2() H5Pget_filter_by_id() - \Code{DH5Pget_filter_by_id_vers=1} + \TText{DH5Pget_filter_by_id_vers=1} H5Pget_filter_by_id1() - \Code{DH5Pget_filter_by_id_vers=2} + \TText{DH5Pget_filter_by_id_vers=2} H5Pget_filter_by_id2() H5Pinsert() - \Code{DH5Pinsert_vers=1} + \TText{DH5Pinsert_vers=1} H5Pinsert1() - \Code{DH5Pinsert_vers=2} + \TText{DH5Pinsert_vers=2} H5Pinsert2() H5Pregister() - \Code{DH5Pregister_vers=1} + \TText{DH5Pregister_vers=1} H5Pregister1() - \Code{DH5Pregister_vers=2} + \TText{DH5Pregister_vers=2} H5Pregister2() H5Rget_obj_type() - \Code{DH5Rget_obj_typevers=1} + \TText{DH5Rget_obj_typevers=1} H5Rget_obj_type1() - \Code{DH5Rget_obj_type_vers=2} + \TText{DH5Rget_obj_type_vers=2} H5Rget_obj_type2() H5Tarray_create() - \Code{DH5Tarray_create_vers=1} + \TText{DH5Tarray_create_vers=1} H5Tarray_create1() - \Code{DH5Tarray_create_vers=2} + \TText{DH5Tarray_create_vers=2} H5Tarray_create2() H5Tcommit() - \Code{DH5Tcommit_vers=1} + \TText{DH5Tcommit_vers=1} H5Tcommit1() - \Code{DH5Tcommit_vers=2} + \TText{DH5Tcommit_vers=2} H5Tcommit2() H5Tget_array_dims() - \Code{DH5Tget_array_dims_vers=1} + \TText{DH5Tget_array_dims_vers=1} H5Tget_array_dims1() - \Code{DH5Tget_array_dims_vers=2} + \TText{DH5Tget_array_dims_vers=2} H5Tget_array_dims2() H5Topen() - \Code{DH5Topen_vers=1} + \TText{DH5Topen_vers=1} H5Topen1() - \Code{DH5Topen_vers=2} + \TText{DH5Topen_vers=2} H5Topen2() \ref H5Z_class_t struct for H5Zregister() - \Code{DH5Z_class_t_vers=1} + \TText{DH5Z_class_t_vers=1} \ref H5Z_class1_t - \Code{DH5Z_class_t_vers=2} + \TText{DH5Z_class_t_vers=2} \ref H5Z_class2_t @@ -819,8 +819,8 @@ h5cc ... -DH5Rdereference_vers=1 -DH5Fget_info_vers=2 ... \endcode As a result of the function and struct mappings in this compile example, all - occurrences of the macro \Code{H5Rdereference} will be mapped to \Code{H5Rdereference1} - and all occurrences of the macro \Code{H5Fget_info} will be mapped to \Code{H5Fget_info2} + occurrences of the macro \TText{H5Rdereference} will be mapped to \TText{H5Rdereference1} + and all occurrences of the macro \TText{H5Fget_info} will be mapped to \TText{H5Fget_info2} for the application being built. The function and struct mappings can be used to guarantee that a given API compatibility @@ -832,17 +832,17 @@ As noted earlier, the function mappings can only reference versioned functions that are included in the HDF5 library, as determined by the configure flag used to build the library. For example, if the HDF5 library being linked with the application was built - with the \Code{--disable-deprecated-symbols} option, version 1 of the underlying functions - would not be available, and the example above that defined \Code{H5Rdereference_vers=1} + with the \TText{--disable-deprecated-symbols} option, version 1 of the underlying functions + would not be available, and the example above that defined \TText{H5Rdereference_vers=1} would not be supported. - The function mappings do not negate any available functions. If \Code{H5Rdereference1} + The function mappings do not negate any available functions. If \TText{H5Rdereference1} is available in the installed version of the HDF5 library, and the application was not - compiled with the \Code{-DH5_NO_DEPRECATED_SYMBOLS} flag, the function \Code{H5Rdereference1} + compiled with the \TText{-DH5_NO_DEPRECATED_SYMBOLS} flag, the function \TText{H5Rdereference1} will remain available to the application through its versioned name. Similarly, - \Code{H5Rdereference2} will remain available to the application as \Code{H5Rdereference2}. - The function mapping version flag \Code{H5Rdereference_vers} only controls the mapping of - the API compatibility macro \Code{H5Rdereference} to one of the two available functions. + \TText{H5Rdereference2} will remain available to the application as \TText{H5Rdereference2}. + The function mapping version flag \TText{H5Rdereference_vers} only controls the mapping of + the API compatibility macro \TText{H5Rdereference} to one of the two available functions. This can be especially useful in any case where the programmer does not have direct control over global macro definitions, such as when writing code meant to be copied to multiple @@ -857,8 +857,8 @@ These macros were strictly a forward-looking feature at that time; they were not necessary for compatibility in 1.6.x. These macros were created at that time to enable writing code that could be used with any version of the library after 1.6.8 - and any library compilation options except \Code{H5_NO_DEPRECATED_SYMBOLS}, by always - using the '1' version of versioned functions and types. For example, \Code{H5Dopen1} + and any library compilation options except \TText{H5_NO_DEPRECATED_SYMBOLS}, by always + using the '1' version of versioned functions and types. For example, \TText{H5Dopen1} will always be interpreted in exactly the same manner by any version of the library since 1.6.8. @@ -867,23 +867,23 @@ of an existing application to a new HDF5 release. An incremental migration plan is outlined here:
    -
  1. Build the HDF5 library without specifying any library mapping \Code{configure} +
  2. Build the HDF5 library without specifying any library mapping \TText{configure} flag. In this default mode, the 1.6.x, 1.8.x, and 1.10.x versions of the underlying functions are available, and the API compatibility macros will be mapped to the current HDF5 versioned functions.
  3. -
  4. Compile the application with the \Code{-DH5_USE_NN_API} application mapping +
  5. Compile the application with the \TText{-DH5_USE_NN_API} application mapping option if it was written for use with an earlier HDF5 library. Because the application mapping overrides the library mapping, the macros will all be mapped to the earlier versions of the functions.
  6. Remap one API compatibility macro at a time (or sets of macros), to use the current HDF5 versions. At each stage, use the function mappings to map the macros being worked on to the current versions. For example, use the - \Code{-DH5Rdereference_vers=2} version flag setting to remap the \Code{H5Rdereference} - macro to \Code{H5Rdereference2}, the 1.10.x version. + \TText{-DH5Rdereference_vers=2} version flag setting to remap the \TText{H5Rdereference} + macro to \TText{H5Rdereference2}, the 1.10.x version. During this step, the application code will need to be modified to change the calling parameters used with the API compatibility macros to match the number and type - of the 1.10.x versioned functions. The macro name, for example \Code{H5Rdereference}, + of the 1.10.x versioned functions. The macro name, for example \TText{H5Rdereference}, should continue to be used in the code, to allow for possible re-mappings to later versioned functions in a future release.
  7. After all macros have been migrated to the latest versioned functions in step 3, @@ -891,8 +891,8 @@ uses the library mappings set in step 1, and maps API compatibility macros to the latest versions.
  8. Finally, compile the application with the application mapping - \Code{-DH5_NO_DEPRECATED_SYMBOLS}, and address any failures to complete + \TText{-DH5_NO_DEPRECATED_SYMBOLS}, and address any failures to complete the application migration process.
- */ \ No newline at end of file + */ diff --git a/doxygen/dox/cookbook/Files.dox b/doxygen/dox/cookbook/Files.dox index 489377153a0..4b133a615cb 100644 --- a/doxygen/dox/cookbook/Files.dox +++ b/doxygen/dox/cookbook/Files.dox @@ -20,7 +20,7 @@ free space tracking information via H5Pset_file_space_strategy(). Free space tracking is supported only in HDF5 versions 1.10.x and higher. This has implications for the accessibility of your HDF5 files and should be considered carefully. If compatibility with previous versions of -HDF5 must be maintained, space reclamation via \Code{h5repack} might be an option.\n +HDF5 must be maintained, space reclamation via \TText{h5repack} might be an option.\n The file space strategy #H5F_FSPACE_STRATEGY_FSM_AGGR is not the only option that supports free-space tracking. #H5F_FSPACE_STRATEGY_PAGE is another option, which adds paged allocation and is used most effectively with page buffering.\n @@ -37,7 +37,7 @@ See \ref CB_MaintainCompat for HDF5 compatibility implications. \subsection CB_RemoveUnusedSpace Removing Unused Space from HDF5 Files \par Problem -Based on estimates or \Code{h5stat} output you know that a large portion +Based on estimates or \TText{h5stat} output you know that a large portion of an HDF5 file consists of free or unaccounted space, and you would like to remove it. @@ -58,7 +58,7 @@ The user block begins at offset 0 and must be at least 512 bytes and a power of 2. The HDF5 library ignores any content between the beginning of the file and the end of the user block.\n You can add or strip a user block to/from an existing HDF5 file with the -\Code{h5jam}/\Code{h5unjam} tool, respectively. +\TText{h5jam}/\TText{h5unjam} tool, respectively. \warning If you try to embed content into the user block for use by other applications, pay close attention to how they handle space beyond the last used byte in the @@ -68,4 +68,4 @@ try to truncate the rest of the file and destroy the HDF5 portion of the file. \par See Also References to related recipes - */ \ No newline at end of file + */ diff --git a/doxygen/dox/rm-template.dox b/doxygen/dox/rm-template.dox index 003d5c4b862..ad5e8387c19 100644 --- a/doxygen/dox/rm-template.dox +++ b/doxygen/dox/rm-template.dox @@ -41,8 +41,8 @@ the *
  • Let \c root denote a valid HDF5 group identifier that refers to the * root group of an HDF5 file, and let \c lapl denote a valid link * access property list identifier. A call to H5Lexists() with * arguments c root, \c "/", and \c lapl returns a positive value; - * in other words, \Code{H5Lexists(root, "/", lapl)} returns a positive + * in other words, \TText{H5Lexists(root, "/", lapl)} returns a positive * value. In the HDF5 1.8 release, this function returns 0.
  • * * Note that the function accepts link names and path names. This is diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 724893484a2..320f55d9368 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -480,7 +480,7 @@ typedef enum H5D_mpio_no_collective_cause_t { H5D_MPIO_DATA_TRANSFORMS = 0x04, /**< Collective I/O was not performed because data transforms needed to be applied */ H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED = 0x08, - /**< Collective I/O was disabled by environment variable (\Code{HDF5_MPI_OPT_TYPES}) */ + /**< Collective I/O was disabled by environment variable (\TText{HDF5_MPI_OPT_TYPES}) */ H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES = 0x10, /**< Collective I/O was not performed because one of the dataspaces was neither simple nor scalar */ H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET = 0x20, @@ -1350,15 +1350,15 @@ H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size); * modified * * - * \Code{const char * name} + * \TText{const char * name} * IN: The name of the property being modified * * - * \Code{size_t size} + * \TText{size_t size} * IN: The size of the property in bytes * * - * \Code{void * value} + * \TText{void * value} * IN: Pointer to new value pointer for the property * being modified * @@ -1393,15 +1393,15 @@ H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size); * IN: The identifier of the property list being queried * * - * \Code{const char * name} + * \TText{const char * name} * IN: The name of the property being queried * * - * \Code{size_t size} + * \TText{size_t size} * IN: The size of the property in bytes * * - * \Code{void * value} + * \TText{void * value} * IN: The value of the property being returned * * @@ -1426,15 +1426,15 @@ H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size); * being deleted from * * - * \Code{const char * name} + * \TText{const char * name} * IN: The name of the property in the list * * - * \Code{size_t size} + * \TText{size_t size} * IN: The size of the property in bytes * * - * \Code{void * value} + * \TText{void * value} * IN: The value for the property being deleted * * @@ -1455,15 +1455,15 @@ H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size); * The parameters to the above callback function are: * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const char * name}\TText{const char * name}IN: The name of the property being copied
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void * value}\TText{void * value}IN/OUT: The value for the property being copied
    @@ -1487,15 +1487,15 @@ H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size); * * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const void * value1}\TText{const void * value1}IN: The value of the first property to compare
    \Code{const void * value2}\TText{const void * value2}IN: The value of the second property to compare
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    @@ -1515,15 +1515,15 @@ H5_DLL herr_t H5Pget_size(hid_t id, const char *name, size_t *size); * * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const char * name}\TText{const char * name}IN: The name of the property in the list
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void * value}\TText{void * value}IN: The value for the property being closed
    @@ -1667,15 +1667,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * * * - * + * * * * - * + * * * * - * + * * * @@ -1701,15 +1701,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * * * - * + * * * * - * + * * * * - * + * * * @@ -1745,15 +1745,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * queried * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const char * name}\TText{const char * name}IN: The name of the property being modified
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void * value}\TText{void * value}IN/OUT: The default value for the property being created, * which will be passed to H5Pregister2()
    IN: The identifier of the property list being modified
    \Code{const char * name}\TText{const char * name}IN: The name of the property being modified
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void *value}\TText{void *value}IN/OUT: Pointer to new value pointer for the property * being modified
    \Code{const char * name}\TText{const char * name}IN: The name of the property being queried
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void * value}\TText{void * value}IN/OUT: The value of the property being returned
    @@ -1778,15 +1778,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * being deleted from * * - * \Code{const char * name} + * \TText{const char * name} * IN: The name of the property in the list * * - * \Code{size_t size} + * \TText{size_t size} * IN: The size of the property in bytes * * - * \Code{void * value} + * \TText{void * value} * IN: The value for the property being deleted * * @@ -1807,15 +1807,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const char * name}\TText{const char * name}IN: The name of the property being copied
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void * value}\TText{void * value}IN/OUT: The value for the property being copied
    @@ -1837,15 +1837,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const void * value1}\TText{const void * value1}IN: The value of the first property to compare
    \Code{const void * value2}\TText{const void * value2}IN: The value of the second property to compare
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    @@ -1865,15 +1865,15 @@ H5_DLL int H5Piterate(hid_t id, int *idx, H5P_iterate_t iter_func, void *iter_da * * * - * + * * * * - * + * * * * - * + * * * *
    \Code{const char * name}\TText{const char * name}IN: The name of the property in the list
    \Code{size_t size}\TText{size_t size}IN: The size of the property in bytes
    \Code{void * value}\TText{void * value}IN: The value for the property being closed
    @@ -2204,7 +2204,7 @@ H5_DLL herr_t H5Pget_filter_by_id2(hid_t plist_id, H5Z_filter_t filter_id, unsig * \details H5Pget_nfilters() returns the number of filters defined in the * filter pipeline associated with the property list \p plist_id. * - * In each pipeline, the filters are numbered from 0 through \Code{N-1}, + * In each pipeline, the filters are numbered from 0 through \TText{N-1}, * where \c N is the value returned by this function. During output to * the file, the filters are applied in increasing order; during * input from the file, they are applied in decreasing order. @@ -2821,7 +2821,7 @@ H5_DLL herr_t H5Pset_fletcher32(hid_t plist_id); * return it in the #H5O_info_t struct. * * If times are not tracked, they will be reported as follows when queried: - * \Code{ 12:00 AM UDT, Jan. 1, 1970} + * \TText{ 12:00 AM UDT, Jan. 1, 1970} * * That date and time are commonly used to represent the beginning of the UNIX epoch. * @@ -3674,17 +3674,17 @@ H5_DLL herr_t H5Pget_fclose_degree(hid_t fapl_id, H5F_close_degree_t *degree); * \param[in,out] buf_ptr_ptr On input, \c NULL or a pointer to a * pointer to a buffer that contains the * file image.\n On successful return, if \p buf_ptr_ptr is not - * \c NULL, \Code{*buf_ptr_ptr} will contain a pointer to a copy + * \c NULL, \TText{*buf_ptr_ptr} will contain a pointer to a copy * of the initial image provided in the last call to * H5Pset_file_image() for the supplied \p fapl_id. If no initial - * image has been set, \Code{*buf_ptr_ptr} will be \c NULL. + * image has been set, \TText{*buf_ptr_ptr} will be \c NULL. * \param[in,out] buf_len_ptr On input, \c NULL or a pointer to a buffer * specifying the required size of the buffer to hold the file * image.\n On successful return, if \p buf_len_ptr was not * passed in as \c NULL, \p buf_len_ptr will return the required * size in bytes of the buffer to hold the initial file image in * the supplied file access property list, \p fapl_id. If no - * initial image is set, the value of \Code{*buf_len_ptr} will be + * initial image is set, the value of \TText{*buf_len_ptr} will be * set to 0 (zero) * \return \herr_t * @@ -3850,7 +3850,7 @@ H5_DLL herr_t H5Pget_libver_bounds(hid_t plist_id, H5F_libver_t *low, H5F_libver * instance of #H5AC_cache_config_t pointed to by the \p config_ptr * parameter. This configuration is used when the file is opened. * - * Note that the version field of \Code{*config_ptr} must be + * Note that the version field of \TText{*config_ptr} must be * initialized; this allows the library to support earlier versions of * the #H5AC_cache_config_t structure. * @@ -5232,7 +5232,7 @@ H5_DLL herr_t H5Pset_mdc_log_options(hid_t plist_id, hbool_t is_enabled, const c * * The default setting is 2048 bytes, meaning that the library will * attempt to aggregate metadata in at least 2K blocks in the file. - * Setting the value to zero (\Code{0}) with this function will turn + * Setting the value to zero (\TText{0}) with this function will turn * off metadata aggregation, even if the VFL driver attempts to use the * metadata aggregation strategy. * @@ -5250,12 +5250,12 @@ H5_DLL herr_t H5Pset_meta_block_size(hid_t fapl_id, hsize_t size); * \brief Sets the number of read attempts in a file access property list * * \fapl_id{plist_id} - * \param[in] attempts The number of read attempts. Must be a value greater than \Code{0} + * \param[in] attempts The number of read attempts. Must be a value greater than \TText{0} * * \return \herr_t * * \return Failure Modes: - * - When the user sets the number of read attempts to \Code{0}. + * - When the user sets the number of read attempts to \TText{0}. * - When the input property list is not a file access property list. * - When the library is unable to set the number of read attempts in the file access property list. * @@ -5273,11 +5273,11 @@ H5_DLL herr_t H5Pset_meta_block_size(hid_t fapl_id, hsize_t size); * opened and whether the user sets the number of read attempts via this routine: * - For a file opened with SWMR access: - * - If the user sets the number of attempts to \Code{N}, the library will use \Code{N}. + * - If the user sets the number of attempts to \TText{N}, the library will use \TText{N}. * - If the user does not set the number of attempts, the library will use the - * default for SWMR access (\Code{100}). + * default for SWMR access (\TText{100}). * - For a file opened with non-SWMR access, the library will always use the default - * for non-SWMR access (\Code{1}). The value set via this routine does not have any effect + * for non-SWMR access (\TText{1}). The value set via this routine does not have any effect * during non-SWMR access. * * \b Example: The first example illustrates the case in setting the number of read attempts for a file @@ -5304,7 +5304,7 @@ H5_DLL herr_t H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts); /** * \ingroup FAPL * - * \brief Specifies type of data to be accessed via the \Code{MULTI} driver, + * \brief Specifies type of data to be accessed via the \TText{MULTI} driver, * enabling more direct access * * \fapl_id{fapl_id} @@ -5316,7 +5316,7 @@ H5_DLL herr_t H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts); * access property list \p fapl_id. This setting enables a user * application to specify the type of data the application wishes to * access so that the application can retrieve a file handle for - * low-level access to the particular member of a set of \Code{MULTI} + * low-level access to the particular member of a set of \TText{MULTI} * files in which that type of data is stored. The file handle is * retrieved with a separate call to H5Fget_vfd_handle() (or, in special * circumstances, to H5FDget_vfd_handle(); see \ref VFL. @@ -5345,7 +5345,7 @@ H5_DLL herr_t H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts); * * * This function is for use only when accessing an HDF5 file written as a set of - * files with the \Code{MULTI} file driver. + * files with the \TText{MULTI} file driver. * * \since 1.6.0 */ @@ -5372,8 +5372,8 @@ H5_DLL herr_t H5Pset_multi_type(hid_t fapl_id, H5FD_mem_t type); * \endcode * * The parameters of the callback function, per the above prototypes, are defined as follows: - * - \Code{object_id} is the identifier of the object which has just been flushed. - * - \Code{user_data} is the user-defined input data for the callback function. + * - \TText{object_id} is the identifier of the object which has just been flushed. + * - \TText{user_data} is the user-defined input data for the callback function. * * \b Example: The example below illustrates the usage of this routine to set * the callback function to invoke when an object flush occurs. @@ -5404,7 +5404,7 @@ H5_DLL herr_t H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void * * * The default value is set to 64KB, indicating that file I/O for raw * data reads and writes will occur in at least 64KB blocks. Setting - * the value to zero (\Code{0}) with this API function will turn off + * the value to zero (\TText{0}) with this API function will turn off * the data sieving, even if the VFL driver attempts to use that * strategy. * @@ -5413,7 +5413,7 @@ H5_DLL herr_t H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void * * access property and the size of the dataset to allocate the sieve * buffer for the dataset in order to save memory usage. * - * \version 1.6.0 The \p size parameter has changed from type \Code{hsize_t} to \Code{size_t}. + * \version 1.6.0 The \p size parameter has changed from type \TText{hsize_t} to \TText{size_t}. * * \since 1.4.0 */ @@ -5425,7 +5425,7 @@ H5_DLL herr_t H5Pset_sieve_buf_size(hid_t fapl_id, size_t size); * * \fapl_id{fapl_id} * \param[in] size Maximum size, in bytes, of the small data block. - The default size is \Code{2048}. + The default size is \TText{2048}. * * \return \herr_t * @@ -5451,7 +5451,7 @@ H5_DLL herr_t H5Pset_sieve_buf_size(hid_t fapl_id, size_t size); * The small data block size is set as an allocation property in the * file access property list identified by \p fapl_id. * - * Setting \p size to zero (\Code{0}) disables the small data block mechanism. + * Setting \p size to zero (\TText{0}) disables the small data block mechanism. * * \since 1.4.4 */ @@ -5512,8 +5512,8 @@ H5_DLL herr_t H5Pget_vol_cap_flags(hid_t plist_id, uint64_t *cap_flags); * * \gacpl_id * \param[in] is_collective Boolean value indicating whether metadata reads are collective - * (\Code{1}) or independent (\Code{0}). - * Default mode: Independent (\Code{0}) + * (\TText{1}) or independent (\TText{0}). + * Default mode: Independent (\TText{0}) * * \return \herr_t * @@ -5521,9 +5521,9 @@ H5_DLL herr_t H5Pget_vol_cap_flags(hid_t plist_id, uint64_t *cap_flags); * operations in the access property list \p plist_id. * * When engaging in parallel I/O, all metadata write operations must be - * collective. If \p is_collective is \Code{1}, this property specifies + * collective. If \p is_collective is \TText{1}, this property specifies * that the HDF5 library will perform all metadata read operations - * collectively; if \p is_collective is \Code{0}, such operations may + * collectively; if \p is_collective is \TText{0}, such operations may * be performed independently. * * Users must be aware that several HDF5 operations can potentially @@ -5563,7 +5563,7 @@ H5_DLL herr_t H5Pget_vol_cap_flags(hid_t plist_id, uint64_t *cap_flags); * cache and HDF5 library behavior will be undefined when both of the following * conditions exist: * - A file is created or opened with a file access property list in which the - * collective metadata I/O property is set to \Code{1}. + * collective metadata I/O property is set to \TText{1}. * - Any function is called that triggers an independent metadata read while the * file remains open with that file access property list. * @@ -5581,8 +5581,8 @@ H5_DLL herr_t H5Pset_all_coll_metadata_ops(hid_t plist_id, hbool_t is_collective * * \gacpl_id * \param[out] is_collective Pointer to a buffer containing the Boolean value indicating whether metadata - * reads are collective (\Code{>0}) or independent (\Code{0}). - * Default mode: Independent (\Code{0}) + * reads are collective (\TText{>0}) or independent (\TText{0}). + * Default mode: Independent (\TText{0}) * * \return \herr_t * @@ -5601,8 +5601,8 @@ H5_DLL herr_t H5Pget_all_coll_metadata_ops(hid_t plist_id, hbool_t *is_collectiv * * \fapl_id{plist_id} * \param[out] is_collective Boolean value indicating whether metadata - * writes are collective (\Code{>0}) or independent (\Code{0}). - * \Emph{Default mode:} Independent (\Code{0}) + * writes are collective (\TText{>0}) or independent (\TText{0}). + * \Emph{Default mode:} Independent (\TText{0}) * \return \herr_t * * \details H5Pset_coll_metadata_write() tells the HDF5 library whether to @@ -5630,8 +5630,8 @@ H5_DLL herr_t H5Pset_coll_metadata_write(hid_t plist_id, hbool_t is_collective); * * \fapl_id{plist_id} * \param[out] is_collective Pointer to a boolean value indicating whether - * metadata writes are collective (\Code{>0}) or independent (\Code{0}). - * \Emph{Default mode:} Independent (\Code{0}) + * metadata writes are collective (\TText{>0}) or independent (\TText{0}). + * \Emph{Default mode:} Independent (\TText{0}) * \return \herr_t * * \details H5Pget_coll_metadata_write() retrieves the collective metadata write @@ -5721,7 +5721,7 @@ H5_DLL herr_t H5Pset_mpi_params(hid_t fapl_id, MPI_Comm comm, MPI_Info info); * #H5AC_cache_image_config_t::entry_ageout should address this problem. In * the interim, not requesting a cache image every n file close/open cycles * may be an acceptable work around. The choice of \c n will be driven by - * application behavior, but \Code{n = 10} seems a good starting point. + * application behavior, but \TText{n = 10} seems a good starting point. * * \since 1.10.1 */ @@ -7073,7 +7073,7 @@ H5_DLL herr_t H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels * \param[in] vspace_id The dataspace identifier with the selection within the * virtual dataset applied, possibly an unlimited selection * \param[in] src_file_name The name of the HDF5 file where the source dataset is - * located or a \Code{"."} (period) for a source dataset in the same + * located or a \TText{"."} (period) for a source dataset in the same * file. The file might not exist yet. The name can be specified using * a C-style \c printf statement as described below. * \param[in] src_dset_name The path to the HDF5 dataset in the file specified by @@ -7096,14 +7096,14 @@ H5_DLL herr_t H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels * treated as literals except for the following substitutions: * * - * - * + * + * * * * * *
    \Code{"%%"}Replaced with a single \Code{"%"} (percent) character.\TText{"%%"}Replaced with a single \TText{"%"} (percent) character.
    "%b"Where "" is the virtual dataset dimension axis (0-based) - * and \Code{"b"} indicates that the block count of the selection in that - * dimension should be used. The full expression (for example, \Code{"%0b"}) + * and \TText{"b"} indicates that the block count of the selection in that + * dimension should be used. The full expression (for example, \TText{"%0b"}) * is replaced with a single numeric value when the mapping is evaluated at * VDS access time. Example code for many source and virtual dataset mappings * is available in the "Examples of Source to Virtual Dataset Mapping" @@ -7120,7 +7120,7 @@ H5_DLL herr_t H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels * When a source dataset residing in a different file is accessed, the * library will search for the source file \p src_file_name as described * below: - * \li If \p src_file_name is a \Code{"."} (period) then it refers to the + * \li If \p src_file_name is a \TText{"."} (period) then it refers to the * file containing the virtual dataset. * \li If \p src_file_name is a relative pathname, the following steps are * performed: @@ -7149,37 +7149,37 @@ H5_DLL herr_t H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels * Note that \p src_file_name is considered to be an absolute pathname when * the following condition is true: * \li For Unix, the first character of \p src_file_name is a slash - * (\Code{/}).\n For example, consider a \p src_file_name of - * \Code{/tmp/A.h5}. If that source file does not exist, the new - * \p src_file_name after stripping will be \Code{A.h5}. + * (\TText{/}).\n For example, consider a \p src_file_name of + * \TText{/tmp/A.h5}. If that source file does not exist, the new + * \p src_file_name after stripping will be \TText{A.h5}. * \li For Windows, there are 6 cases: * 1. \p src_file_name is an absolute drive with absolute pathname.\n - * For example, consider a \p src_file_name of \Code{/tmp/A.h5}. + * For example, consider a \p src_file_name of \TText{/tmp/A.h5}. * If that source file does not exist, the new \p src_file_name - * after stripping will be \Code{A.h5}. + * after stripping will be \TText{A.h5}. * 2. \p src_file_name is an absolute pathname without specifying * drive name.\n For example, consider a \p src_file_name of - * \Code{/tmp/A.h5}. If that source file does not exist, the new - * \p src_file_name after stripping will be \Code{A.h5}. + * \TText{/tmp/A.h5}. If that source file does not exist, the new + * \p src_file_name after stripping will be \TText{A.h5}. * 3. \p src_file_name is an absolute drive with relative pathname.\n - * For example, consider a \p src_file_name of \Code{/tmp/A.h5}. + * For example, consider a \p src_file_name of \TText{/tmp/A.h5}. * If that source file does not exist, the new \p src_file_name - * after stripping will be \Code{tmp/A.h5}. + * after stripping will be \TText{tmp/A.h5}. * 4. \p src_file_name is in UNC (Uniform Naming Convention) format * with server name, share name, and pathname.\n - * For example, consider a \p src_file_name of \Code{/tmp/A.h5}. + * For example, consider a \p src_file_name of \TText{/tmp/A.h5}. * If that source file does not exist, the new \p src_file_name - * after stripping will be \Code{A.h5}. + * after stripping will be \TText{A.h5}. * 5. \p src_file_name is in Long UNC (Uniform Naming Convention) * format with server name, share name, and pathname.\n - * For example, consider a \p src_file_name of \Code{/tmp/A.h5}. + * For example, consider a \p src_file_name of \TText{/tmp/A.h5}. * If that source file does not exist, the new \p src_file_name - * after stripping will be \Code{A.h5}. + * after stripping will be \TText{A.h5}. * 6. \p src_file_name is in Long UNC (Uniform Naming Convention) * format with an absolute drive and an absolute pathname.\n - * For example, consider a \p src_file_name of \Code{/tmp/A.h5}. + * For example, consider a \p src_file_name of \TText{/tmp/A.h5}. * If that source file does not exist, the new \p src_file_name - * after stripping will be \Code{A.h5} + * after stripping will be \TText{A.h5} * * \see * Virtual Dataset Overview @@ -7538,7 +7538,7 @@ H5_DLL herr_t H5Pset_append_flush(hid_t dapl_id, unsigned ndims, const hsize_t b * use a hash table with 12421 elements and a maximum size of * 16 MB, while using the preemption policy specified for the * entire file: - * \Code{ + * \TText{ * H5Pset_chunk_cache(dapl_id, 12421, 16*1024*1024, * H5D_CHUNK_CACHE_W0_DEFAULT);} * @@ -8012,11 +8012,11 @@ H5_DLL herr_t H5Pset_btree_ratios(hid_t plist_id, double left, double middle, do * mining can only break the data up along the first dimension, so the * buffer must be large enough to accommodate a complete slice that * encompasses all of the remaining dimensions. For example, when strip - * mining a \Code{100x200x300} hyperslab of a simple data space, the - * buffer must be large enough to hold \Code{1x200x300} data - * elements. When strip mining a \Code{100x200x300x150} hyperslab of a + * mining a \TText{100x200x300} hyperslab of a simple data space, the + * buffer must be large enough to hold \TText{1x200x300} data + * elements. When strip mining a \TText{100x200x300x150} hyperslab of a * simple data space, the buffer must be large enough to hold - * \Code{1x200x300x150} data elements. + * \TText{1x200x300x150} data elements. * * If \p tconv and/or \p bkg are null pointers, then buffers will be * allocated and freed during the data transfer. @@ -8046,7 +8046,7 @@ H5_DLL herr_t H5Pset_buffer(hid_t plist_id, size_t size, void *tconv, void *bkg) * transfer property list \p plist_id. * * The \p expression parameter is a string containing an algebraic - * expression, such as \Code{(5/9.0)*(x-32)} or \Code{x*(x-5)}. When a + * expression, such as \TText{(5/9.0)*(x-32)} or \TText{x*(x-5)}. When a * dataset is read or written with this property list, the transform * expression is applied with the \c x being replaced by the values in * the dataset. When reading data, the values in the file are not diff --git a/src/H5Tmodule.h b/src/H5Tmodule.h index fd2a278fd22..636679e8380 100644 --- a/src/H5Tmodule.h +++ b/src/H5Tmodule.h @@ -2019,7 +2019,7 @@ filled according to the value of this property. The padding can be: *
    * - * Code for a compound datatype nested in a compound datatype + * TText for a compound datatype nested in a compound datatype * \code * typedef struct { * complex_t x; @@ -4006,8 +4006,8 @@ filled according to the value of this property. The padding can be: * component, they have a C-like type name. * \li If the type begins with \c U then it is the unsigned version of * the integer type; other integer types are signed. - * \li The datatype \c LLONG corresponds C's \Code{long long} and - * \c LDOUBLE is \Code{long double}. These types might be the same + * \li The datatype \c LLONG corresponds C's \TText{long long} and + * \c LDOUBLE is \TText{long double}. These types might be the same * as \c LONG and \c DOUBLE, respectively. *
    * \snippet{doc} tables/predefinedDatatypes.dox predefined_native_datatypes_table diff --git a/src/H5Tpublic.h b/src/H5Tpublic.h index 83761af2f58..97ee27c7f46 100644 --- a/src/H5Tpublic.h +++ b/src/H5Tpublic.h @@ -755,72 +755,72 @@ H5_DLLVAR hid_t H5T_VAX_F64_g; #define H5T_NATIVE_CHAR (CHAR_MIN ? H5T_NATIVE_SCHAR : H5T_NATIVE_UCHAR) /** * \ingroup PDTNAT - * C-style \Code{signed char} + * C-style \TText{signed char} */ #define H5T_NATIVE_SCHAR (H5OPEN H5T_NATIVE_SCHAR_g) /** * \ingroup PDTNAT - * C-style \Code{unsigned char} + * C-style \TText{unsigned char} */ #define H5T_NATIVE_UCHAR (H5OPEN H5T_NATIVE_UCHAR_g) /** * \ingroup PDTNAT - * C-style \Code{short} + * C-style \TText{short} */ #define H5T_NATIVE_SHORT (H5OPEN H5T_NATIVE_SHORT_g) /** * \ingroup PDTNAT - * C-style \Code{unsigned short} + * C-style \TText{unsigned short} */ #define H5T_NATIVE_USHORT (H5OPEN H5T_NATIVE_USHORT_g) /** * \ingroup PDTNAT - * C-style \Code{int} + * C-style \TText{int} */ #define H5T_NATIVE_INT (H5OPEN H5T_NATIVE_INT_g) /** * \ingroup PDTNAT - * C-style \Code{unsigned int} + * C-style \TText{unsigned int} */ #define H5T_NATIVE_UINT (H5OPEN H5T_NATIVE_UINT_g) /** * \ingroup PDTNAT - * C-style \Code{long} + * C-style \TText{long} */ #define H5T_NATIVE_LONG (H5OPEN H5T_NATIVE_LONG_g) /** * \ingroup PDTNAT - * C-style \Code{unsigned long} + * C-style \TText{unsigned long} */ #define H5T_NATIVE_ULONG (H5OPEN H5T_NATIVE_ULONG_g) /** * \ingroup PDTNAT - * C-style \Code{long long} + * C-style \TText{long long} */ #define H5T_NATIVE_LLONG (H5OPEN H5T_NATIVE_LLONG_g) /** * \ingroup PDTNAT - * C-style \Code{unsigned long long} + * C-style \TText{unsigned long long} */ #define H5T_NATIVE_ULLONG (H5OPEN H5T_NATIVE_ULLONG_g) /** * \ingroup PDTNAT - * C-style \Code{_Float16} + * C-style \TText{_Float16} */ #define H5T_NATIVE_FLOAT16 (H5OPEN H5T_NATIVE_FLOAT16_g) /** * \ingroup PDTNAT - * C-style \Code{float} + * C-style \TText{float} */ #define H5T_NATIVE_FLOAT (H5OPEN H5T_NATIVE_FLOAT_g) /** * \ingroup PDTNAT - * C-style \Code{double} + * C-style \TText{double} */ #define H5T_NATIVE_DOUBLE (H5OPEN H5T_NATIVE_DOUBLE_g) /** * \ingroup PDTNAT - * C-style \Code{long double} + * C-style \TText{long double} */ #define H5T_NATIVE_LDOUBLE (H5OPEN H5T_NATIVE_LDOUBLE_g) /** diff --git a/src/H5public.h b/src/H5public.h index 7551e088ffe..e2a82b9bb14 100644 --- a/src/H5public.h +++ b/src/H5public.h @@ -651,7 +651,7 @@ H5_DLL herr_t H5get_libversion(unsigned *majnum, unsigned *minnum, unsigned *rel * example: * * An official HDF5 release is labelled as follows: - * HDF5 Release \Code{\.\.\}\n + * HDF5 Release \TText{\.\.\}\n * For example, in HDF5 Release 1.8.5: * \li 1 is the major version number, \p majnum. * \li 8 is the minor version number, \p minnum. @@ -835,15 +835,15 @@ H5_DLL void *H5allocate_memory(size_t size, hbool_t clear); * This function is intended to have the semantics of realloc(): * * - * + * * - * + * * - * + * * - * + * * *
    \Code{H5resize_memory(buffer, size)}
    \TText{H5resize_memory(buffer, size)}Resizes buffer. Returns pointer to resized buffer.
    \Code{H5resize_memory(NULL, size)}
    \TText{H5resize_memory(NULL, size)}Allocates memory using HDF5 Library allocator. * Returns pointer to new buffer
    \Code{H5resize_memory(buffer, 0)}
    \TText{H5resize_memory(buffer, 0)}Frees memory using HDF5 Library allocator. * Returns NULL.
    \Code{H5resize_memory(NULL, 0)}
    \TText{H5resize_memory(NULL, 0)}Returns NULL (undefined in C standard).
    * From 819e00db91d23d091537480e8ddaa59f049b8f51 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:22:50 -0500 Subject: [PATCH 05/94] Correct signing names and variables (#4713) --- .github/workflows/cmake-ctest.yml | 55 ++++++++++++++++--------------- .github/workflows/daily-build.yml | 2 +- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index eb75076ed65..48f1d9d5e8c 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -40,11 +40,32 @@ permissions: contents: read jobs: + check-secret: + name: Check Secrets exists + runs-on: ubuntu-latest + outputs: + sign-state: ${{ steps.set-signing-state.outputs.BINSIGN }} + steps: + - name: Identify Signing Status + id: set-signing-state + env: + signing_secret: ${{ secrets.AZURE_ENDPOINT }} + run: | + if [[ '${{ env.signing_secret }}' == '' ]] + then + SIGN_VAL=$(echo "false") + else + SIGN_VAL=$(echo "true") + fi + echo "BINSIGN=$SIGN_VAL" >> $GITHUB_OUTPUT + shell: bash + build_and_test_win: # Windows w/ MSVC + CMake # name: "Windows MSVC CTest" runs-on: windows-latest + needs: [check-secret] steps: - name: Install Dependencies (Windows) run: choco install ninja @@ -57,18 +78,6 @@ jobs: - name: Enable Developer Command Prompt uses: ilammy/msvc-dev-cmd@v1.13.0 - - name: Check Secrets exists - id: set-signing-state - run: | - if [ '${{ secrets.AZURE_ENDPOINT }}' != '' ]; - then - SIGN_VAL=$(echo "true"); - else - SIGN_VAL=$(echo "false"); - fi - echo "BINSIGN=$SIGN_VAL" >> $GITHUB_OUTPUT - shell: bash - - name: Set file base name (Windows) id: set-file-base run: | @@ -125,7 +134,7 @@ jobs: file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 - if: ${{ steps.set-signing-state.BINSIGN == 'true' }} + if: ${{ needs.check-secret.outputs.sign-state == 'true' }} - name: Publish binary (Windows) id: publish-ctest-binary @@ -179,6 +188,7 @@ jobs: # name: "Ubuntu gcc CMake" runs-on: ubuntu-latest + needs: [check-secret] steps: - name: Install CMake Dependencies (Linux) run: | @@ -303,6 +313,7 @@ jobs: # name: "MacOS Clang CMake" runs-on: macos-latest + needs: [check-secret] steps: - name: Install Dependencies (MacOS_latest) run: brew install ninja @@ -485,22 +496,11 @@ jobs: # name: "Windows Intel CTest" runs-on: windows-latest + needs: [check-secret] steps: - name: Install Dependencies (Windows_intel) run: choco install ninja - - name: Check Secrets exists - id: set-signing-state - run: | - if [ '${{ secrets.AZURE_ENDPOINT }}' != '' ]; - then - SIGN_VAL=$(echo "true"); - else - SIGN_VAL=$(echo "false"); - fi - echo "BINSIGN=$SIGN_VAL" >> $GITHUB_OUTPUT - shell: bash - - name: add oneAPI to env uses: fortran-lang/setup-fortran@v1 id: setup-fortran @@ -563,12 +563,12 @@ jobs: endpoint: ${{ secrets.AZURE_ENDPOINT }} trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }} certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }} - files-folder: ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-MSVC + files-folder: ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Intel files-folder-filter: msi file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 - if: ${{ steps.set-signing-state.BINSIGN == 'true' }} + if: ${{ needs.check-secret.outputs.sign-state == 'true' }} - name: Publish binary (Windows_intel) id: publish-ctest-binary @@ -622,6 +622,7 @@ jobs: # name: "Ubuntu Intel CMake" runs-on: ubuntu-latest + needs: [check-secret] steps: - name: Install CMake Dependencies (Linux_intel) run: | diff --git a/.github/workflows/daily-build.yml b/.github/workflows/daily-build.yml index 1fd6435110c..3375dec6f31 100644 --- a/.github/workflows/daily-build.yml +++ b/.github/workflows/daily-build.yml @@ -85,5 +85,5 @@ jobs: file_base: ${{ needs.get-old-names.outputs.hdf5-name }} use_tag: snapshot use_environ: snapshots - if: ${{ needs.call-workflow-tarball.outputs.has_changes == 'true' }} + if: ${{ (needs.call-workflow-tarball.outputs.has_changes == 'true') && (needs.get-old-names.outputs.hdf5-name != needs.call-workflow-tarball.outputs.file_base) }} From 78fb239e83e4832f7875504bfdc44d3ff3261488 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:00:00 -0500 Subject: [PATCH 06/94] Add secrets to release workflow (#4719) --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9890c8abb45..de0c3f4e89f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,6 +40,13 @@ jobs: file_base: ${{ needs.call-workflow-tarball.outputs.file_base }} snap_name: hdf5-${{ needs.call-workflow-tarball.outputs.source_base }} use_environ: release + secrets: + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_ENDPOINT: ${{ secrets.AZURE_ENDPOINT }} + AZURE_CODE_SIGNING_NAME: ${{ secrets.AZURE_CODE_SIGNING_NAME }} + AZURE_CERT_PROFILE_NAME: ${{ secrets.AZURE_CERT_PROFILE_NAME }} call-workflow-abi: needs: [log-the-inputs, call-workflow-tarball, call-workflow-ctest] From 32ee132b0bc8fcd5ecc2306d2a3900f34c956d32 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:14:04 -0500 Subject: [PATCH 07/94] Add missing blosc2 info (#4717) --- CMakePresets.json | 2 ++ config/cmake/cacheinit.cmake | 8 ++++++++ release_docs/INSTALL_CMake.txt | 20 ++++++++++++++------ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index fc323af2dc2..31849736320 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -53,6 +53,8 @@ "BLOSC_ZLIB_PACKAGE_NAME": {"type": "STRING", "value": "zlib"}, "BLOSC2_TGZ_NAME": {"type": "STRING", "value": "c-blosc2-2.14.4.tar.gz"}, "BLOSC2_PACKAGE_NAME": {"type": "STRING", "value": "blosc2"}, + "BLOSC2_ZLIB_TGZ_NAME": {"type": "STRING", "value": "zlib-1.3.tar.gz"}, + "BLOSC2_ZLIB_PACKAGE_NAME": {"type": "STRING", "value": "zlib"}, "BZ2_TGZ_NAME": {"type": "STRING", "value": "bzip2-bzip2-1.0.8.tar.gz"}, "BZ2_PACKAGE_NAME": {"type": "STRING", "value": "bz2"}, "FPZIP_TGZ_NAME": {"type": "STRING", "value": "fpzip-1.3.0.tar.gz"}, diff --git a/config/cmake/cacheinit.cmake b/config/cmake/cacheinit.cmake index 4e56a1d5383..75936d1d298 100644 --- a/config/cmake/cacheinit.cmake +++ b/config/cmake/cacheinit.cmake @@ -130,6 +130,14 @@ set (BLOSC2_TGZ_NAME "c-blosc2-2.14.4.tar.gz" CACHE STRING "Use BLOSC2 from comp set (BLOSC2_PACKAGE_NAME "blosc2" CACHE STRING "Name of BLOSC2 package" FORCE) +set (BLOSC2_ZLIB_GIT_URL "https://github.com/madler/zlib.git" CACHE STRING "Use ZLIB from GitHub repository" FORCE) +set (BLOSC2_ZLIB_GIT_BRANCH "develop" CACHE STRING "" FORCE) + +set (BLOSC2_ZLIB_TGZ_ORIGPATH "https://github.com/madler/zlib/releases/download/v1.3" CACHE STRING "Use PLUGINS from original location" FORCE) +set (BLOSC2_ZLIB_TGZ_NAME "zlib-1.3.tar.gz" CACHE STRING "Use ZLib from compressed file" FORCE) + +set (BLOSC2_ZLIB_PACKAGE_NAME "zlib" CACHE STRING "Name of BLOSC2_ZLIB package" FORCE) + ######## # bzip2 ######## diff --git a/release_docs/INSTALL_CMake.txt b/release_docs/INSTALL_CMake.txt index 2322b763662..a86bae4bab6 100644 --- a/release_docs/INSTALL_CMake.txt +++ b/release_docs/INSTALL_CMake.txt @@ -144,6 +144,7 @@ To build HDF5 with the SZIP and ZLIB external libraries you will need to: ------bin ------include ------lib + --------plugins ------cmake On Linux, change to the install destination directory @@ -162,6 +163,7 @@ To build HDF5 with the SZIP and ZLIB external libraries you will need to: ------bin ------include ------lib + --------plugins ------share On Mac you will find HDF5-1.15."X"-Darwin.dmg in the myhdfstuff folder. Click @@ -173,6 +175,7 @@ To build HDF5 with the SZIP and ZLIB external libraries you will need to: ------bin ------include ------lib + --------plugins ------share By default the installation will create the bin, include, lib and cmake @@ -239,6 +242,7 @@ Notes: This short set of instructions is written for users who want to ------bin ------include ------lib + --------plugins ------cmake On Linux, change to the install destination directory @@ -257,6 +261,7 @@ Notes: This short set of instructions is written for users who want to ------bin ------include ------lib + --------plugins ------share On Mac you will find HDF5-1.15."X"-Darwin.dmg in the build folder. Click @@ -268,6 +273,7 @@ Notes: This short set of instructions is written for users who want to ------bin ------include ------lib + --------plugins ------share @@ -411,10 +417,8 @@ IV. Further considerations Notes: CMake and HDF5 1. Using CMake for building and using HDF5 is under active development. - While we have attempted to provide error-free files, please - understand that development with CMake has not been extensively - tested outside of HDF. The CMake specific files may change - before the next release. + We have attempted to provide error-free files. The CMake specific + files may change before the next release. 2. CMake support for HDF5 development should be usable on any system where CMake is supported. Please send us any comments on @@ -587,6 +591,11 @@ These five steps are described in detail below. set (BLOSC2_TGZ_ORIGPATH "https://github.com/Blosc/c-blosc2/archive/refs/tags" CACHE STRING "Use PLUGINS from original location" FORCE) set (BLOSC2_TGZ_NAME "c-blosc2-2.14.4.tar.gz" CACHE STRING "Use BLOSC2 from compressed file" FORCE) set (BLOSC2_PACKAGE_NAME "blosc2" CACHE STRING "Name of BLOSC2 package" FORCE) + set (BLOSC2_ZLIB_GIT_URL "https://github.com/madler/zlib.git" CACHE STRING "Use ZLIB from GitHub repository" FORCE) + set (BLOSC2_ZLIB_GIT_BRANCH "develop" CACHE STRING "" FORCE) + set (BLOSC2_ZLIB_TGZ_ORIGPATH "https://github.com/madler/zlib/releases/download/v1.3" CACHE STRING "Use PLUGINS from original location" FORCE) + set (BLOSC2_ZLIB_TGZ_NAME "zlib-1.3.tar.gz" CACHE STRING "Use ZLib from compressed file" FORCE) + set (BLOSC2_ZLIB_PACKAGE_NAME "zlib" CACHE STRING "Name of BLOSC2_ZLIB package" FORCE) ######## # bzip2 ######## @@ -663,7 +672,7 @@ These five steps are described in detail below. 2.1 Visual CMake users, click the Configure button. If this is the first time you are running cmake-gui in this directory, you will be prompted for the - generator you wish to use (for example on Windows, Visual Studio 12). + generator you wish to use (for example on Windows, Visual Studio 14). CMake will read in the CMakeLists.txt files from the source directory and display options for the HDF5 project. After the first configure you can adjust the cache settings and/or specify the locations of other programs. @@ -1124,7 +1133,6 @@ Using individual command presets (where is GNUC or MSVC or Clan ctest --preset ci-StdShar- cpack --preset ci-StdShar- - Using the workflow preset to configure, build, test and package the standard configuration: change directory to the hdf5 source folder execute "cmake --workflow --preset ci-StdShar- --fresh" From 89f62a937d026f3a793a5141018c39da2ea28833 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:03:42 -0700 Subject: [PATCH 08/94] Fix error return types in H5Rdeprec.c (#4722) Copy-pasted code from elsewhere used FAIL instead of H5G_UNKNOWN and H5I_INVALID_HID. --- src/H5Rdeprec.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/H5Rdeprec.c b/src/H5Rdeprec.c index 988f3292722..154d47cb508 100644 --- a/src/H5Rdeprec.c +++ b/src/H5Rdeprec.c @@ -267,12 +267,12 @@ H5Rget_obj_type1(hid_t id, H5R_type_t ref_type, const void *ref) /* Check if using native VOL connector */ if (H5VL_object_is_native(vol_obj, &is_native_vol_obj) < 0) - HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, H5G_UNKNOWN, "can't determine if VOL object is native connector object"); /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, H5G_UNKNOWN, "H5Rget_obj_type1 is only meant to be used with the native VOL connector"); /* Get object type */ @@ -341,12 +341,12 @@ H5Rdereference1(hid_t obj_id, H5R_type_t ref_type, const void *ref) /* Check if using native VOL connector */ if (H5VL_object_is_native(vol_obj, &is_native_vol_obj) < 0) - HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, H5I_INVALID_HID, "can't determine if VOL object is native connector object"); /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, H5I_INVALID_HID, "H5Rdereference1 is only meant to be used with the native VOL connector"); /* Get object type */ @@ -614,12 +614,12 @@ H5Rdereference2(hid_t obj_id, hid_t oapl_id, H5R_type_t ref_type, const void *re /* Check if using native VOL connector */ if (H5VL_object_is_native(vol_obj, &is_native_vol_obj) < 0) - HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_CANTGET, H5I_INVALID_HID, "can't determine if VOL object is native connector object"); /* Must use native VOL connector for this operation */ if (!is_native_vol_obj) - HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, H5I_INVALID_HID, "H5Rdereference2 is only meant to be used with the native VOL connector"); /* Get object type */ @@ -694,7 +694,7 @@ H5Rget_region(hid_t id, H5R_type_t ref_type, const void *ref) "can't query if file uses native VOL connector"); if (!is_native_vol_obj) - HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, FAIL, + HGOTO_ERROR(H5E_REFERENCE, H5E_VOL, H5I_INVALID_HID, "H5Rget_region is only meant to be used with the native VOL connector"); /* Get object type */ From 6896bf46eb4f3bb6d8636fbe93772098fa6cfdc5 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:04:03 -0500 Subject: [PATCH 09/94] Fix the release reference name (#4721) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de0c3f4e89f..1b0a90ff61e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,7 @@ jobs: needs: [log-the-inputs, call-workflow-tarball, call-workflow-ctest] uses: ./.github/workflows/abi-report.yml with: - file_ref: '1_14_3' + file_ref: '1.14.4.3' file_base: ${{ needs.call-workflow-tarball.outputs.file_base }} use_tag: ${{ needs.log-the-inputs.outputs.rel_tag }} use_environ: release From d25cc7d41b1275bc9d7f0184dc796744a2068920 Mon Sep 17 00:00:00 2001 From: mattjala <124107509+mattjala@users.noreply.github.com> Date: Mon, 19 Aug 2024 07:35:40 -0500 Subject: [PATCH 10/94] Test creating unseekable file (#4720) --- test/tfile.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/test/tfile.c b/test/tfile.c index 62881264441..a93b7be6857 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -8100,6 +8100,49 @@ test_min_dset_ohdr(void) CHECK(ret, FAIL, "H5Fclose"); } /* end test_min_dset_ohdr() */ +/**************************************************************** +** +** test_unseekable_file(): +** Test that attempting to open an unseekable file fails gracefully +** without a segfault (see hdf5#1498) +****************************************************************/ +static void +test_unseekable_file(void) +{ + hid_t file_id = H5I_INVALID_HID; /* File ID */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing creating/opening an unseekable file\n")); + + /* Creation */ +#ifdef H5_HAVE_WIN32_API + file_id = H5Fcreate("NUL", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); +#else + file_id = H5Fcreate("/dev/null", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); +#endif + + H5Fclose(file_id); + + /* Open, truncate */ +#ifdef H5_HAVE_WIN32_API + file_id = H5Fopen("NUL", H5F_ACC_TRUNC, H5P_DEFAULT); +#else + file_id = H5Fopen("/dev/null", H5F_ACC_TRUNC, H5P_DEFAULT); +#endif + + H5Fclose(file_id); + + /* Open, RDWR */ +#ifdef H5_HAVE_WIN32_API + file_id = H5Fopen("NUL", H5F_ACC_RDWR, H5P_DEFAULT); +#else + file_id = H5Fopen("/dev/null", H5F_ACC_RDWR, H5P_DEFAULT); +#endif + + H5Fclose(file_id); + + exit(EXIT_SUCCESS); +} /**************************************************************** ** ** test_deprec(): @@ -8419,10 +8462,11 @@ test_file(void) test_libver_bounds(); /* Test compatibility for file space management */ test_libver_bounds_low_high(driver_name); - test_libver_macros(); /* Test the macros for library version comparison */ - test_libver_macros2(); /* Test the macros for library version comparison */ - test_incr_filesize(); /* Test H5Fincrement_filesize() and H5Fget_eoa() */ - test_min_dset_ohdr(); /* Test dataset object header minimization */ + test_libver_macros(); /* Test the macros for library version comparison */ + test_libver_macros2(); /* Test the macros for library version comparison */ + test_incr_filesize(); /* Test H5Fincrement_filesize() and H5Fget_eoa() */ + test_min_dset_ohdr(); /* Test dataset object header minimization */ + test_unseekable_file(); /* Test attempting to open/create an unseekable file */ #ifndef H5_NO_DEPRECATED_SYMBOLS test_file_ishdf5(driver_name); /* Test detecting HDF5 files correctly */ test_deprec(driver_name); /* Test deprecated routines */ From b4731e4a85772ead7d5f2be2db3236eec46a725b Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Mon, 19 Aug 2024 09:02:13 -0400 Subject: [PATCH 11/94] Cleanup up tests (#4724) --- test/trefer.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test/trefer.c b/test/trefer.c index fcd0a21484a..6e5bd65e48b 100644 --- a/test/trefer.c +++ b/test/trefer.c @@ -618,21 +618,22 @@ test_reference_obj(void) /* Check file name for reference */ namelen = H5Rget_file_name(&rbuf[0], NULL, 0); - CHECK(namelen, FAIL, "H5Dget_file_name"); - VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Dget_file_name"); + CHECK(namelen, FAIL, "H5Rget_file_name"); + VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Rget_file_name"); /* Make sure size parameter is ignored */ namelen = H5Rget_file_name(&rbuf[0], NULL, 200); - CHECK(namelen, FAIL, "H5Dget_file_name"); - VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Dget_file_name"); + CHECK(namelen, FAIL, "H5Rget_file_name"); + VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Rget_file_name"); /* Get the file name for the reference */ namebuf = (char *)malloc((size_t)namelen + 1); - namelen = H5Rget_file_name(&rbuf[0], (char *)namebuf, (size_t)namelen + 1); - CHECK(namelen, FAIL, "H5Dget_file_name"); + namelen = H5Rget_file_name(&rbuf[0], namebuf, (size_t)namelen + 1); + CHECK(namelen, FAIL, "H5Rget_file_name"); + VERIFY(strcmp(namebuf, FILE_REF_OBJ), 0, "namebuf vs FILE_REF_OBJ"); + VERIFY(namelen, strlen(FILE_REF_OBJ), "H5Rget_file_name"); - ret = !((strcmp(namebuf, FILE_REF_OBJ) == 0) && (namelen == strlen(FILE_REF_OBJ))); - CHECK(ret, FAIL, "H5Literate"); + free(namebuf); /* Testing Dataset1 */ @@ -644,7 +645,8 @@ test_reference_obj(void) namebuf = (char *)malloc((size_t)namelen + 1); namelen = H5Rget_obj_name(&rbuf[0], H5P_DEFAULT, namebuf, (size_t)namelen + 1); CHECK(namelen, FAIL, "H5Rget_obj_name"); - VERIFY(strcmp(namebuf, DS1_REF_OBJ), 0, "strcmp namebuf vs DS1_REF_OBJ"); + VERIFY(strcmp(namebuf, DS1_REF_OBJ), 0, "namebuf vs DS1_REF_OBJ"); + VERIFY(namelen, strlen(DS1_REF_OBJ), "H5Rget_obj_name"); /* Open dataset object */ ref_ds1 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id); @@ -697,13 +699,12 @@ test_reference_obj(void) /* Getting the name of the referenced object and verify it */ namelen = H5Rget_obj_name(&rbuf[1], H5P_DEFAULT, NULL, 0); - CHECK(namelen, FAIL, "H5Rget_obj_name"); VERIFY(namelen, strlen(DS2_REF_OBJ), "H5Rget_obj_name"); namebuf = (char *)malloc((size_t)namelen + 1); namelen = H5Rget_obj_name(&rbuf[1], H5P_DEFAULT, namebuf, (size_t)namelen + 1); - CHECK(namelen, FAIL, "H5Rget_obj_name"); - VERIFY(strcmp(namebuf, DS2_REF_OBJ), 0, "strcmp namebuf vs DS2_REF_OBJ"); + VERIFY(namelen, strlen(DS2_REF_OBJ), "H5Rget_obj_name"); + VERIFY(strcmp(namebuf, DS2_REF_OBJ), 0, "namebuf vs DS2_REF_OBJ"); /* Open dataset object */ ref_ds2 = H5Ropen_object(&rbuf[1], H5P_DEFAULT, dapl_id); From adc3a37e96936c11862d113cf986a00fd277ff12 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Mon, 19 Aug 2024 08:53:10 -0500 Subject: [PATCH 12/94] Fix semaphore test (#4725) * Make counter in semaphore test an atomic variable * Revert using atomic counter and fix counter access outside of semaphore --- src/H5TSsemaphore.h | 2 +- test/ttsafe.c | 2 -- test/ttsafe.h | 2 -- test/ttsafe_semaphore.c | 14 ++++++++------ 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/H5TSsemaphore.h b/src/H5TSsemaphore.h index 0db1a888809..340b1cf9a11 100644 --- a/src/H5TSsemaphore.h +++ b/src/H5TSsemaphore.h @@ -179,7 +179,7 @@ H5TS_semaphore_wait(H5TS_semaphore_t *sem) * * Purpose: Increments (unlocks) the semaphore. If the semaphore's value * becomes greater than zero, then another thread blocked in a wait - * call will be woken up and proceed to lock the semaphore. + * call will proceed to lock the semaphore. * * Return: Non-negative on success / Negative on failure * diff --git a/test/ttsafe.c b/test/ttsafe.c index 08022eb1992..76dfa22bcbd 100644 --- a/test/ttsafe.c +++ b/test/ttsafe.c @@ -138,9 +138,7 @@ main(int argc, char *argv[]) AddTest("rec_rwlock_4", tts_rec_rw_lock_smoke_check_4, NULL, "recursive R/W lock smoke check 4 -- mixed mob", NULL); #endif /* !H5_HAVE_WIN_THREADS */ -#ifdef H5_HAVE_STDATOMIC_H AddTest("semaphore", tts_semaphore, NULL, "lightweight system semaphores", NULL); -#endif /* H5_HAVE_STDATOMIC_H */ #ifdef H5_HAVE_THREADSAFE AddTest("thread_id", tts_thread_id, NULL, "thread IDs", NULL); diff --git a/test/ttsafe.h b/test/ttsafe.h index d2066782b6b..f551e40462a 100644 --- a/test/ttsafe.h +++ b/test/ttsafe.h @@ -38,9 +38,7 @@ void tts_is_threadsafe(void); #ifdef H5_HAVE_THREADS void tts_thread_pool(void); void tts_atomics(void); -#ifdef H5_HAVE_STDATOMIC_H void tts_semaphore(void); -#endif /* H5_HAVE_STDATOMIC_H */ void tts_rec_rw_lock_smoke_check_1(void); void tts_rec_rw_lock_smoke_check_2(void); void tts_rec_rw_lock_smoke_check_3(void); diff --git a/test/ttsafe_semaphore.c b/test/ttsafe_semaphore.c index 41076632a4f..313508fe315 100644 --- a/test/ttsafe_semaphore.c +++ b/test/ttsafe_semaphore.c @@ -18,7 +18,7 @@ #include "ttsafe.h" -#if defined(H5_HAVE_THREADS) && defined(H5_HAVE_STDATOMIC_H) +#if defined(H5_HAVE_THREADS) #define NUM_PINGPONG (1000 * 1000) #define NUM_CLIENTSERVER (50 * 1000) @@ -40,6 +40,7 @@ static H5TS_THREAD_RETURN_TYPE ping(void *_test_info) { pingpong_t *test_info = (pingpong_t *)_test_info; + unsigned count; herr_t result; H5TS_thread_ret_t ret_value = 0; @@ -47,11 +48,11 @@ ping(void *_test_info) result = H5TS_semaphore_wait(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_wait"); - test_info->counter++; + count = ++test_info->counter; result = H5TS_semaphore_signal(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (test_info->counter < NUM_PINGPONG); + } while (count < NUM_PINGPONG); return ret_value; } @@ -60,6 +61,7 @@ static H5TS_THREAD_RETURN_TYPE pong(void *_test_info) { pingpong_t *test_info = (pingpong_t *)_test_info; + unsigned count; herr_t result; H5TS_thread_ret_t ret_value = 0; @@ -67,11 +69,11 @@ pong(void *_test_info) result = H5TS_semaphore_wait(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_wait"); - test_info->counter++; + count = ++test_info->counter; result = H5TS_semaphore_signal(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (test_info->counter < NUM_PINGPONG); + } while (count < NUM_PINGPONG); return ret_value; } @@ -268,4 +270,4 @@ tts_semaphore(void) tts_semaphore_clientserver(); } /* end tts_semaphore() */ -#endif /* defined(H5_HAVE_THREADS) && defined(H5_HAVE_STDATOMIC_H) */ +#endif /* defined(H5_HAVE_THREADS) */ From b54cc5b8c57293250ee2757ac7446713db2688cd Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Mon, 19 Aug 2024 11:42:48 -0500 Subject: [PATCH 13/94] Add arch name to dmg file name (#4732) The binaries in snapshot dmg file do not work on x86_64. --- .github/workflows/cmake-ctest.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 48f1d9d5e8c..bbb0acaba27 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -395,7 +395,7 @@ jobs: cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/README.md ${{ runner.workspace }}/builddmg/hdf5 cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/*.dmg ${{ runner.workspace }}/builddmg/hdf5 cd "${{ runner.workspace }}/builddmg" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz hdf5 + tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz hdf5 shell: bash - name: List files in the space (MacOS_latest) @@ -415,7 +415,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: tgz-macos14_clang-dmg-binary - path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` build_and_test_S3_linux: From b11f2d0d6784f47bd80b79013dc9c0a1cac0b85a Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Tue, 20 Aug 2024 07:38:38 -0500 Subject: [PATCH 14/94] Fix snapshot CI failure by adding arch name to dmg file (#4734) See also #4732. --- .github/workflows/release-files.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index 2eea38fceb4..2ef1c80faac 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -186,7 +186,7 @@ jobs: sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt @@ -232,7 +232,7 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz @@ -261,7 +261,7 @@ jobs: hdf5.tar.gz hdf5.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz @@ -281,7 +281,7 @@ jobs: ls ${{ runner.workspace }} - name: dev-only-docs - uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 + uses: peaceiris/actions-gh-pages@0b7567fde6f7517edcc13d8ffa2d89cd8734d47c # v4.0.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ${{ github.workspace }}/${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen From aea4c536546c5f963f4db524bedcb939fa4c935a Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Tue, 20 Aug 2024 20:36:40 -0400 Subject: [PATCH 15/94] Fix incorrect VOL vs. non-VOL calls partially (#4733) * Fix incorrect VOL vs. non-VOL calls H5Lget_info2() called H5I_object() instead of H5VL_vol_object() crashed user application. This is a wide-spread issue (GH-4730) but this PR only addresses GH-4705. * Remove an incorrect change --- src/H5L.c | 28 ++++++++++++++-------------- test/th5o.c | 5 +++++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/H5L.c b/src/H5L.c index 091296240b2..eb731f1832e 100644 --- a/src/H5L.c +++ b/src/H5L.c @@ -135,11 +135,11 @@ H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds if (H5L_SAME_LOC != src_loc_id) /* Get the location object */ - if (NULL == (vol_obj1 = (H5VL_object_t *)H5I_object(src_loc_id))) + if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); if (H5L_SAME_LOC != dst_loc_id) /* Get the location object */ - if (NULL == (vol_obj2 = (H5VL_object_t *)H5I_object(dst_loc_id))) + if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL connectors are the same */ @@ -236,11 +236,11 @@ H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds if (H5L_SAME_LOC != src_loc_id) /* Get the location object */ - if (NULL == (vol_obj1 = (H5VL_object_t *)H5I_object(src_loc_id))) + if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); if (H5L_SAME_LOC != dst_loc_id) /* Get the location object */ - if (NULL == (vol_obj2 = (H5VL_object_t *)H5I_object(dst_loc_id))) + if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL connectors are the same */ @@ -675,7 +675,7 @@ H5Lcreate_external(const char *file_name, const char *obj_name, hid_t link_loc_i loc_params.obj_type = H5I_get_type(link_loc_id); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(link_loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(link_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier"); /* Set up VOL callback arguments */ @@ -753,7 +753,7 @@ H5Lcreate_ud(hid_t link_loc_id, const char *link_name, H5L_type_t link_type, con loc_params.obj_type = H5I_get_type(link_loc_id); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(link_loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(link_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1043,7 +1043,7 @@ H5Lget_val(hid_t loc_id, const char *name, void *buf /*out*/, size_t size, hid_t loc_params.loc_data.loc_by_name.lapl_id = lapl_id; /* Get the VOL object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1107,7 +1107,7 @@ H5Lget_val_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5_ loc_params.obj_type = H5I_get_type(loc_id); /* Get the VOL object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1269,7 +1269,7 @@ H5Lget_info2(hid_t loc_id, const char *name, H5L_info2_t *linfo /*out*/, hid_t l loc_params.loc_data.loc_by_name.lapl_id = lapl_id; /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1328,7 +1328,7 @@ H5Lget_info_by_idx2(hid_t loc_id, const char *group_name, H5_index_t idx_type, H loc_params.obj_type = H5I_get_type(loc_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1514,7 +1514,7 @@ H5Lget_name_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5 loc_params.obj_type = H5I_get_type(loc_id); /* Get the VOL object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1720,7 +1720,7 @@ H5Literate_by_name2(hid_t loc_id, const char *group_name, H5_index_t idx_type, H HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access property list info"); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set location struct fields */ @@ -1799,7 +1799,7 @@ H5Lvisit2(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterat loc_params.obj_type = H5I_get_type(group_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(group_id))) + if (NULL == (vol_obj = H5VL_vol_object(group_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1873,7 +1873,7 @@ H5Lvisit_by_name2(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5_ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access property list info"); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set location struct fields */ diff --git a/test/th5o.c b/test/th5o.c index 801091f6b9f..39d804a347e 100644 --- a/test/th5o.c +++ b/test/th5o.c @@ -545,6 +545,7 @@ test_h5o_refcount(void) hid_t grp, dset, dtype, dspace; /* Object identifiers */ char filename[1024]; H5O_info2_t oinfo; /* Object info struct */ + H5L_info2_t linfo; /* Buffer for H5Lget_info */ hsize_t dims[RANK]; herr_t ret; /* Value returned from API calls */ @@ -568,6 +569,10 @@ test_h5o_refcount(void) ret = H5Tcommit2(fid, "datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); CHECK(ret, FAIL, "H5Tcommit2"); + /* Test passing a datatype ID to H5Lget_info2, it should not fail */ + ret = H5Lget_info2(dtype, "/datatype", &linfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info2"); + /* Create the data space for the dataset. */ dims[0] = DIM0; dims[1] = DIM1; From 4791d3416c65e66171f035b90b3ed1058892643f Mon Sep 17 00:00:00 2001 From: mattjala <124107509+mattjala@users.noreply.github.com> Date: Wed, 21 Aug 2024 07:35:29 -0500 Subject: [PATCH 16/94] Fix segfault in ROS3 credential parsing (#4736) * Fix segfault in s3 credential parsing * Fix AWS cred parsing when >1 profile provided --- src/H5FDs3comms.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/H5FDs3comms.c b/src/H5FDs3comms.c index 4b1ff0091aa..1d5ee2608e1 100644 --- a/src/H5FDs3comms.c +++ b/src/H5FDs3comms.c @@ -1671,6 +1671,9 @@ H5FD_s3comms_HMAC_SHA256(const unsigned char *key, size_t key_len, const char *m FUNC_ENTER_NOAPI_NOINIT + if (!key) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "signing key not provided"); + if (dest == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination cannot be null."); @@ -1751,6 +1754,7 @@ H5FD__s3comms_load_aws_creds_from_file(FILE *file, const char *profile_name, cha unsigned setting_i = 0; int found_setting = 0; char *line_buffer = &(buffer[0]); + size_t end = 0; FUNC_ENTER_PACKAGE @@ -1761,8 +1765,7 @@ H5FD__s3comms_load_aws_creds_from_file(FILE *file, const char *profile_name, cha /* look for start of profile */ do { /* clear buffer */ - for (buffer_i = 0; buffer_i < 128; buffer_i++) - buffer[buffer_i] = 0; + memset(buffer, 0, 128); line_buffer = fgets(line_buffer, 128, file); if (line_buffer == NULL) /* reached end of file */ @@ -1771,9 +1774,9 @@ H5FD__s3comms_load_aws_creds_from_file(FILE *file, const char *profile_name, cha /* extract credentials from lines */ do { - /* clear buffer */ - for (buffer_i = 0; buffer_i < 128; buffer_i++) - buffer[buffer_i] = 0; + /* clear buffer and flag */ + memset(buffer, 0, 128); + found_setting = 0; /* collect a line from file */ line_buffer = fgets(line_buffer, 128, file); @@ -1812,10 +1815,11 @@ H5FD__s3comms_load_aws_creds_from_file(FILE *file, const char *profile_name, cha strncpy(setting_pointers[setting_i], (const char *)line_buffer, strlen(line_buffer)); /* "trim" tailing whitespace by replacing with null terminator*/ - buffer_i = 0; - while (!isspace(setting_pointers[setting_i][buffer_i])) - buffer_i++; - setting_pointers[setting_i][buffer_i] = '\0'; + end = strlen(line_buffer) - 1; + while (end > 0 && isspace((int)setting_pointers[setting_i][end])) { + setting_pointers[setting_i][end] = '\0'; + end--; + } break; /* have read setting; don't compare with others */ } /* end if possible name match */ @@ -2173,7 +2177,7 @@ H5FD_s3comms_signing_key(unsigned char *md, const char *secret, const char *regi HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "`iso8601now` cannot be NULL."); AWS4_secret_len = 4 + strlen(secret) + 1; - AWS4_secret = (char *)H5MM_malloc(sizeof(char *) * AWS4_secret_len); + AWS4_secret = (char *)H5MM_malloc(AWS4_secret_len); if (AWS4_secret == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Could not allocate space."); @@ -2188,10 +2192,13 @@ H5FD_s3comms_signing_key(unsigned char *md, const char *secret, const char *regi HMAC(EVP_sha256(), (const unsigned char *)AWS4_secret, (int)strlen(AWS4_secret), (const unsigned char *)iso8601now, 8, /* 8 --> length of 8 --> "yyyyMMDD" */ datekey, NULL); + HMAC(EVP_sha256(), (const unsigned char *)datekey, SHA256_DIGEST_LENGTH, (const unsigned char *)region, strlen(region), dateregionkey, NULL); + HMAC(EVP_sha256(), (const unsigned char *)dateregionkey, SHA256_DIGEST_LENGTH, (const unsigned char *)"s3", 2, dateregionservicekey, NULL); + HMAC(EVP_sha256(), (const unsigned char *)dateregionservicekey, SHA256_DIGEST_LENGTH, (const unsigned char *)"aws4_request", 12, md, NULL); From eed772ef7fb1c4e26fb8703dc48bacb746cda98f Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Wed, 21 Aug 2024 07:43:58 -0500 Subject: [PATCH 17/94] Revert gh-pages action hash to fix daily build (#4735) * Revert gh-pages action hash to fix daily build See also #4734 * Revert gh-pages action hash to fix daily build --- .github/workflows/release-files.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index 2ef1c80faac..b2d6234a3bb 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -281,7 +281,7 @@ jobs: ls ${{ runner.workspace }} - name: dev-only-docs - uses: peaceiris/actions-gh-pages@0b7567fde6f7517edcc13d8ffa2d89cd8734d47c # v4.0.0 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ${{ github.workspace }}/${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen From 679b01774092e239e37401f881ed970d1067991d Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Wed, 21 Aug 2024 09:28:59 -0500 Subject: [PATCH 18/94] Eliminate another use of H5E_clear_stack() within the library (#4726) * Remove call to H5E_clear_stack() Also clean up a bunch of error macros and the return value from H5B_valid() --- src/H5B.c | 40 +++++++------- src/H5Bprivate.h | 2 +- src/H5Gstab.c | 138 +++++++++++++++++++++++++---------------------- 3 files changed, 95 insertions(+), 85 deletions(-) diff --git a/src/H5B.c b/src/H5B.c index 5a7a23853c5..30e39ef71a6 100644 --- a/src/H5B.c +++ b/src/H5B.c @@ -98,10 +98,10 @@ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ -#include "H5Bpkg.h" /* B-link trees */ -#include "H5CXprivate.h" /* API Contexts */ +#include "H5Bpkg.h" /* B-link trees */ +#include "H5CXprivate.h" /* API Contexts */ #include "H5Eprivate.h" /* Error handling */ -#include "H5FLprivate.h" /* Free Lists */ +#include "H5FLprivate.h" /* Free Lists */ #include "H5MFprivate.h" /* File memory management */ #include "H5MMprivate.h" /* Memory management */ @@ -109,7 +109,7 @@ /* Local Macros */ /****************/ #define H5B_SIZEOF_HDR(F) \ - (H5_SIZEOF_MAGIC + /*magic number */ \ + (H5_SIZEOF_MAGIC + /*magic number */ \ 4 + /*type, level, num entries */ \ 2 * H5F_SIZEOF_ADDR(F)) /*left and right sibling addresses */ @@ -234,7 +234,7 @@ H5B_create(H5F_t *f, const H5B_class_t *type, void *udata, haddr_t *addr_p /*out * Cache the new B-tree node. */ if (H5AC_insert_entry(f, H5AC_BT, *addr_p, bt, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "can't add B-tree root node to cache"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTINS, FAIL, "can't add B-tree root node to cache"); done: if (ret_value < 0) { @@ -245,7 +245,7 @@ H5B_create(H5F_t *f, const H5B_class_t *type, void *udata, haddr_t *addr_p /*out if (bt) /* Destroy B-tree node */ if (H5B__node_dest(bt) < 0) - HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, FAIL, "unable to destroy B-tree node"); + HDONE_ERROR(H5E_BTREE, H5E_CANTRELEASE, FAIL, "unable to destroy B-tree node"); } /* end if */ FUNC_LEAVE_NOAPI(ret_value) @@ -539,7 +539,7 @@ H5B_insert(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) /* Insert the object */ if ((int)(my_ins = H5B__insert_helper(f, &bt_ud, type, lt_key, <_key_changed, md_key, udata, rt_key, &rt_key_changed, &split_bt_ud /*out*/)) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to insert key"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, FAIL, "unable to insert key"); /* Check if the root node split */ if (H5B_INS_NOOP == my_ins) { @@ -585,7 +585,7 @@ H5B_insert(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) /* Move the location of the old root on the disk */ if (H5AC_move_entry(f, H5AC_BT, bt_ud.addr, old_root_addr) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTSPLIT, FAIL, "unable to move B-tree root node"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTMOVE, FAIL, "unable to move B-tree root node"); bt_ud.addr = old_root_addr; /* Update the split b-tree's left pointer to point to the new location */ @@ -609,7 +609,7 @@ H5B_insert(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) /* Insert the modified copy of the old root into the file again */ if (H5AC_insert_entry(f, H5AC_BT, addr, new_root_bt, H5AC__NO_FLAGS_SET) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTFLUSH, FAIL, "unable to add old B-tree root node to cache"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTINS, FAIL, "unable to add old B-tree root node to cache"); done: if (ret_value < 0) @@ -857,8 +857,7 @@ H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8 /* Since we are to the left of the leftmost key there must not be a left * sibling */ if (H5_addr_defined(bt->left)) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, - "internal error: likely corrupt key values"); + HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, H5B_INS_ERROR, "internal error: likely corrupt key values"); #endif /* H5_STRICT_FORMAT_CHECKS */ } else if (cmp > 0 && idx + 1 >= bt->nchildren) { @@ -909,8 +908,7 @@ H5B__insert_helper(H5F_t *f, H5B_ins_ud_t *bt_ud, const H5B_class_t *type, uint8 /* Since we are to the right of the rightmost key there must not be a * right sibling */ if (H5_addr_defined(bt->right)) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINSERT, H5B_INS_ERROR, - "internal error: likely corrupt key values"); + HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, H5B_INS_ERROR, "internal error: likely corrupt key values"); #endif /* H5_STRICT_FORMAT_CHECKS */ } else if (cmp) { @@ -1215,7 +1213,7 @@ H5B__remove_helper(H5F_t *f, haddr_t addr, const H5B_class_t *type, int level, u H5B__remove_helper(f, bt->child[idx], type, level + 1, H5B_NKEY(bt, shared, idx) /*out*/, lt_key_changed /*out*/, udata, H5B_NKEY(bt, shared, idx + 1) /*out*/, rt_key_changed /*out*/)) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "key not found in subtree"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, H5B_INS_ERROR, "key not found in subtree"); } else if (type->remove) { /* @@ -1225,7 +1223,7 @@ H5B__remove_helper(H5F_t *f, haddr_t addr, const H5B_class_t *type, int level, u */ if ((int)(ret_value = (type->remove)(f, bt->child[idx], H5B_NKEY(bt, shared, idx), lt_key_changed, udata, H5B_NKEY(bt, shared, idx + 1), rt_key_changed)) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, H5B_INS_ERROR, "key not found in leaf node"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, H5B_INS_ERROR, "key not found in leaf node"); } else { /* @@ -1499,7 +1497,7 @@ H5B_remove(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) /* The actual removal */ if (H5B_INS_ERROR == H5B__remove_helper(f, addr, type, 0, lt_key, <_key_changed, udata, rt_key, &rt_key_changed)) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "unable to remove entry from B-tree"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "unable to remove entry from B-tree"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1550,7 +1548,7 @@ H5B_delete(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) /* Iterate over all children in node, deleting them */ for (u = 0; u < bt->nchildren; u++) if (H5B_delete(f, type, bt->child[u], udata) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "unable to delete B-tree node"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTDELETE, FAIL, "unable to delete B-tree node"); } /* end if */ else { @@ -1563,7 +1561,7 @@ H5B_delete(H5F_t *f, const H5B_class_t *type, haddr_t addr, void *udata) /* Call user's callback for each entry */ if ((type->remove)(f, bt->child[u], H5B_NKEY(bt, shared, u), <_key_changed, udata, H5B_NKEY(bt, shared, u + 1), &rt_key_changed) < H5B_INS_NOOP) - HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "can't remove B-tree node"); + HGOTO_ERROR(H5E_BTREE, H5E_CANTREMOVE, FAIL, "can't remove B-tree node"); } /* end for */ } /* end if */ } /* end else */ @@ -1826,7 +1824,7 @@ H5B__get_info_helper(H5F_t *f, const H5B_class_t *type, haddr_t addr, const H5B_ if (level > 0) { /* Keep following the left-most child until we reach a leaf node. */ if (H5B__get_info_helper(f, type, left_child, info_udata) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTLIST, FAIL, "unable to list B-tree node"); + HGOTO_ERROR(H5E_BTREE, H5E_BADITER, FAIL, "unable to list B-tree node"); } /* end if */ done: @@ -1893,13 +1891,13 @@ H5B_get_info(H5F_t *f, const H5B_class_t *type, haddr_t addr, H5B_info_t *bt_inf * *------------------------------------------------------------------------- */ -htri_t +herr_t H5B_valid(H5F_t *f, const H5B_class_t *type, haddr_t addr) { H5B_t *bt = NULL; /* The B-tree */ H5UC_t *rc_shared; /* Ref-counted shared info */ H5B_cache_ud_t cache_udata; /* User-data for metadata cache callback */ - htri_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) diff --git a/src/H5Bprivate.h b/src/H5Bprivate.h index f93fa9c5d82..f354dea2ac0 100644 --- a/src/H5Bprivate.h +++ b/src/H5Bprivate.h @@ -142,5 +142,5 @@ H5_DLL H5B_shared_t *H5B_shared_new(const H5F_t *f, const H5B_class_t *type, siz H5_DLL herr_t H5B_shared_free(void *_shared); H5_DLL herr_t H5B_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, const H5B_class_t *type, void *udata); -H5_DLL htri_t H5B_valid(H5F_t *f, const H5B_class_t *type, haddr_t addr); +H5_DLL herr_t H5B_valid(H5F_t *f, const H5B_class_t *type, haddr_t addr); #endif /* H5Bprivate_H */ diff --git a/src/H5Gstab.c b/src/H5Gstab.c index 6c7e6db8824..594842830c4 100644 --- a/src/H5Gstab.c +++ b/src/H5Gstab.c @@ -138,7 +138,7 @@ H5G__stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint) /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(f, stab->heap_addr, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Insert name into the heap */ if (H5HL_insert(f, heap, (size_t)1, "", &name_offset) < 0) @@ -152,7 +152,7 @@ H5G__stab_create_components(H5F_t *f, H5O_stab_t *stab, size_t size_hint) done: /* Release resources */ if (heap && FAIL == H5HL_unprotect(heap)) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_create_components() */ @@ -243,7 +243,7 @@ H5G__stab_insert_real(H5F_t *f, const H5O_stab_t *stab, H5O_link_t *obj_lnk, H5O /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(f, stab->heap_addr, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Initialize data to pass through B-tree */ udata.common.name = obj_lnk->name; @@ -260,7 +260,7 @@ H5G__stab_insert_real(H5F_t *f, const H5O_stab_t *stab, H5O_link_t *obj_lnk, H5O done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_insert_real() */ @@ -288,10 +288,10 @@ H5G__stab_insert(const H5O_loc_t *grp_oloc, H5O_link_t *obj_lnk, H5O_type_t obj_ /* Retrieve symbol table message */ if (NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "not a symbol table"); if (H5G__stab_insert_real(grp_oloc->file, &stab, obj_lnk, obj_type, crt_info) < 0) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5_ITER_ERROR, "unable to insert the link"); + HGOTO_ERROR(H5E_SYM, H5E_CANTINSERT, H5_ITER_ERROR, "unable to insert the link"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -321,11 +321,11 @@ H5G__stab_remove(const H5O_loc_t *loc, H5RS_str_t *grp_full_path_r, const char * /* Read in symbol table message */ if (NULL == H5O_msg_read(loc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "not a symbol table"); /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(loc->file, stab.heap_addr, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Initialize data to pass through B-tree */ udata.common.name = name; @@ -335,12 +335,12 @@ H5G__stab_remove(const H5O_loc_t *loc, H5RS_str_t *grp_full_path_r, const char * /* Remove from symbol table */ if (H5B_remove(loc->file, H5B_SNODE, stab.btree_addr, &udata) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry"); + HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove entry"); done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_remove() */ @@ -376,11 +376,11 @@ H5G__stab_remove_by_idx(const H5O_loc_t *grp_oloc, H5RS_str_t *grp_full_path_r, /* Read in symbol table message */ if (NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "not a symbol table"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "not a symbol table"); /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Initialize data to pass through B-tree */ udata.common.name = obj_lnk.name; @@ -390,12 +390,12 @@ H5G__stab_remove_by_idx(const H5O_loc_t *grp_oloc, H5RS_str_t *grp_full_path_r, /* Remove link from symbol table */ if (H5B_remove(grp_oloc->file, H5B_SNODE, stab.btree_addr, &udata) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to remove entry"); + HGOTO_ERROR(H5E_SYM, H5E_CANTREMOVE, FAIL, "unable to remove entry"); done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); /* Reset the link information, if we have a copy */ if (lnk_copied) @@ -429,7 +429,7 @@ H5G__stab_delete(H5F_t *f, const H5O_stab_t *stab) /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(f, stab->heap_addr, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Set up user data for B-tree deletion */ udata.common.name = NULL; @@ -441,7 +441,7 @@ H5G__stab_delete(H5F_t *f, const H5O_stab_t *stab) /* Release resources */ if (H5HL_unprotect(heap) < 0) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); heap = NULL; /* Delete local heap for names */ @@ -451,7 +451,7 @@ H5G__stab_delete(H5F_t *f, const H5O_stab_t *stab) done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_delete() */ @@ -482,11 +482,11 @@ H5G__stab_iterate(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t skip, hs /* Get the B-tree info */ if (NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to determine local heap address"); /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Check on iteration order */ /* ("native" iteration order is increasing for this link storage mechanism) */ @@ -519,7 +519,7 @@ H5G__stab_iterate(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t skip, hs /* Iterate over the group members */ if (H5B_iterate(oloc->file, H5B_SNODE, stab.btree_addr, H5G__node_build_table, &udata) < 0) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to build link table"); + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "unable to build link table"); /* Check for skipping out of bounds */ if (skip > 0 && (size_t)skip >= ltable.nlinks) @@ -537,9 +537,9 @@ H5G__stab_iterate(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t skip, hs done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); if (ltable.lnks && H5G__link_release_table(<able) < 0) - HDONE_ERROR(H5E_SYM, H5E_CANTFREE, FAIL, "unable to release link table"); + HDONE_ERROR(H5E_SYM, H5E_CANTRELEASE, FAIL, "unable to release link table"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_iterate() */ @@ -570,11 +570,11 @@ H5G__stab_count(const H5O_loc_t *oloc, hsize_t *num_objs) /* Get the B-tree info */ if (NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to determine local heap address"); /* Iterate over the group members */ if (H5B_iterate(oloc->file, H5B_SNODE, stab.btree_addr, H5G__node_sumup, num_objs) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iteration operator failed"); done: FUNC_LEAVE_NOAPI_TAG(ret_value) @@ -608,14 +608,14 @@ H5G__stab_bh_size(H5F_t *f, const H5O_stab_t *stab, H5_ih_info_t *bh_info) /* Get the B-tree & symbol table node size info */ if (H5B_get_info(f, H5B_SNODE, stab->btree_addr, &bt_info, H5G__node_iterate_size, &snode_size) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_CANTINIT, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "iteration operator failed"); /* Add symbol table & B-tree node sizes to index info */ bh_info->index_size += snode_size + bt_info.size; /* Get the size of the local heap for the group */ if (H5HL_heapsize(f, stab->heap_addr, &(bh_info->heap_size)) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "iteration operator failed"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -657,7 +657,7 @@ H5G__stab_get_name_by_idx_cb(const H5G_entry_t *ent, void *_udata) HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to get symbol table link name"); if (NULL == (udata->name = H5MM_strndup(name, (block_size - name_off)))) - HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to duplicate symbol table link name"); + HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, FAIL, "unable to duplicate symbol table link name"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -692,11 +692,11 @@ H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t /* Get the B-tree & local heap info */ if (NULL == H5O_msg_read(oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to determine local heap address"); /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Remap index for decreasing iteration order */ if (order == H5_ITER_DEC) { @@ -704,7 +704,7 @@ H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t /* Iterate over the symbol table nodes, to count the links */ if (H5B_iterate(oloc->file, H5B_SNODE, stab.btree_addr, H5G__node_sumup, &nlinks) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iteration operator failed"); /* Map decreasing iteration order index to increasing iteration order index */ n = nlinks - (n + 1); @@ -720,11 +720,11 @@ H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t /* Iterate over the group members */ if (H5B_iterate(oloc->file, H5B_SNODE, stab.btree_addr, H5G__node_by_idx, &udata) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iteration operator failed"); /* If we don't know the name now, we almost certainly went out of bounds */ if (udata.name == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "index out of bound"); + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound"); /* Get the length of the name */ *name_len = strlen(udata.name); @@ -739,7 +739,7 @@ H5G__stab_get_name_by_idx(const H5O_loc_t *oloc, H5_iter_order_t order, hsize_t done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); /* Free the duplicated name */ if (udata_valid && udata.name != NULL) @@ -805,11 +805,11 @@ H5G__stab_lookup(const H5O_loc_t *grp_oloc, const char *name, bool *found, H5O_l /* Retrieve the symbol table message for the group */ if (NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "can't read message"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "can't read message"); /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Set up user data to pass to 'find' operation callback */ udata.name = name; @@ -830,7 +830,7 @@ H5G__stab_lookup(const H5O_loc_t *grp_oloc, const char *name, bool *found, H5O_l done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_lookup() */ @@ -892,11 +892,11 @@ H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_ /* Get the B-tree & local heap info */ if (NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to determine local heap address"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to determine local heap address"); /* Pin the heap down in memory */ if (NULL == (heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); /* Remap index for decreasing iteration order */ if (order == H5_ITER_DEC) { @@ -904,7 +904,7 @@ H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_ /* Iterate over the symbol table nodes, to count the links */ if (H5B_iterate(grp_oloc->file, H5B_SNODE, stab.btree_addr, H5G__node_sumup, &nlinks) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iteration operator failed"); /* Map decreasing iteration order index to increasing iteration order index */ n = nlinks - (n + 1); @@ -920,16 +920,16 @@ H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_ /* Iterate over the group members */ if (H5B_iterate(grp_oloc->file, H5B_SNODE, stab.btree_addr, H5G__node_by_idx, &udata) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "iteration operator failed"); + HGOTO_ERROR(H5E_SYM, H5E_BADITER, FAIL, "iteration operator failed"); /* If we didn't find the link, we almost certainly went out of bounds */ if (!udata.found) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "index out of bound"); + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "index out of bound"); done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__stab_lookup_by_idx() */ @@ -939,8 +939,8 @@ H5G__stab_lookup_by_idx(const H5O_loc_t *grp_oloc, H5_iter_order_t order, hsize_ /*------------------------------------------------------------------------- * Function: H5G__stab_valid * - * Purpose: Verify that a group's symbol table message is valid. If - * provided, the addresses in alt_stab will be tried if the + * Purpose: Verify that a group's symbol table message is valid. + * The addresses in alt_stab will be tried if the * addresses in the group's stab message are invalid, and * the stab message will be updated if necessary. * @@ -958,22 +958,32 @@ herr_t H5G__stab_valid(H5O_loc_t *grp_oloc, H5O_stab_t *alt_stab) { H5O_stab_t stab; /* Current symbol table */ - H5HL_t *heap = NULL; /* Pointer to local heap */ - bool changed = false; /* Whether stab has been modified */ + H5HL_t *heap = NULL; /* Pointer to local heap */ + bool changed = false; /* Whether stab has been modified */ + herr_t bt_status; /* B-tree status */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_TAG(grp_oloc->addr) + /* Sanity check */ + assert(grp_oloc); + assert(alt_stab); + /* Read the symbol table message */ if (NULL == H5O_msg_read(grp_oloc, H5O_STAB_ID, &stab)) - HGOTO_ERROR(H5E_SYM, H5E_BADMESG, FAIL, "unable to read symbol table message"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, FAIL, "unable to read symbol table message"); /* Check if the symbol table message's b-tree address is valid */ - if (H5B_valid(grp_oloc->file, H5B_SNODE, stab.btree_addr) < 0) { - /* Address is invalid, try the b-tree address in the alternate symbol - * table message */ - if (!alt_stab || H5B_valid(grp_oloc->file, H5B_SNODE, alt_stab->btree_addr) < 0) - HGOTO_ERROR(H5E_BTREE, H5E_NOTFOUND, FAIL, "unable to locate b-tree"); + H5E_PAUSE_ERRORS + { + bt_status = H5B_valid(grp_oloc->file, H5B_SNODE, stab.btree_addr); + } + H5E_RESUME_ERRORS + + if (bt_status < 0) { + /* Address is invalid, try the b-tree address in the alternate symbol table message */ + if (H5B_valid(grp_oloc->file, H5B_SNODE, alt_stab->btree_addr) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to locate b-tree"); else { /* The alternate symbol table's b-tree address is valid. Adjust the * symbol table message in the group. */ @@ -983,12 +993,16 @@ H5G__stab_valid(H5O_loc_t *grp_oloc, H5O_stab_t *alt_stab) } /* end if */ /* Check if the symbol table message's heap address is valid */ - if (NULL == (heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG))) { - /* Address is invalid, try the heap address in the alternate symbol - * table message */ - if (!alt_stab || - NULL == (heap = H5HL_protect(grp_oloc->file, alt_stab->heap_addr, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_HEAP, H5E_NOTFOUND, FAIL, "unable to locate heap"); + H5E_PAUSE_ERRORS + { + heap = H5HL_protect(grp_oloc->file, stab.heap_addr, H5AC__READ_ONLY_FLAG); + } + H5E_RESUME_ERRORS + + if (NULL == heap) { + /* Address is invalid, try the heap address in the alternate symbol table message */ + if (NULL == (heap = H5HL_protect(grp_oloc->file, alt_stab->heap_addr, H5AC__READ_ONLY_FLAG))) + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to locate heap"); else { /* The alternate symbol table's heap address is valid. Adjust the * symbol table message in the group. */ @@ -998,16 +1012,14 @@ H5G__stab_valid(H5O_loc_t *grp_oloc, H5O_stab_t *alt_stab) } /* end if */ /* Update the symbol table message and clear errors if necessary */ - if (changed) { - H5E_clear_stack(); + if (changed) if (H5O_msg_write(grp_oloc, H5O_STAB_ID, 0, H5O_UPDATE_TIME | H5O_UPDATE_FORCE, &stab) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to correct symbol table message"); - } /* end if */ + HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "unable to correct symbol table message"); done: /* Release resources */ if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI_TAG(ret_value) } /* end H5G__stab_valid */ From c1cbba69c65cd32bc1d6da6d066c9626abad3542 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Wed, 21 Aug 2024 21:33:13 -0500 Subject: [PATCH 19/94] Use gfortran 14 for cmake-ctest.yml on mac (#4739) * Use gfortran 14 for cmake-test on mac * Remove notarization step * Address @byrnHDF review --- .github/workflows/cmake-bintest.yml | 2 +- .github/workflows/cmake-ctest.yml | 2 +- .github/workflows/main-cmake.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake-bintest.yml b/.github/workflows/cmake-bintest.yml index 84f66007213..379db3a2ca5 100644 --- a/.github/workflows/cmake-bintest.yml +++ b/.github/workflows/cmake-bintest.yml @@ -192,7 +192,7 @@ jobs: id: setup-fortran with: compiler: gcc - version: 12 + version: 14 - name: Run ctest (MacOS_latest) id: run-ctest diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index bbb0acaba27..a588614e673 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -363,7 +363,7 @@ jobs: id: setup-fortran with: compiler: gcc - version: 12 + version: 14 - name: Run ctest (MacOS_latest) id: run-ctest diff --git a/.github/workflows/main-cmake.yml b/.github/workflows/main-cmake.yml index abc4140831b..9c58f0ba8e2 100644 --- a/.github/workflows/main-cmake.yml +++ b/.github/workflows/main-cmake.yml @@ -141,7 +141,7 @@ jobs: id: setup-fortran with: compiler: gcc - version: 12 + version: 14 if: ${{ matrix.os == 'macos-latest' }} - name: Install Dependencies From 17123cd8ba59bf029fe450897aa4b1d39192c6a1 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Wed, 21 Aug 2024 22:40:53 -0500 Subject: [PATCH 20/94] Fix enum type mismatch warning (#4741) --- src/H5VLpassthru.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5VLpassthru.c b/src/H5VLpassthru.c index 09ac6617e09..df13afc2513 100644 --- a/src/H5VLpassthru.c +++ b/src/H5VLpassthru.c @@ -2686,7 +2686,7 @@ H5VL_pass_through_request_wait(void *obj, uint64_t timeout, H5VL_request_status_ ret_value = H5VLrequest_wait(o->under_object, o->under_vol_id, timeout, status); - if (ret_value >= 0 && *status != H5ES_STATUS_IN_PROGRESS) + if (ret_value >= 0 && *status != H5VL_REQUEST_STATUS_IN_PROGRESS) H5VL_pass_through_free_obj(o); return ret_value; From 8b3041f3a33979255bda605c80509054fd7df705 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Thu, 22 Aug 2024 11:12:59 -0500 Subject: [PATCH 21/94] Fix macro redefined warnings (#4744) Removes a duplicated HDopen macro from the performance testing programs --- tools/src/h5perf/pio_engine.c | 6 ------ tools/src/h5perf/sio_engine.c | 6 ------ 2 files changed, 12 deletions(-) diff --git a/tools/src/h5perf/pio_engine.c b/tools/src/h5perf/pio_engine.c index 8b11f51fc68..7930d9645a0 100644 --- a/tools/src/h5perf/pio_engine.c +++ b/tools/src/h5perf/pio_engine.c @@ -72,12 +72,6 @@ } while (0) /* POSIX I/O macros */ -#ifdef H5_HAVE_WIN32_API -/* Can't link against the library, so this test will use the older, non-Unicode - * _open() call on Windows. - */ -#define HDopen(S, F, ...) _open(S, F | _O_BINARY, __VA_ARGS__) -#endif /* H5_HAVE_WIN32_API */ #define POSIXCREATE(fn) HDopen(fn, O_CREAT | O_TRUNC | O_RDWR, 0600) #define POSIXOPEN(fn, F) HDopen(fn, F, 0600) #define POSIXCLOSE(F) HDclose(F) diff --git a/tools/src/h5perf/sio_engine.c b/tools/src/h5perf/sio_engine.c index 12305f54a76..0d2240fa69f 100644 --- a/tools/src/h5perf/sio_engine.c +++ b/tools/src/h5perf/sio_engine.c @@ -53,12 +53,6 @@ } while (0) /* POSIX I/O macros */ -#ifdef H5_HAVE_WIN32_API -/* Can't link against the library, so this test will use the older, non-Unicode - * _open() call on Windows. - */ -#define HDopen(S, F, ...) _open(S, F | _O_BINARY, __VA_ARGS__) -#endif /* H5_HAVE_WIN32_API */ #define POSIXCREATE(fn) HDopen(fn, O_CREAT | O_TRUNC | O_RDWR, 0600) #define POSIXOPEN(fn, F) HDopen(fn, F, 0600) #define POSIXCLOSE(F) HDclose(F) From 7a17a98e9bccaabf0fccd94f44f172a988156b72 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Thu, 22 Aug 2024 11:17:11 -0500 Subject: [PATCH 22/94] Update nvhpc CI version to 24.7 (#4740) --- .github/workflows/nvhpc-auto.yml | 20 ++++++++++---------- .github/workflows/nvhpc-cmake.yml | 16 ++++++++-------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/nvhpc-auto.yml b/.github/workflows/nvhpc-auto.yml index 775143f84c9..bb986d3c800 100644 --- a/.github/workflows/nvhpc-auto.yml +++ b/.github/workflows/nvhpc-auto.yml @@ -35,21 +35,21 @@ jobs: curl https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg echo 'deb [signed-by=/usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg] https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64 /' | sudo tee /etc/apt/sources.list.d/nvhpc.list sudo apt-get update -y - sudo apt-get install -y nvhpc-24-5 + sudo apt-get install -y nvhpc-24-7 echo "NVHPCSDK=/opt/nvidia/hpc_sdk" >> $GITHUB_ENV - echo "OMPI_CXX=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin/nvc++" >> $GITHUB_ENV - echo "OMPI_CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin/nvc" >> $GITHUB_ENV - echo "OMPI_FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin/nvfortran" >> $GITHUB_ENV - echo "CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin/mpicc" >> $GITHUB_ENV - echo "FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin/mpifort" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/lib" >> $GITHUB_ENV + echo "OMPI_CXX=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin/nvc++" >> $GITHUB_ENV + echo "OMPI_CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin/nvc" >> $GITHUB_ENV + echo "OMPI_FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin/nvfortran" >> $GITHUB_ENV + echo "CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin/mpicc" >> $GITHUB_ENV + echo "FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin/mpifort" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/lib" >> $GITHUB_ENV echo "DESTDIR=/tmp" >> $GITHUB_ENV - name: Autotools Configure shell: bash run: | export RUNPARALLEL="mpiexec -np 2" - export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin:$PATH + export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin:$PATH sh ./autogen.sh mkdir "${{ runner.workspace }}/build" cd "${{ runner.workspace }}/build" @@ -63,13 +63,13 @@ jobs: - name: Autotools Build shell: bash run: | - export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin:$PATH + export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin:$PATH make -j3 working-directory: ${{ runner.workspace }}/build - name: Autotools Install shell: bash run: | - export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin:$PATH + export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin:$PATH make install working-directory: ${{ runner.workspace }}/build diff --git a/.github/workflows/nvhpc-cmake.yml b/.github/workflows/nvhpc-cmake.yml index 08da821702c..a0641fa3089 100644 --- a/.github/workflows/nvhpc-cmake.yml +++ b/.github/workflows/nvhpc-cmake.yml @@ -34,20 +34,20 @@ jobs: curl https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg echo 'deb [signed-by=/usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg] https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64 /' | sudo tee /etc/apt/sources.list.d/nvhpc.list sudo apt-get update -y - sudo apt-get install -y nvhpc-24-5 + sudo apt-get install -y nvhpc-24-7 echo "NVHPCSDK=/opt/nvidia/hpc_sdk" >> $GITHUB_ENV - echo "OMPI_CXX=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin/nvc++" >> $GITHUB_ENV - echo "OMPI_CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin/nvc" >> $GITHUB_ENV - echo "OMPI_FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin/nvfortran" >> $GITHUB_ENV - echo "CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin/mpicc" >> $GITHUB_ENV - echo "FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin/mpifort" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/cuda/12.3/lib64:/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/lib" >> $GITHUB_ENV + echo "OMPI_CXX=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin/nvc++" >> $GITHUB_ENV + echo "OMPI_CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin/nvc" >> $GITHUB_ENV + echo "OMPI_FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin/nvfortran" >> $GITHUB_ENV + echo "CC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin/mpicc" >> $GITHUB_ENV + echo "FC=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin/mpifort" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/cuda/12.3/lib64:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/lib" >> $GITHUB_ENV echo "DESTDIR=/tmp" >> $GITHUB_ENV - name: CMake Configure shell: bash run: | - export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.5/compilers/bin:$PATH + export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin:$PATH mkdir "${{ runner.workspace }}/build" cd "${{ runner.workspace }}/build" cmake -C $GITHUB_WORKSPACE/config/cmake/cacheinit.cmake -G Ninja \ From 8a8ac85a691471449031b64c6aeab08e26bebb32 Mon Sep 17 00:00:00 2001 From: Aleksandar Jelenak Date: Thu, 22 Aug 2024 12:18:54 -0400 Subject: [PATCH 23/94] Return basic HTTP range GET logging to ROS3 (#4738) * Add minimal amount of S3 request logging to ROS3 * Fix ROS3 logging ifdef conditions --- src/H5FDs3comms.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/H5FDs3comms.c b/src/H5FDs3comms.c index 1d5ee2608e1..0d1cd0f868a 100644 --- a/src/H5FDs3comms.c +++ b/src/H5FDs3comms.c @@ -50,7 +50,7 @@ /* manipulate verbosity of CURL output * * 0 -> no explicit curl output - * 1 -> on error, print failure info to stderr + * 1 -> print: (1) failure info to stderr on error, (2) basic HTTP range GET info * 2 -> in addition to above, print information for all performs; sets all * curl handles with CURLOPT_VERBOSE */ @@ -810,6 +810,11 @@ H5FD_s3comms_s3r_getsize(s3r_t *handle) handle->filesize = (size_t)content_length; +#if S3COMMS_CURL_VERBOSITY > 0 + fprintf(stdout, " -- size: %ju\n", content_length); + fflush(stdout); +#endif + /********************** * UNDO HEAD SETTINGS * **********************/ @@ -1119,6 +1124,12 @@ H5FD_s3comms_s3r_read(s3r_t *handle, haddr_t offset, size_t len, void *dest) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to format HTTP Range value"); } +#if S3COMMS_CURL_VERBOSITY > 0 + fprintf(stdout, "%s: Bytes %" PRIuHADDR " - %" PRIuHADDR ", Request Size: %zu\n", handle->httpverb, + offset, offset + len - 1, len); + fflush(stdout); +#endif + /******************* * COMPILE REQUEST * *******************/ From a03203afbc7557127c32cd7bab8f8f2d9c6a4e27 Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:32:48 -0400 Subject: [PATCH 24/94] Replace non-VOL calls with VOL calls - part 1 (#4745) This PR is part of the incremental switching H5I_object() and H5I_object_verify() to their VOL counterpart, H5VL_object() and H5VL_vol_object_verify(), a newly addedinternal function. Fixes GH-4730 partially. --- src/H5A.c | 14 +++++++------- src/H5D.c | 46 +++++++++++++++++++++++----------------------- src/H5Ddeprec.c | 2 +- src/H5VLint.c | 35 +++++++++++++++++++++++++++++++++++ src/H5VLprivate.h | 1 + 5 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/H5A.c b/src/H5A.c index 651ed13c256..9bad7053a48 100644 --- a/src/H5A.c +++ b/src/H5A.c @@ -983,7 +983,7 @@ H5A__read_api_common(hid_t attr_id, hid_t dtype_id, void *buf, void **token_ptr, HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf parameter can't be NULL"); /* Get attribute object pointer */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute"); /* Read the attribute data */ @@ -1090,7 +1090,7 @@ H5Aget_space(hid_t attr_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not an attribute"); /* Set up VOL callback arguments */ @@ -1134,7 +1134,7 @@ H5Aget_type(hid_t attr_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not an attribute"); /* Set up VOL callback arguments */ @@ -1183,7 +1183,7 @@ H5Aget_create_plist(hid_t attr_id) assert(H5P_LST_ATTRIBUTE_CREATE_ID_g != -1); /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not an attribute"); /* Set up VOL callback arguments */ @@ -1234,7 +1234,7 @@ H5Aget_name(hid_t attr_id, size_t buf_size, char *buf /*out*/) FUNC_ENTER_API((-1)) /* check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not an attribute"); if (!buf && buf_size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "buf cannot be NULL if buf_size is non-zero"); @@ -1352,7 +1352,7 @@ H5Aget_storage_size(hid_t attr_id) FUNC_ENTER_API(0) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not an attribute"); /* Set up VOL callback arguments */ @@ -1390,7 +1390,7 @@ H5Aget_info(hid_t attr_id, H5A_info_t *ainfo /*out*/) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(attr_id, H5I_ATTR))) + if (NULL == (vol_obj = H5VL_vol_object_verify(attr_id, H5I_ATTR))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an attribute"); if (!ainfo) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "attribute_info parameter cannot be NULL"); diff --git a/src/H5D.c b/src/H5D.c index 7416405e7f9..a50a2aceda6 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -295,7 +295,7 @@ H5Dcreate_anon(hid_t loc_id, hid_t type_id, hid_t space_id, hid_t dcpl_id, hid_t HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, H5I_INVALID_HID, "can't set access property list info"); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Set location parameters */ @@ -559,7 +559,7 @@ H5D__get_space_api_common(hid_t dset_id, void **token_ptr, H5VL_object_t **_vol_ FUNC_ENTER_PACKAGE /* Check args */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -671,7 +671,7 @@ H5Dget_space_status(hid_t dset_id, H5D_space_status_t *allocation /*out*/) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -709,7 +709,7 @@ H5Dget_type(hid_t dset_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -750,7 +750,7 @@ H5Dget_create_plist(hid_t dset_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -808,7 +808,7 @@ H5Dget_access_plist(hid_t dset_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -852,7 +852,7 @@ H5Dget_storage_size(hid_t dset_id) FUNC_ENTER_API(0) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -893,7 +893,7 @@ H5Dget_offset(hid_t dset_id) FUNC_ENTER_API(HADDR_UNDEF) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, HADDR_UNDEF, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -957,7 +957,7 @@ H5D__read_api_common(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t m HGOTO_ERROR(H5E_VOL, H5E_CANTALLOC, FAIL, "can't allocate space for object array"); /* Get vol_obj_ptr (return just the first dataset to caller if requested) */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id[0], H5I_DATASET))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object_verify(dset_id[0], H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID"); /* Save the connector of the first dataset. Unpack the connector and call @@ -969,7 +969,7 @@ H5D__read_api_common(size_t count, hid_t dset_id[], hid_t mem_type_id[], hid_t m obj[0] = (*vol_obj_ptr)->data; for (i = 1; i < count; i++) { /* Get the object */ - if (NULL == (tmp_vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id[i], H5I_DATASET))) + if (NULL == (tmp_vol_obj = H5VL_vol_object_verify(dset_id[i], H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID"); obj[i] = tmp_vol_obj->data; @@ -1181,7 +1181,7 @@ H5Dread_chunk(hid_t dset_id, hid_t dxpl_id, const hsize_t *offset, uint32_t *fil FUNC_ENTER_API(FAIL) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id is not a dataset ID"); if (!buf) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf cannot be NULL"); @@ -1487,7 +1487,7 @@ H5Dwrite_chunk(hid_t dset_id, hid_t dxpl_id, uint32_t filters, const hsize_t *of FUNC_ENTER_API(FAIL) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset ID"); if (!buf) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buf cannot be NULL"); @@ -1874,7 +1874,7 @@ H5Dvlen_get_buf_size(hid_t dataset_id, hid_t type_id, hid_t space_id, hsize_t *s FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dataset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dataset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); if (H5I_DATATYPE != H5I_get_type(type_id)) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid datatype identifier"); @@ -1935,7 +1935,7 @@ H5D__set_extent_api_common(hid_t dset_id, const hsize_t size[], void **token_ptr FUNC_ENTER_PACKAGE /* Check args */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); if (!size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "size array cannot be NULL"); @@ -2040,7 +2040,7 @@ H5Dflush(hid_t dset_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id parameter is not a valid dataset identifier"); /* Set up collective metadata if appropriate */ @@ -2081,7 +2081,7 @@ H5Drefresh(hid_t dset_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id parameter is not a valid dataset identifier"); /* Set up collective metadata if appropriate */ @@ -2124,7 +2124,7 @@ H5Dformat_convert(hid_t dset_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id parameter is not a valid dataset identifier"); /* Set up collective metadata if appropriate */ @@ -2163,7 +2163,7 @@ H5Dget_chunk_index_type(hid_t dset_id, H5D_chunk_index_t *idx_type /*out*/) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id parameter is not a valid dataset identifier"); if (NULL == idx_type) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "idx_type parameter cannot be NULL"); @@ -2204,7 +2204,7 @@ H5Dget_chunk_storage_size(hid_t dset_id, const hsize_t *offset, hsize_t *chunk_n FUNC_ENTER_API(FAIL) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "dset_id parameter is not a valid dataset identifier"); if (NULL == offset) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "offset parameter cannot be NULL"); @@ -2254,7 +2254,7 @@ H5Dget_num_chunks(hid_t dset_id, hid_t fspace_id, hsize_t *nchunks /*out*/) FUNC_ENTER_API(FAIL) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); if (NULL == nchunks) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid argument (null)"); @@ -2308,7 +2308,7 @@ H5Dget_chunk_info(hid_t dset_id, hid_t fspace_id, hsize_t chk_index, hsize_t *of if (NULL == offset && NULL == filter_mask && NULL == addr && NULL == size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid arguments, must have at least one non-null output argument"); - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); /* Set up VOL callback arguments */ @@ -2373,7 +2373,7 @@ H5Dget_chunk_info_by_coord(hid_t dset_id, const hsize_t *offset, unsigned *filte FUNC_ENTER_API(FAIL) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); if (NULL == filter_mask && NULL == addr && NULL == size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, @@ -2423,7 +2423,7 @@ H5Dchunk_iter(hid_t dset_id, hid_t dxpl_id, H5D_chunk_iter_op_t op, void *op_dat FUNC_ENTER_API(FAIL) /* Check arguments */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); if (NULL == op) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback to chunk iteration"); diff --git a/src/H5Ddeprec.c b/src/H5Ddeprec.c index 5b0f4e33ede..51d6e4323c0 100644 --- a/src/H5Ddeprec.c +++ b/src/H5Ddeprec.c @@ -232,7 +232,7 @@ H5Dextend(hid_t dset_id, const hsize_t size[]) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(dset_id, H5I_DATASET))) + if (NULL == (vol_obj = H5VL_vol_object_verify(dset_id, H5I_DATASET))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid dataset identifier"); if (!size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no size specified"); diff --git a/src/H5VLint.c b/src/H5VLint.c index a40d64e3ac4..19a11e9b6b8 100644 --- a/src/H5VLint.c +++ b/src/H5VLint.c @@ -1761,6 +1761,41 @@ H5VL_vol_object(hid_t id) FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL_vol_object() */ +/*------------------------------------------------------------------------- + * Function: H5VL_vol_object_verify + * + * Purpose: Utility function to return the object pointer associated with + * an ID of the specified type. This routine is the same as + * H5VL_vol_object except it takes the additional argument + * obj_type to verify the ID's type against. + * + * Return: Success: object pointer + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +H5VL_object_t * +H5VL_vol_object_verify(hid_t id, H5I_type_t obj_type) +{ + void *obj = NULL; + H5VL_object_t *ret_value = NULL; + + FUNC_ENTER_NOAPI(NULL) + + if (NULL == (obj = H5I_object_verify(id, obj_type))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "identifier is not of specified type"); + + /* If this is a datatype, get the VOL object attached to the H5T_t struct */ + if (H5I_DATATYPE == obj_type) + if (NULL == (obj = H5T_get_named_type((H5T_t *)obj))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a named datatype"); + + ret_value = (H5VL_object_t *)obj; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + /*------------------------------------------------------------------------- * Function: H5VL_object_data * diff --git a/src/H5VLprivate.h b/src/H5VLprivate.h index 79ed93c03ba..2904a5b1c15 100644 --- a/src/H5VLprivate.h +++ b/src/H5VLprivate.h @@ -96,6 +96,7 @@ H5_DLL void *H5VL_object_data(const H5VL_object_t *vol_obj); H5_DLL void *H5VL_object_unwrap(const H5VL_object_t *vol_obj); H5_DLL void *H5VL_object_verify(hid_t id, H5I_type_t obj_type); H5_DLL H5VL_object_t *H5VL_vol_object(hid_t id); +H5_DLL H5VL_object_t *H5VL_vol_object_verify(hid_t id, H5I_type_t obj_type); H5_DLL H5VL_object_t *H5VL_create_object(void *object, H5VL_t *vol_connector); H5_DLL H5VL_object_t *H5VL_create_object_using_vol_id(H5I_type_t type, void *obj, hid_t connector_id); H5_DLL hsize_t H5VL_object_inc_rc(H5VL_object_t *obj); From 379a5baa0f092fee403a959baf96c314f7139cd9 Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:17:35 -0400 Subject: [PATCH 25/94] Fix inconsistent documentation of get_name functions (#4715) - Verified that the listed functions do not include null terminator in the returned length - Improved some of the tests - Corrected documentation Fixes GH-4704 * Casted a positive int to size_t --- src/H5A.c | 42 +++++++++++++++++++++++++++--------------- src/H5Apublic.h | 15 +++------------ src/H5Epublic.h | 8 +++++--- src/H5Gdeprec.c | 7 +++---- src/H5Gpublic.h | 7 +------ src/H5Lpublic.h | 11 ++++------- test/error_test.c | 6 ++++-- test/links.c | 14 ++++++++++++-- test/tfile.c | 3 ++- test/th5o.c | 5 +++++ test/tmisc.c | 1 + test/trefer.c | 1 + 12 files changed, 68 insertions(+), 52 deletions(-) diff --git a/src/H5A.c b/src/H5A.c index 9bad7053a48..10475919fbe 100644 --- a/src/H5A.c +++ b/src/H5A.c @@ -1218,7 +1218,7 @@ H5Aget_create_plist(hid_t attr_id) DESCRIPTION This function retrieves the name of an attribute for an attribute ID. - Up to 'buf_size' characters are stored in 'buf' followed by a '\0' string + Up to 'buf_size'-1 characters are stored in 'buf' followed by a '\0' string terminator. If the name of the attribute is longer than 'buf_size'-1, the string terminator is stored in the last position of the buffer to properly terminate the string. @@ -1258,20 +1258,32 @@ H5Aget_name(hid_t attr_id, size_t buf_size, char *buf /*out*/) FUNC_LEAVE_API(ret_value) } /* H5Aget_name() */ -/*------------------------------------------------------------------------- - * Function: H5Aget_name_by_idx - * - * Purpose: Retrieve the name of an attribute, according to the - * order within an index. - * - * Same pattern of behavior as H5Iget_name. - * - * Return: Success: Non-negative length of name, with information - * in NAME buffer - * Failure: Negative - * - *------------------------------------------------------------------------- - */ +/*-------------------------------------------------------------------------- + NAME + H5Aget_name_by_idx + PURPOSE + Retrieve the name of an attribute, according to the order within an index. + USAGE + ssize_t H5Aget_name_by_idx(loc_id, obj_name, idx_type, order, n, name, size, lapl_id) + hid_t loc_id; IN: Object that attribute is attached to + const char *obj_name; IN: Name of the object relative to location + H5_index_t idx_type; IN: Type of index to use + H5_iter_order_t order; IN: Order to iterate over index + hsize_t n; IN: Index (0-based) of attribute to retrieve + char *name; IN: Buffer to store the name in + size_t size; IN: The size of the buffer to store the name in. + hid_t lapl_id; IN: Link access property list + RETURNS + This function returns the length of the attribute's name (which may be + longer than 'buf_size') on success or negative for failure. + + DESCRIPTION + This function retrieves the name of an attribute given its index. Up + to 'buf_size'-1 characters are stored in 'buf' followed by a '\0' string + terminator. If the name of the attribute is longer than 'buf_size'-1, + the string terminator is stored in the last position of the buffer to + properly terminate the string. +--------------------------------------------------------------------------*/ ssize_t H5Aget_name_by_idx(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, char *name /*out*/, size_t size, hid_t lapl_id) diff --git a/src/H5Apublic.h b/src/H5Apublic.h index 256d19cf355..7c28c0a24a2 100644 --- a/src/H5Apublic.h +++ b/src/H5Apublic.h @@ -501,15 +501,9 @@ H5_DLL herr_t H5Aget_info_by_name(hid_t loc_id, const char *obj_name, const char * value. * * \details H5Aget_name() retrieves the name of an attribute specified by - * the identifier, \p attr_id. Up to \p buf_size characters are - * stored in \p buf followed by a \0 string terminator. If the - * name of the attribute is longer than (\p buf_size -1), the - * string terminator is stored in the last position of the buffer - * to properly terminate the string. + * the identifier, \p attr_id. * - * If the user only wants to retrieve the name length, the - * values 0 and NULL should be passed for the parameters - * \p bufsize and \p buf. + * \details_namelen{attribute,H5Aget_name} * * \since 1.0.0 * @@ -544,10 +538,7 @@ H5_DLL ssize_t H5Aget_name(hid_t attr_id, size_t buf_size, char *buf); * traversal order, and a position in the index, \p idx_type, * \p order and \p n, respectively. * - * If the attribute name's size is unknown, the values 0 and NULL - * can be passed in for the parameters \p size and \p name. The - * function's return value will provide the correct value for - * \p size. + * \details_namelen{attribute,H5Aget_name_by_idx} * * The link access property list, \p lapl_id, may provide * information regarding the properties of links required to access diff --git a/src/H5Epublic.h b/src/H5Epublic.h index 49628efb9be..9263c3c96bf 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -420,9 +420,11 @@ H5_DLL herr_t H5Eclose_stack(hid_t stack_id); * by the class identifier. If a non-NULL pointer is passed in for \p * name and \p size is greater than zero, the class name of \p size * long is returned. The length of the error class name is also - * returned. If NULL is passed in as \p name, only the length of class - * name is returned. If zero is returned, it means no name. The user is - * responsible for allocating sufficient buffer space for the name. + * returned. + * + * \details_namelen{error class,H5Eget_class_name} + * + * If zero is returned, it means the error class has no name. * * \since 1.8.0 */ diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index 433748e4389..e86bc82c738 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -719,11 +719,10 @@ H5Gset_comment(hid_t loc_id, const char *name, const char *comment) * * Note: Deprecated in favor of H5Oget_comment/H5Oget_comment_by_name * - * Return: Success: Number of characters in the comment counting - * the null terminator. The value returned may - * be larger than the BUFSIZE argument. + * Return: Success: Number of characters in the comment. The value + * returned may be larger than the BUFSIZE argument. * - * Failure: Negative + * Failure: Negative * *------------------------------------------------------------------------- */ diff --git a/src/H5Gpublic.h b/src/H5Gpublic.h index 03c7dfbed6f..38880e787b7 100644 --- a/src/H5Gpublic.h +++ b/src/H5Gpublic.h @@ -960,12 +960,7 @@ H5_DLL herr_t H5Gset_comment(hid_t loc_id, const char *name, const char *comment * root group * \li A dot (\c .), if \p loc_id fully specifies the object * - * At most bufsize characters, including a null-terminator, are - * returned in \p buf. The returned value is not null-terminated if the - * comment is longer than the supplied buffer. If the size of the - * comment is unknown, a preliminary \p H5Gget_comment() call will - * return the size of the comment, including space for the - * null-terminator. + * \details_namelen{comment,H5Gget_comment} * * If an object does not have a comment, the empty string is returned * in comment. diff --git a/src/H5Lpublic.h b/src/H5Lpublic.h index 89998b838e7..ec325b8ad77 100644 --- a/src/H5Lpublic.h +++ b/src/H5Lpublic.h @@ -764,7 +764,7 @@ H5_DLL herr_t H5Lget_info2(hid_t loc_id, const char *name, H5L_info2_t *linfo, h * * \return \herr_t * - * \details H5get_info_by_idx2() returns the metadata for a link in a group + * \details H5Lget_info_by_idx2() returns the metadata for a link in a group * according to a specified field or index and a specified order. The * link for which information is to be returned is specified by \p * idx_type, \p order, and \p n as follows: @@ -819,7 +819,7 @@ H5_DLL herr_t H5Lget_info_by_idx2(hid_t loc_id, const char *group_name, H5_index * \return Returns the size of the link name if successful; otherwise returns a * negative value. * - * \details H5get_name_by_idx() retrieves the name of the \Emph{n}-th link in a + * \details H5Lget_name_by_idx() retrieves the name of the \Emph{n}-th link in a * group, according to the specified order, \p order, within a specified * field or index, \p idx_type. * @@ -835,10 +835,7 @@ H5_DLL herr_t H5Lget_info_by_idx2(hid_t loc_id, const char *group_name, H5_index * If \p loc_id specifies the group in which the link resides, * \p group_name can be a dot (\c .). * - * The size in bytes of name is specified in \p size. If \p size is - * unknown, it can be determined via an initial H5Lget_name_by_idx() - * call with name set to NULL; the function's return value will be the - * size of the name. + * \details_namelen{link,H5Lget_name_by_idx} * * \note Please note that in order for the specified index to correspond to the * creation order index, \p order must be set to #H5_ITER_INC or @@ -1578,7 +1575,7 @@ H5_DLL herr_t H5Lget_info1(hid_t loc_id, const char *name, H5L_info1_t *linfo /* * the function H5Lget_info_by_idx2() and the macro * H5Lget_info_by_idx(). * - * \details H5get_info_by_idx1() returns the metadata for a link in a group + * \details H5Lget_info_by_idx1() returns the metadata for a link in a group * according to a specified field or index and a specified order. * * The link for which information is to be returned is specified by \p diff --git a/test/error_test.c b/test/error_test.c index fe27300f431..204055097b8 100644 --- a/test/error_test.c +++ b/test/error_test.c @@ -175,12 +175,13 @@ test_error(hid_t file) static herr_t init_error(void) { - ssize_t cls_size = (ssize_t)strlen(ERR_CLS_NAME) + 1; + ssize_t cls_size = (ssize_t)strlen(ERR_CLS_NAME); ssize_t msg_size = (ssize_t)strlen(ERR_MIN_SUBROUTINE_MSG) + 1; char *cls_name = NULL; char *msg = NULL; H5E_type_t msg_type; + /* Account for null terminator */ if (NULL == (cls_name = (char *)malloc(strlen(ERR_CLS_NAME) + 1))) TEST_ERROR; if (NULL == (msg = (char *)malloc(strlen(ERR_MIN_SUBROUTINE_MSG) + 1))) @@ -189,7 +190,8 @@ init_error(void) if ((ERR_CLS = H5Eregister_class(ERR_CLS_NAME, PROG_NAME, PROG_VERS)) < 0) TEST_ERROR; - if (cls_size != H5Eget_class_name(ERR_CLS, cls_name, (size_t)cls_size) + 1) + /* Account for null terminator */ + if (cls_size != H5Eget_class_name(ERR_CLS, cls_name, (size_t)cls_size + 1)) TEST_ERROR; if (strcmp(ERR_CLS_NAME, cls_name) != 0) TEST_ERROR; diff --git a/test/links.c b/test/links.c index 222b3b66039..6612f56e363 100644 --- a/test/links.c +++ b/test/links.c @@ -1949,6 +1949,7 @@ test_deprec(hid_t fapl, bool new_format) hsize_t num_objs; /* Number of objects in a group */ char filename[1024]; char tmpstr[1024]; + int len = 0; /* Length of comment */ if (new_format) TESTING("backwards compatibility (w/new group format)"); @@ -1968,12 +1969,21 @@ test_deprec(hid_t fapl, bool new_format) FAIL_STACK_ERROR; /* Test H5Gset and get comment */ + if (H5Gset_comment(file_id, "group1", "comment") < 0) FAIL_STACK_ERROR; - if (H5Gget_comment(file_id, "group1", sizeof(tmpstr), tmpstr) < 0) + if ((len = H5Gget_comment(file_id, "group1", 0, NULL)) < 0) + FAIL_STACK_ERROR; + + /* Returned length should be the same as strlen of the comment */ + if ((size_t)len != strlen("comment")) + FAIL_STACK_ERROR; + + /* Get and verify the comment */ + if (H5Gget_comment(file_id, "group1", (size_t)len + 1, tmpstr) < 0) FAIL_STACK_ERROR; if (strcmp(tmpstr, "comment") != 0) - TEST_ERROR; + FAIL_STACK_ERROR; /* Create links using H5Glink and H5Glink2 */ if (H5Glink(file_id, H5G_LINK_HARD, "group2", "group1/link_to_group2") < 0) diff --git a/test/tfile.c b/test/tfile.c index a93b7be6857..92d75caf5e9 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -2420,10 +2420,11 @@ test_file_getname(void) file_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); CHECK(file_id, FAIL, "H5Fcreate"); - /* Get and verify file name */ + /* Get and verify file name and its length */ name_len = H5Fget_name(file_id, name, (size_t)TESTA_NAME_BUF_SIZE); CHECK(name_len, FAIL, "H5Fget_name"); VERIFY_STR(name, FILE1, "H5Fget_name"); + VERIFY(name_len, strlen(FILE1), "H5Fget_name"); /* Create a group in the root group */ group_id = H5Gcreate2(file_id, TESTA_GROUPNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); diff --git a/test/th5o.c b/test/th5o.c index 39d804a347e..0ea8d927e83 100644 --- a/test/th5o.c +++ b/test/th5o.c @@ -1220,6 +1220,7 @@ test_h5o_comment(void) /* Getting the comment on the file and verify it */ comment_len = H5Oget_comment(fid, NULL, (size_t)0); CHECK(comment_len, FAIL, "H5Oget_comment"); + VERIFY(comment_len, strlen(file_comment), "H5Oget_comment"); len = H5Oget_comment(fid, check_comment, (size_t)comment_len + 1); CHECK(len, FAIL, "H5Oget_comment"); @@ -1237,6 +1238,7 @@ test_h5o_comment(void) len = H5Oget_comment(grp, check_comment, (size_t)comment_len + 1); CHECK(len, FAIL, "H5Oget_comment"); + VERIFY(len, strlen(grp_comment), "H5Oget_comment"); ret_value = strcmp(grp_comment, check_comment); VERIFY(ret_value, 0, "H5Oget_comment"); @@ -1248,6 +1250,7 @@ test_h5o_comment(void) /* Getting the comment on the datatype and verify it */ comment_len = H5Oget_comment(dtype, NULL, (size_t)0); CHECK(comment_len, FAIL, "H5Oget_comment"); + VERIFY(comment_len, strlen(dtype_comment), "H5Oget_comment"); len = H5Oget_comment(dtype, check_comment, (size_t)comment_len + 1); CHECK(len, FAIL, "H5Oget_comment"); @@ -1265,6 +1268,7 @@ test_h5o_comment(void) len = H5Oget_comment(dset, check_comment, (size_t)comment_len + 1); CHECK(ret, len, "H5Oget_comment"); + VERIFY(len, strlen(dset_comment), "H5Oget_comment"); ret_value = strcmp(dset_comment, check_comment); VERIFY(ret_value, 0, "H5Oget_comment"); @@ -1406,6 +1410,7 @@ test_h5o_comment_by_name(void) len = H5Oget_comment_by_name(fid, ".", check_comment, (size_t)comment_len + 1, H5P_DEFAULT); CHECK(len, FAIL, "H5Oget_comment_by_name"); + VERIFY(len, strlen(file_comment), "H5Oget_comment"); ret_value = strcmp(file_comment, check_comment); VERIFY(ret_value, 0, "H5Oget_comment_by_name"); diff --git a/test/tmisc.c b/test/tmisc.c index a9d94a5ec97..63bf5d8edcb 100644 --- a/test/tmisc.c +++ b/test/tmisc.c @@ -4296,6 +4296,7 @@ test_misc23(void) namelen = H5Iget_name(tmp_id, objname, (size_t)MISC23_NAME_BUF_SIZE); CHECK(namelen, FAIL, "H5Iget_name"); VERIFY_STR(objname, "/A/B01/grp", "H5Iget_name"); + VERIFY(namelen, strlen("/A/B01/grp"), "H5Iget_name"); status = H5Gclose(tmp_id); CHECK(status, FAIL, "H5Gclose"); diff --git a/test/trefer.c b/test/trefer.c index 6e5bd65e48b..b1e4a3854b4 100644 --- a/test/trefer.c +++ b/test/trefer.c @@ -2417,6 +2417,7 @@ test_reference_group(void) H5P_DEFAULT); CHECK(size, (-1), "H5Lget_name_by_idx"); VERIFY_STR(objname, DSETNAME2, "H5Lget_name_by_idx"); + VERIFY(size, strlen(DSETNAME2), "H5Lget_name_by_idx"); ret = H5Oget_info_by_idx3(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)0, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); From 7cf3963f8d74d29a4ebab6b05f1b7ec2f71bba6b Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Fri, 23 Aug 2024 09:41:33 -0700 Subject: [PATCH 26/94] Remove HDF-EOS5 CI action (#4750) The code can't be downloaded due to changes that put it behind an EarthData login. We'll disable this while we figure out a work-around. --- .github/workflows/hdfeos5.yml | 51 ----------------------------------- README.md | 1 - 2 files changed, 52 deletions(-) delete mode 100644 .github/workflows/hdfeos5.yml diff --git a/.github/workflows/hdfeos5.yml b/.github/workflows/hdfeos5.yml deleted file mode 100644 index 0d5cf969382..00000000000 --- a/.github/workflows/hdfeos5.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: hdfeos5 dev - -# Triggers the workflow on push or pull request or on demand -on: - workflow_dispatch: - push: - pull_request: - branches: [ develop ] - paths-ignore: - - '.github/CODEOWNERS' - - '.github/FUNDING.yml' - - 'doc/**' - - 'release_docs/**' - - 'ACKNOWLEDGEMENTS' - - 'COPYING**' - - '**.md' - -# Using concurrency to cancel any in-progress job or run -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - build: - name: Build hdfeos5 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4.1.7 - - - name: Install Autotools Dependencies (Linux) - run: | - sudo apt update - sudo apt install automake autoconf libtool libtool-bin - - name: Install HDF5 - run: | - ./autogen.sh - ./configure --prefix=/usr/local --disable-tests --with-default-api-version=v16 - make - sudo make install - - name: Install HDF-EOS5 - run: | - wget -O HDF-EOS5.2.0.tar.gz "https://git.earthdata.nasa.gov/projects/DAS/repos/hdfeos5/raw/hdf-eos5-2.0-src.tar.gz?at=refs%2Fheads%2FHDFEOS5_2.0" - tar zxvf HDF-EOS5.2.0.tar.gz - cd hdf-eos5-2.0 - ./configure CC=/usr/local/bin/h5cc --prefix=/usr/local/ --enable-install-include - make - make check - sudo make install diff --git a/README.md b/README.md index f5d6a54c695..36f853c6990 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ HDF5 version 1.15.0 currently under development [![develop cmake build status](https://img.shields.io/github/actions/workflow/status/HDFGroup/hdf5/cmake.yml?branch=develop&label=HDF5%20develop%20CMake%20CI)](https://github.com/HDFGroup/hdf5/actions/workflows/cmake.yml?query=branch%3Adevelop) [![develop autotools build status](https://img.shields.io/github/actions/workflow/status/HDFGroup/hdf5/autotools.yml?branch=develop&label=HDF5%20develop%20Autotools%20CI)](https://github.com/HDFGroup/hdf5/actions/workflows/autotools.yml?query=branch%3Adevelop) -[![HDF-EOS5 build status](https://img.shields.io/github/actions/workflow/status/HDFGroup/hdf5/hdfeos5.yml?branch=develop&label=HDF-EOS5)](https://github.com/HDFGroup/hdf5/actions/workflows/hdfeos5.yml?query=branch%3Adevelop) [![netCDF build status](https://img.shields.io/github/actions/workflow/status/HDFGroup/hdf5/netcdf.yml?branch=develop&label=netCDF)](https://github.com/HDFGroup/hdf5/actions/workflows/netcdf.yml?query=branch%3Adevelop) [![h5py build status](https://img.shields.io/github/actions/workflow/status/HDFGroup/hdf5/h5py.yml?branch=develop&label=h5py)](https://github.com/HDFGroup/hdf5/actions/workflows/h5py.yml?query=branch%3Adevelop) [![CVE regression](https://img.shields.io/github/actions/workflow/status/HDFGroup/hdf5/cve.yml?branch=develop&label=CVE)](https://github.com/HDFGroup/hdf5/actions/workflows/cve.yml?query=branch%3Adevelop) From 9adacb54a635e0da9c5845ce8a577c3ffaae6623 Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:44:48 -0400 Subject: [PATCH 27/94] Replace non-VOL calls with VOL calls - part 2 (#4748) This PR switches H5I_object_verify() to H5VL_vol_object_verify() in the H5F API and fixes documentation of H5Fmount and H5Funmount. * More on H5F API --- src/H5F.c | 74 ++++++++++++++++++++++++------------------------- src/H5Fdeprec.c | 2 +- src/H5Fpublic.h | 10 +++---- test/mount.c | 25 +++++++++++++++++ test/tfile.c | 8 ++++++ 5 files changed, 76 insertions(+), 43 deletions(-) diff --git a/src/H5F.c b/src/H5F.c index 390f667648b..5dd7bda3903 100644 --- a/src/H5F.c +++ b/src/H5F.c @@ -118,7 +118,7 @@ H5Fget_create_plist(hid_t file_id) FUNC_ENTER_API(H5I_INVALID_HID) /* check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -164,7 +164,7 @@ H5Fget_access_plist(hid_t file_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -239,7 +239,7 @@ H5Fget_obj_count(hid_t file_id, unsigned types) H5VL_file_get_args_t vol_cb_args; /* Arguments to VOL callback */ /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not a file id"); /* Set up VOL callback arguments */ @@ -358,7 +358,7 @@ H5Fget_obj_ids(hid_t file_id, unsigned types, size_t max_objs, hid_t *oid_list / H5VL_file_get_args_t vol_cb_args; /* Arguments to VOL callback */ /* get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "invalid file identifier"); /* Set up VOL callback arguments */ @@ -439,7 +439,7 @@ H5Fget_vfd_handle(hid_t file_id, hid_t fapl_id, void **file_handle /*out*/) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file handle pointer"); /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1226,7 +1226,7 @@ H5Fmount(hid_t loc_id, const char *name, hid_t child_id, hid_t plist_id) H5VL_loc_params_t loc_params; /* Location parameters for object access */ /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set location parameters */ @@ -1244,12 +1244,12 @@ H5Fmount(hid_t loc_id, const char *name, hid_t child_id, hid_t plist_id) } /* end if */ else { assert(H5I_GROUP == loc_type); - if (NULL == (loc_vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (loc_vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not get location object"); } /* end else */ /* Get the child object */ - if (NULL == (child_vol_obj = (H5VL_object_t *)H5I_object(child_id))) + if (NULL == (child_vol_obj = H5VL_vol_object(child_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not get child object"); /* Check if both objects are associated with the same VOL connector */ @@ -1336,7 +1336,7 @@ H5Funmount(hid_t loc_id, const char *name) H5VL_loc_params_t loc_params; /* Location parameters for object access */ /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5VL_vol_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set location parameters */ @@ -1354,7 +1354,7 @@ H5Funmount(hid_t loc_id, const char *name) } /* end if */ else { assert(H5I_GROUP == loc_type); - if (NULL == (loc_vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (loc_vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not get location object"); } /* end else */ @@ -1404,7 +1404,7 @@ H5F__reopen_api_common(hid_t file_id, void **token_ptr) FUNC_ENTER_PACKAGE /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1555,7 +1555,7 @@ H5Fget_intent(hid_t file_id, unsigned *intent_flags /*out*/) H5VL_file_get_args_t vol_cb_args; /* Arguments to VOL callback */ /* Get the internal file structure */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1594,7 +1594,7 @@ H5Fget_fileno(hid_t file_id, unsigned long *fnumber /*out*/) H5VL_file_get_args_t vol_cb_args; /* Arguments to VOL callback */ /* Get the internal file structure */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1631,7 +1631,7 @@ H5Fget_freespace(hid_t file_id) FUNC_ENTER_API((-1)) /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1674,7 +1674,7 @@ H5Fget_filesize(hid_t file_id, hsize_t *size /*out*/) /* Check args */ if (!size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "size parameter cannot be NULL"); - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up VOL callback arguments */ @@ -1739,7 +1739,7 @@ H5Fget_file_image(hid_t file_id, void *buf /*out*/, size_t buf_len) FUNC_ENTER_API((-1)) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "not a file ID"); /* Set up VOL callback arguments */ @@ -1789,7 +1789,7 @@ H5Fget_mdc_config(hid_t file_id, H5AC_cache_config_t *config /*out*/) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Bad config ptr"); /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1827,7 +1827,7 @@ H5Fset_mdc_config(hid_t file_id, const H5AC_cache_config_t *config_ptr) FUNC_ENTER_API(FAIL) /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -1868,7 +1868,7 @@ H5Fget_mdc_hit_rate(hid_t file_id, double *hit_rate /*out*/) /* Check args */ if (NULL == hit_rate) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL hit rate pointer"); - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up VOL callback arguments */ @@ -1910,7 +1910,7 @@ H5Fget_mdc_size(hid_t file_id, size_t *max_size /*out*/, size_t *min_clean_size FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up VOL callback arguments */ @@ -1959,7 +1959,7 @@ H5Freset_mdc_hit_rate_stats(hid_t file_id) FUNC_ENTER_API(FAIL) /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -2109,7 +2109,7 @@ H5Fget_metadata_read_retry_info(hid_t file_id, H5F_retry_info_t *info /*out*/) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no info struct"); /* Get the file pointer */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up VOL callback arguments */ @@ -2149,7 +2149,7 @@ H5Fget_free_sections(hid_t file_id, H5F_mem_t type, size_t nsects, H5F_sect_info FUNC_ENTER_API((-1)) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "invalid file identifier"); if (sect_info && nsects == 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "nsects must be > 0"); @@ -2194,7 +2194,7 @@ H5Fclear_elink_file_cache(hid_t file_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up VOL callback arguments */ @@ -2253,7 +2253,7 @@ H5Fstart_swmr_write(hid_t file_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Set up collective metadata if appropriate */ @@ -2292,7 +2292,7 @@ H5Fstart_mdc_logging(hid_t file_id) FUNC_ENTER_API(FAIL) /* Sanity check */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Set up VOL callback arguments */ @@ -2328,7 +2328,7 @@ H5Fstop_mdc_logging(hid_t file_id) FUNC_ENTER_API(FAIL) /* Sanity check */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Set up VOL callback arguments */ @@ -2365,7 +2365,7 @@ H5Fget_mdc_logging_status(hid_t file_id, hbool_t *is_enabled /*out*/, hbool_t *i FUNC_ENTER_API(FAIL) /* Sanity check */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Set up VOL callback arguments */ @@ -2405,7 +2405,7 @@ H5Fset_libver_bounds(hid_t file_id, H5F_libver_t low, H5F_libver_t high) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up collective metadata if appropriate */ @@ -2447,7 +2447,7 @@ H5Fformat_convert(hid_t file_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "file_id parameter is not a valid file identifier"); /* Set up collective metadata if appropriate */ @@ -2485,7 +2485,7 @@ H5Freset_page_buffering_stats(hid_t file_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -2522,7 +2522,7 @@ H5Fget_page_buffering_stats(hid_t file_id, unsigned accesses[2] /*out*/, unsigne FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a file ID"); if (NULL == accesses || NULL == hits || NULL == misses || NULL == evictions || NULL == bypasses) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "NULL input parameters for stats"); @@ -2568,7 +2568,7 @@ H5Fget_mdc_image_info(hid_t file_id, haddr_t *image_addr /*out*/, hsize_t *image FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Set up VOL callback arguments */ @@ -2605,7 +2605,7 @@ H5Fget_eoa(hid_t file_id, haddr_t *eoa /*out*/) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Only do work if valid pointer to fill in */ @@ -2647,7 +2647,7 @@ H5Fincrement_filesize(hid_t file_id, hsize_t increment) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hid_t identifier is not a file ID"); /* Set up VOL callback arguments */ @@ -2686,7 +2686,7 @@ H5Fget_dset_no_attrs_hint(hid_t file_id, hbool_t *minimize /*out*/) /* Check args */ if (NULL == minimize) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "out pointer 'minimize' cannot be NULL"); - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ @@ -2723,7 +2723,7 @@ H5Fset_dset_no_attrs_hint(hid_t file_id, hbool_t minimize) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Set up VOL callback arguments */ diff --git a/src/H5Fdeprec.c b/src/H5Fdeprec.c index 06141de767b..c7552840bc1 100644 --- a/src/H5Fdeprec.c +++ b/src/H5Fdeprec.c @@ -214,7 +214,7 @@ H5Fset_latest_format(hid_t file_id, hbool_t latest_format) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(file_id, H5I_FILE))) + if (NULL == (vol_obj = H5VL_vol_object_verify(file_id, H5I_FILE))) HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "not a file ID"); /* Set up collective metadata if appropriate */ diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index eb22f6abf7d..1e5a84cdb09 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -874,7 +874,7 @@ H5_DLL herr_t H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle); * * \brief Mounts an HDF5 file * - * \loc_id{loc} + * \fg_loc_id{loc_id} * \param[in] name Name of the group onto which the file specified by \p child * is to be mounted * \file_id{child} @@ -898,13 +898,13 @@ H5_DLL herr_t H5Fget_vfd_handle(hid_t file_id, hid_t fapl, void **file_handle); * \since 1.0.0 * */ -H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist); +H5_DLL herr_t H5Fmount(hid_t loc_id, const char *name, hid_t child, hid_t plist); /** * \ingroup H5F * - * \brief Unounts an HDF5 file + * \brief Un-mounts an HDF5 file * - * \loc_id{loc} + * \fg_loc_id{loc_id} * \param[in] name Name of the mount point * * \return \herr_t @@ -922,7 +922,7 @@ H5_DLL herr_t H5Fmount(hid_t loc, const char *name, hid_t child, hid_t plist); * \since 1.0.0 * */ -H5_DLL herr_t H5Funmount(hid_t loc, const char *name); +H5_DLL herr_t H5Funmount(hid_t loc_id, const char *name); /** * \ingroup H5F * diff --git a/test/mount.c b/test/mount.c index 92a0c13d84c..2d833fbf102 100644 --- a/test/mount.c +++ b/test/mount.c @@ -164,6 +164,7 @@ test_illegal(hid_t fapl) { hid_t file1 = H5I_INVALID_HID, file1b = H5I_INVALID_HID, file2 = H5I_INVALID_HID, file3 = H5I_INVALID_HID, file3b = H5I_INVALID_HID, mnt = H5I_INVALID_HID; + hid_t dtype = H5I_INVALID_HID; /* To test invalid ID */ char filename1[1024], filename2[1024], filename3[1024]; herr_t status; @@ -259,6 +260,30 @@ test_illegal(hid_t fapl) if (H5Funmount(file1, "/mnt1") < 0) FAIL_STACK_ERROR; + /* Try passing in IDs that are not a file or group ID */ + if ((dtype = H5Tcopy(H5T_C_S1)) < 0) + FAIL_STACK_ERROR; + H5E_BEGIN_TRY + { + status = H5Fmount(dtype, "/mnt1", file1b, H5P_DEFAULT); + } + H5E_END_TRY + if (status >= 0) { + H5_FAILED(); + puts(" Passing in an ID other than file or group ID should have failed."); + TEST_ERROR; + } /* end if */ + H5E_BEGIN_TRY + { + status = H5Funmount(dtype, "/mnt1"); + } + H5E_END_TRY + if (status >= 0) { + H5_FAILED(); + puts(" Passing in an ID other than file or group ID should have failed."); + TEST_ERROR; + } /* end if */ + /* Close everything and return */ if (H5Fclose(file1) < 0) FAIL_STACK_ERROR; diff --git a/test/tfile.c b/test/tfile.c index 92d75caf5e9..1c8e6a04b1f 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -8198,6 +8198,14 @@ test_deprec(const char *driver_name) fcpl = H5Fget_create_plist(file); CHECK(fcpl, FAIL, "H5Fget_create_plist"); + /* Test passing in an ID that is not a file ID, should fail */ + H5E_BEGIN_TRY + { + ret = H5Fset_latest_format(fcpl, true); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Fset_latest_format"); + /* Get the file's version information */ ret = H5Pget_version(fcpl, &super, &freelist, &stab, &shhdr); CHECK(ret, FAIL, "H5Pget_version"); From 5c5b72712788014d3debf7f08de8c9f03315b1c1 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:22:40 -0700 Subject: [PATCH 28/94] Restore rand_r in a few parallel tests (#4749) The t_pmulti_dset and t_select_io_dset tests rely on the behavior of the previous private rand_r-like implementation to get the correct sequence of random numbers to pass. This has been restored using a fully private rand_r-like implementation that doesn't rely on rand_r and will work on Windows and other platforms where rand_r doesn't exist. --- test/h5test.c | 21 ++++++++++++++++ test/h5test.h | 8 ++++++ testpar/t_pmulti_dset.c | 51 ++++++++++++++++++++------------------ testpar/t_select_io_dset.c | 14 +++++------ 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/test/h5test.c b/test/h5test.c index 01216ca1059..61c01da529c 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -2563,3 +2563,24 @@ h5_driver_uses_multiple_files(const char *drv_name, unsigned flags) return ret_val; } + +/* Deterministic random number functions that don't modify the underlying + * C/POSIX library rand/random state, as this can cause spurious test failures. + * + * Adapted from the example code in the POSIX.1-2001 standard. + */ + +static unsigned int next_g = 1; + +int +h5_local_rand(void) +{ + next_g = next_g * 1103515245 + 12345; + return next_g & RAND_MAX; +} + +void +h5_local_srand(unsigned int seed) +{ + next_g = seed; +} diff --git a/test/h5test.h b/test/h5test.h index 238bd38acd6..1ec537c62e3 100644 --- a/test/h5test.h +++ b/test/h5test.h @@ -319,6 +319,14 @@ H5TEST_DLL herr_t h5_using_parallel_driver(hid_t fapl_id, bool *driver_i H5TEST_DLL herr_t h5_driver_is_default_vfd_compatible(hid_t fapl_id, bool *default_vfd_compatible); H5TEST_DLL bool h5_driver_uses_multiple_files(const char *drv_name, unsigned flags); +/* Random number functions that don't modify the underlying rand/random state. + * These use rand_r with a state pointer under the hood. The state is always + * initialized to the same value so that each process in the parallel tests + * always gets the same sequence. + */ +H5TEST_DLL int h5_local_rand(void); +H5TEST_DLL void h5_local_srand(unsigned int seed); + /* Functions that will replace components of a FAPL */ H5TEST_DLL herr_t h5_get_vfd_fapl(hid_t fapl_id); H5TEST_DLL herr_t h5_get_libver_fapl(hid_t fapl_id); diff --git a/testpar/t_pmulti_dset.c b/testpar/t_pmulti_dset.c index 622690dbece..e9819840cb3 100644 --- a/testpar/t_pmulti_dset.c +++ b/testpar/t_pmulti_dset.c @@ -267,7 +267,7 @@ test_pmdset(size_t niter, unsigned flags) for (i = 0; i < niter; i++) { /* Determine number of datasets */ ndsets = (flags & MDSET_FLAG_MLAYOUT) ? 3 - : (flags & MDSET_FLAG_MDSET) ? (size_t)((size_t)rand() % max_dsets) + 1 + : (flags & MDSET_FLAG_MDSET) ? (size_t)((size_t)h5_local_rand() % max_dsets) + 1 : 1; /* Create file */ @@ -280,16 +280,16 @@ test_pmdset(size_t niter, unsigned flags) (flags & MDSET_FLAG_CHUNK) || ((flags & MDSET_FLAG_MLAYOUT) && (j == 1 || j == 2)); /* Generate file dataspace */ - dset_dims[j][0] = (hsize_t)((rand() % MAX_DSET_X) + 1); - dset_dims[j][1] = (hsize_t)((rand() % MAX_DSET_Y) + 1); + dset_dims[j][0] = (hsize_t)((h5_local_rand() % MAX_DSET_X) + 1); + dset_dims[j][1] = (hsize_t)((h5_local_rand() % MAX_DSET_Y) + 1); if ((file_space_ids[j] = H5Screate_simple(2, dset_dims[j], use_chunk ? max_dims : NULL)) < 0) T_PMD_ERROR; /* Generate chunk if called for by configuration (multi layout uses chunked for datasets * 1 and 2) */ if (use_chunk) { - chunk_dims[0] = (hsize_t)((rand() % MAX_CHUNK_X) + 1); - chunk_dims[1] = (hsize_t)((rand() % MAX_CHUNK_Y) + 1); + chunk_dims[0] = (hsize_t)((h5_local_rand() % MAX_CHUNK_X) + 1); + chunk_dims[1] = (hsize_t)((h5_local_rand() % MAX_CHUNK_Y) + 1); if (H5Pset_chunk(dcpl_id[j], 2, chunk_dims) < 0) T_PMD_ERROR; } /* end if */ @@ -297,10 +297,10 @@ test_pmdset(size_t niter, unsigned flags) /* Create dataset */ /* If MDSET_FLAG_TCONV is set, use a different datatype with 50% probability, so * some datasets require type conversion and others do not */ - if ((dset_ids[j] = - H5Dcreate2(file_id, dset_name[j], - (flags & MDSET_FLAG_TCONV && rand() % 2) ? H5T_NATIVE_LONG : H5T_NATIVE_UINT, - file_space_ids[j], H5P_DEFAULT, dcpl_id[j], H5P_DEFAULT)) < 0) + if ((dset_ids[j] = H5Dcreate2(file_id, dset_name[j], + (flags & MDSET_FLAG_TCONV && h5_local_rand() % 2) ? H5T_NATIVE_LONG + : H5T_NATIVE_UINT, + file_space_ids[j], H5P_DEFAULT, dcpl_id[j], H5P_DEFAULT)) < 0) T_PMD_ERROR; } /* end for */ @@ -325,7 +325,7 @@ test_pmdset(size_t niter, unsigned flags) /* Perform read/write operations */ for (j = 0; j < OPS_PER_FILE; j++) { /* Decide whether to read or write */ - do_read = (bool)(rand() % 2); + do_read = (bool)(h5_local_rand() % 2); /* Barrier to ensure processes have finished the previous operation */ @@ -387,9 +387,9 @@ test_pmdset(size_t niter, unsigned flags) (int)((unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y) * ((int)l - (int)mpi_rank); /* Decide whether to do a hyperslab or point selection */ - if (rand() % 2) { + if (h5_local_rand() % 2) { /* Hyperslab */ - size_t nhs = (size_t)((rand() % MAX_HS) + 1); /* Number of hyperslabs */ + size_t nhs = (size_t)((h5_local_rand() % MAX_HS) + 1); /* Number of hyperslabs */ size_t max_hs_x = (MAX_HS_X <= dset_dims[k][0]) ? MAX_HS_X : dset_dims[k][0]; /* Determine maximum hyperslab size in X */ @@ -401,14 +401,16 @@ test_pmdset(size_t niter, unsigned flags) overlap = true; for (n = 0; overlap && (n < MAX_SEL_RETRIES); n++) { /* Generate hyperslab */ - count[m][0] = (hsize_t)(((hsize_t)rand() % max_hs_x) + 1); - count[m][1] = (hsize_t)(((hsize_t)rand() % max_hs_y) + 1); - start[m][0] = (count[m][0] == dset_dims[k][0]) - ? 0 - : (hsize_t)rand() % (dset_dims[k][0] - count[m][0] + 1); - start[m][1] = (count[m][1] == dset_dims[k][1]) - ? 0 - : (hsize_t)rand() % (dset_dims[k][1] - count[m][1] + 1); + count[m][0] = (hsize_t)(((hsize_t)h5_local_rand() % max_hs_x) + 1); + count[m][1] = (hsize_t)(((hsize_t)h5_local_rand() % max_hs_y) + 1); + start[m][0] = + (count[m][0] == dset_dims[k][0]) + ? 0 + : (hsize_t)h5_local_rand() % (dset_dims[k][0] - count[m][0] + 1); + start[m][1] = + (count[m][1] == dset_dims[k][1]) + ? 0 + : (hsize_t)h5_local_rand() % (dset_dims[k][1] - count[m][1] + 1); /* If writing, check for overlap with other processes */ overlap = false; @@ -460,7 +462,8 @@ test_pmdset(size_t niter, unsigned flags) } /* end if */ else { /* Point selection */ - size_t npoints = (size_t)(((size_t)rand() % MAX_POINTS) + 1); /* Number of points */ + size_t npoints = + (size_t)(((size_t)h5_local_rand() % MAX_POINTS) + 1); /* Number of points */ /* Reset dataset usage array if reading, since in this case we don't care * about overlapping selections between processes */ @@ -472,8 +475,8 @@ test_pmdset(size_t niter, unsigned flags) overlap = true; for (n = 0; overlap && (n < MAX_SEL_RETRIES); n++) { /* Generate point */ - points[2 * m] = (unsigned)((hsize_t)rand() % dset_dims[k][0]); - points[(2 * m) + 1] = (unsigned)((hsize_t)rand() % dset_dims[k][1]); + points[2 * m] = (unsigned)((hsize_t)h5_local_rand() % dset_dims[k][0]); + points[(2 * m) + 1] = (unsigned)((hsize_t)h5_local_rand() % dset_dims[k][1]); /* Check for overlap with other processes (write) or this process * (always) */ @@ -664,7 +667,7 @@ main(int argc, char *argv[]) /* Seed random number generator with shared seed (so all ranks generate the * same sequence) */ - srand(seed); + h5_local_srand(seed); /* Fill dset_name array */ for (i = 0; i < MAX_DSETS; i++) { diff --git a/testpar/t_select_io_dset.c b/testpar/t_select_io_dset.c index 271d38c7fbd..a6e62c6f8e5 100644 --- a/testpar/t_select_io_dset.c +++ b/testpar/t_select_io_dset.c @@ -1588,7 +1588,7 @@ test_multi_dsets_no_bkg(hid_t fid, unsigned chunked, unsigned dtrans, unsigned s mwbuf ? "mwbuf" : "nomwbuf"); /* Flip a coin to see if we're doing type conversion */ - tconv = rand() % 2; + tconv = h5_local_rand() % 2; if (tconv) any_tconv = true; @@ -2079,7 +2079,7 @@ test_multi_dsets_cmpd_with_bkg(hid_t fid, unsigned chunked, unsigned select, uns } /* Case c */ - mm = rand() % (int)ndsets; + mm = h5_local_rand() % (int)ndsets; if (!mm) mm++; @@ -2719,9 +2719,9 @@ test_multi_dsets_conv_sel_empty(hid_t fid, unsigned chunked, unsigned dtrans, un P_TEST_ERROR; } else { - if ((dset_dids[i] = - H5Dcreate2(fid, dset_names[i], ((rand() % 2) ? H5T_NATIVE_LLONG : H5T_NATIVE_SHORT), - file_sids[i], H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) + if ((dset_dids[i] = H5Dcreate2(fid, dset_names[i], + ((h5_local_rand() % 2) ? H5T_NATIVE_LLONG : H5T_NATIVE_SHORT), + file_sids[i], H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) P_TEST_ERROR; } } @@ -2790,7 +2790,7 @@ test_multi_dsets_conv_sel_empty(hid_t fid, unsigned chunked, unsigned dtrans, un * process 0: get 0 row; other processes: hyperslab */ - mm = rand() % (int)ndsets; + mm = h5_local_rand() % (int)ndsets; if (mm == 0) mm++; @@ -3169,7 +3169,7 @@ test_multi_dsets_all(int niter, hid_t fid, unsigned chunked, unsigned select, un if ((mem_sids[i] = H5Screate_simple(1, block, NULL)) < 0) P_TEST_ERROR; - mm = rand() % (int)ndsets; + mm = h5_local_rand() % (int)ndsets; if (mm == 0) { dset_types[i] = DSET_WITH_NO_CONV; snprintf(dset_names[i], sizeof(dset_names[i]), "multi_all_nconv_dset%d_%s_%s_%s", i, From 7c4b501fc7df025f2fa96981bfa7d01312fd0039 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:37:28 -0700 Subject: [PATCH 29/94] Don't run AOCC parallel tests with -j2 (#4752) Don't run parallel tests in both Autotools and CMake with multiple processes. ph5diff still runs with -j2 w/ Autotools since the test script is in the tools/test/h5diff directory. * Split off AOCC CMake parallel tests * Remove unnecessary NPROCS env vars * Put NPROCS back in serial tests We run ph5diff tests there --- .github/workflows/aocc-auto.yml | 16 ++++++++++++---- .github/workflows/aocc-cmake.yml | 8 +++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/aocc-auto.yml b/.github/workflows/aocc-auto.yml index a1927eb0403..b556737e3b1 100644 --- a/.github/workflows/aocc-auto.yml +++ b/.github/workflows/aocc-auto.yml @@ -79,24 +79,32 @@ jobs: - name: Autotools Build shell: bash - env: - NPROCS: 2 run: | export PATH=/home/runner/work/hdf5/hdf5/openmpi-4.1.6-install/bin:/usr/local/bin:$PATH make -j3 working-directory: ${{ runner.workspace }}/build + # ph5diff tests are in the tools/tests directory so they will get run + # here, so leave NPROCS set here as well - name: Autotools Run Tests env: NPROCS: 2 run: | export PATH=/home/runner/work/hdf5/hdf5/openmpi-4.1.6-install/bin:/usr/local/bin:$PATH - make check -j + cd test && make check -j2 && cd .. + cd tools && make check -j2 && cd .. + cd hl && make check -j2 && cd .. working-directory: ${{ runner.workspace }}/build - - name: Autotools Install + - name: Autotools Run Parallel Tests env: NPROCS: 2 + run: | + export PATH=/home/runner/work/hdf5/hdf5/openmpi-4.1.6-install/bin:/usr/local/bin:$PATH + cd testpar && make check && cd .. + working-directory: ${{ runner.workspace }}/build + + - name: Autotools Install run: | export PATH=/home/runner/work/hdf5/hdf5/openmpi-4.1.6-install/bin:/usr/local/bin:$PATH make install diff --git a/.github/workflows/aocc-cmake.yml b/.github/workflows/aocc-cmake.yml index 71966caf41e..92ac0d25fe8 100644 --- a/.github/workflows/aocc-cmake.yml +++ b/.github/workflows/aocc-cmake.yml @@ -89,5 +89,11 @@ jobs: - name: CMake Run Tests shell: bash run: | - ctest . --parallel 2 -C ${{ inputs.build_mode }} -V + ctest . -E MPI_TEST --parallel 2 -C ${{ inputs.build_mode }} -V + working-directory: ${{ runner.workspace }}/build + + - name: CMake Run Parallel Tests + shell: bash + run: | + ctest . -R MPI_TEST -C ${{ inputs.build_mode }} -V working-directory: ${{ runner.workspace }}/build From c38064b7f7886e59c13438fba8ec7bb6d55d0fb8 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sat, 24 Aug 2024 21:39:56 -0500 Subject: [PATCH 30/94] Another try at correcting the ping pong semaphore test (#4754) * Add ifdef around prototype * Add casts to make MSVC happy * Fix missing atomic load --- src/H5TSwin.c | 2 ++ test/ttsafe_semaphore.c | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/H5TSwin.c b/src/H5TSwin.c index 4eca38e34db..913dbff0099 100644 --- a/src/H5TSwin.c +++ b/src/H5TSwin.c @@ -45,10 +45,12 @@ /********************/ /* Local Prototypes */ /********************/ +#ifdef H5_HAVE_THREADSAFE #if defined(H5_BUILT_AS_DYNAMIC_LIB) && defined(H5_HAVE_WIN32_API) static herr_t H5TS__win32_thread_enter(void); static herr_t H5TS__win32_thread_exit(void); #endif +#endif /*********************/ /* Package Variables */ diff --git a/test/ttsafe_semaphore.c b/test/ttsafe_semaphore.c index 313508fe315..37c8ed29941 100644 --- a/test/ttsafe_semaphore.c +++ b/test/ttsafe_semaphore.c @@ -20,14 +20,14 @@ #if defined(H5_HAVE_THREADS) -#define NUM_PINGPONG (1000 * 1000) +#define NUM_PINGPONG (500 * 1000) #define NUM_CLIENTSERVER (50 * 1000) #define NUM_THREADS 16 typedef struct { - H5TS_semaphore_t ping_sem, pong_sem; - unsigned counter; + H5TS_semaphore_t ping_sem, pong_sem; + H5TS_atomic_uint_t counter; } pingpong_t; typedef struct { @@ -40,7 +40,6 @@ static H5TS_THREAD_RETURN_TYPE ping(void *_test_info) { pingpong_t *test_info = (pingpong_t *)_test_info; - unsigned count; herr_t result; H5TS_thread_ret_t ret_value = 0; @@ -48,11 +47,11 @@ ping(void *_test_info) result = H5TS_semaphore_wait(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_wait"); - count = ++test_info->counter; + H5TS_atomic_fetch_add_uint(&test_info->counter, (unsigned)1); result = H5TS_semaphore_signal(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (count < NUM_PINGPONG); + } while (H5TS_atomic_load_uint(&test_info->counter) < NUM_PINGPONG); return ret_value; } @@ -61,7 +60,6 @@ static H5TS_THREAD_RETURN_TYPE pong(void *_test_info) { pingpong_t *test_info = (pingpong_t *)_test_info; - unsigned count; herr_t result; H5TS_thread_ret_t ret_value = 0; @@ -69,11 +67,11 @@ pong(void *_test_info) result = H5TS_semaphore_wait(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_wait"); - count = ++test_info->counter; + H5TS_atomic_fetch_add_uint(&test_info->counter, (unsigned)1); result = H5TS_semaphore_signal(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (count < NUM_PINGPONG); + } while (H5TS_atomic_load_uint(&test_info->counter) < NUM_PINGPONG); return ret_value; } @@ -95,7 +93,7 @@ tts_semaphore_pingpong(void) CHECK_I(result, "H5TS_semaphore_init"); result = H5TS_semaphore_init(&test_info.pong_sem, 0); CHECK_I(result, "H5TS_semaphore_init"); - test_info.counter = 0; + H5TS_atomic_init_uint(&test_info.counter, (unsigned)0); /* Start ping & pong threads */ result = H5TS_thread_create(&ping_thread, ping, &test_info); @@ -113,13 +111,15 @@ tts_semaphore_pingpong(void) result = H5TS_thread_join(pong_thread, NULL); CHECK_I(result, "H5TS_thread_join"); - VERIFY(test_info.counter, (NUM_PINGPONG + 1), "ping pong"); + VERIFY(H5TS_atomic_load_uint(&test_info.counter), (NUM_PINGPONG + 1), "ping pong"); - /* Destroy semaphores */ + /* Destroy semaphores, etc. */ result = H5TS_semaphore_destroy(&test_info.ping_sem); CHECK_I(result, "H5TS_semaphore_destroy"); result = H5TS_semaphore_destroy(&test_info.pong_sem); CHECK_I(result, "H5TS_semaphore_destroy"); + + H5TS_atomic_destroy_uint(&test_info.counter); } /* end tts_semaphore_pingpong() */ static H5TS_THREAD_RETURN_TYPE From d0fe57624fab00b7dd50f3163587d4707f5dc7a8 Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:04:18 -0400 Subject: [PATCH 31/94] Replace non-VOL calls with VOL calls - part 3 (#4756) This PR switches H5I_object_verify() to H5VL_vol_object_verify() in the H5G API and removes unnecessary casts. --- src/H5G.c | 8 ++++---- src/H5L.c | 4 ++-- src/H5Ldeprec.c | 12 ++++++------ test/th5o.c | 9 +++++++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/H5G.c b/src/H5G.c index ede81551b9c..88d617afc3d 100644 --- a/src/H5G.c +++ b/src/H5G.c @@ -340,7 +340,7 @@ H5Gcreate_anon(hid_t loc_id, hid_t gcpl_id, hid_t gapl_id) loc_params.obj_type = H5I_get_type(loc_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Create the group */ @@ -507,7 +507,7 @@ H5Gget_create_plist(hid_t group_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(group_id, H5I_GROUP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(group_id, H5I_GROUP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a group ID"); /* Set up VOL callback arguments */ @@ -960,7 +960,7 @@ H5Gflush(hid_t group_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(group_id, H5I_GROUP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(group_id, H5I_GROUP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group ID"); /* Set up collective metadata if appropriate */ @@ -998,7 +998,7 @@ H5Grefresh(hid_t group_id) FUNC_ENTER_API(FAIL) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(group_id, H5I_GROUP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(group_id, H5I_GROUP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a group ID"); /* Set up collective metadata if appropriate */ diff --git a/src/H5L.c b/src/H5L.c index eb731f1832e..cbc584f6b44 100644 --- a/src/H5L.c +++ b/src/H5L.c @@ -468,11 +468,11 @@ H5L__create_hard_api_common(hid_t cur_loc_id, const char *cur_name, hid_t link_l if (H5L_SAME_LOC != cur_loc_id) /* Get the current location object */ - if (NULL == (curr_vol_obj = (H5VL_object_t *)H5VL_vol_object(cur_loc_id))) + if (NULL == (curr_vol_obj = H5VL_vol_object(cur_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); if (H5L_SAME_LOC != link_loc_id) /* Get the new location object */ - if (NULL == (link_vol_obj = (H5VL_object_t *)H5VL_vol_object(link_loc_id))) + if (NULL == (link_vol_obj = H5VL_vol_object(link_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL connectors are the same */ diff --git a/src/H5Ldeprec.c b/src/H5Ldeprec.c index c5f8470c912..819aea87f10 100644 --- a/src/H5Ldeprec.c +++ b/src/H5Ldeprec.c @@ -162,7 +162,7 @@ H5Literate1(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, hsize_t HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified"); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(group_id))) + if (NULL == (vol_obj = H5VL_vol_object(group_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Check if the VOL object is a native VOL connector object */ @@ -248,7 +248,7 @@ H5Literate_by_name1(hid_t loc_id, const char *group_name, H5_index_t idx_type, H HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access property list info"); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Check if the VOL object is a native VOL connector object */ @@ -325,7 +325,7 @@ H5Lget_info1(hid_t loc_id, const char *name, H5L_info1_t *linfo /*out*/, hid_t l loc_params.loc_data.loc_by_name.lapl_id = lapl_id; /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Check if the VOL object is a native VOL connector object */ @@ -416,7 +416,7 @@ H5Lget_info_by_idx1(hid_t loc_id, const char *group_name, H5_index_t idx_type, H loc_params.obj_type = H5I_get_type(loc_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Check if the VOL object is a native VOL connector object */ @@ -515,7 +515,7 @@ H5Lvisit1(hid_t group_id, H5_index_t idx_type, H5_iter_order_t order, H5L_iterat loc_params.obj_type = H5I_get_type(group_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(group_id))) + if (NULL == (vol_obj = H5VL_vol_object(group_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Check if the VOL object is a native VOL connector object */ @@ -604,7 +604,7 @@ H5Lvisit_by_name1(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5_ HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access property list info"); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Check if the VOL object is a native VOL connector object */ diff --git a/test/th5o.c b/test/th5o.c index 0ea8d927e83..815b5648e4d 100644 --- a/test/th5o.c +++ b/test/th5o.c @@ -752,6 +752,7 @@ test_h5o_plist(void) hid_t grp, dset, dtype, dspace; /* Object identifiers */ hid_t fapl; /* File access property list */ hid_t gcpl, dcpl, tcpl; /* Object creation properties */ + hid_t bad_pl = H5I_INVALID_HID; /* Invalid property list dues to invalid arg */ char filename[1024]; unsigned def_max_compact, def_min_dense; /* Default phase change parameters */ unsigned max_compact, min_dense; /* Actual phase change parameters */ @@ -854,6 +855,14 @@ test_h5o_plist(void) dcpl = H5Dget_create_plist(dset); CHECK(dcpl, FAIL, "H5Dget_create_plist"); + /* Test passing in a non-group identifier to the H5G API */ + H5E_BEGIN_TRY + { + bad_pl = H5Gget_create_plist(dtype); + } + H5E_END_TRY + VERIFY(bad_pl, H5I_INVALID_HID, "H5Gget_create_plist"); + /* Retrieve attribute phase change values on each creation property list and verify */ ret = H5Pget_attr_phase_change(gcpl, &max_compact, &min_dense); CHECK(ret, FAIL, "H5Pget_attr_phase_change"); From fe7dca0683ade23ecfbe647151d093b80e310c02 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:32:44 -0700 Subject: [PATCH 32/94] Turn on parallel CI tests in Autotools & CMake (#4573) --- .github/workflows/main-auto-par.yml | 26 ++++++++++++++++++++++++-- .github/workflows/main-cmake-par.yml | 13 +++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main-auto-par.yml b/.github/workflows/main-auto-par.yml index bd1b1c45902..3d5d7563a15 100644 --- a/.github/workflows/main-auto-par.yml +++ b/.github/workflows/main-auto-par.yml @@ -50,8 +50,9 @@ jobs: - name: Get Sources uses: actions/checkout@v4.1.7 - # AUTOTOOLS CONFIGURE - name: Autotools Configure + env: + NPROCS: 2 run: | sh ./autogen.sh mkdir "${{ runner.workspace }}/build" @@ -71,7 +72,28 @@ jobs: --with-szlib=yes shell: bash - # BUILD - name: Autotools Build run: make -j3 working-directory: ${{ runner.workspace }}/build + + # ph5diff tests are in the tools/tests directory so they will get run + # here, so leave NPROCS set here as well + - name: Autotools Run Tests + env: + NPROCS: 2 + run: | + cd test && make check -j2 && cd .. + cd tools && make check -j2 && cd .. + cd hl && make check -j2 && cd .. + cd fortran/test && make check -j2 && cd ../.. + working-directory: ${{ runner.workspace }}/build + if: ${{ inputs.thread_safety == 'disable' }} + + - name: Autotools Run Parallel Tests + env: + NPROCS: 2 + run: | + cd testpar && make check && cd .. + cd fortran/testpar && make check -j2 && cd ../.. + working-directory: ${{ runner.workspace }}/build + if: ${{ inputs.thread_safety == 'disable' }} diff --git a/.github/workflows/main-cmake-par.yml b/.github/workflows/main-cmake-par.yml index 9a87dead10d..55d79ecb776 100644 --- a/.github/workflows/main-cmake-par.yml +++ b/.github/workflows/main-cmake-par.yml @@ -62,3 +62,16 @@ jobs: - name: CMake Build run: cmake --build . --parallel 3 --config ${{ inputs.build_mode }} working-directory: ${{ runner.workspace }}/build + + # + # RUN TESTS + # + - name: CMake Run Tests + run: ctest . -E MPI_TEST --parallel 2 -C ${{ inputs.build_mode }} -V + working-directory: ${{ runner.workspace }}/build + if: ${{ matrix.run_tests && (inputs.thread_safety != 'TS') }} + + - name: CMake Run Parallel Tests + run: ctest . -R MPI_TEST -C ${{ inputs.build_mode }} -V + working-directory: ${{ runner.workspace }}/build + if: ${{ matrix.run_tests && (inputs.thread_safety != 'TS') }} From 6ccbf30199fc0bcd08655d3052959d51dfcd71c9 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Mon, 26 Aug 2024 12:25:27 -0500 Subject: [PATCH 33/94] Fix typo in H5Centry.c (#4762) --- src/H5Centry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Centry.c b/src/H5Centry.c index 6883e897186..1ca7479cf7e 100644 --- a/src/H5Centry.c +++ b/src/H5Centry.c @@ -3131,7 +3131,7 @@ H5C_protect(H5F_t *f, const H5C_class_t *type, haddr_t addr, void *udata, unsign else empty_space = cache_ptr->max_cache_size - cache_ptr->index_size; - /* try to free up if necceary and if evictions are permitted. Note + /* try to free up if necessary and if evictions are permitted. Note * that if evictions are enabled, we will call H5C__make_space_in_cache() * regardless if the min_free_space requirement is not met. */ From e5eede68429e22849691f545db78b83664be3703 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Mon, 26 Aug 2024 12:38:31 -0500 Subject: [PATCH 34/94] Set/Unset VOL wrapping context in H5VL_attr_close (#4759) --- src/H5VLcallback.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index 1662776ef9c..58e839c9985 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -1744,18 +1744,28 @@ H5VL__attr_close(void *obj, const H5VL_class_t *cls, hid_t dxpl_id, void **req) herr_t H5VL_attr_close(const H5VL_object_t *vol_obj, hid_t dxpl_id, void **req) { - herr_t ret_value = SUCCEED; /* Return value */ + bool vol_wrapper_set = false; /* Whether the VOL object wrapping context was set up */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ assert(vol_obj); + /* Set wrapper info in API context */ + if (H5VL_set_vol_wrapper(vol_obj) < 0) + HGOTO_ERROR(H5E_VOL, H5E_CANTSET, FAIL, "can't set VOL wrapper info"); + vol_wrapper_set = true; + /* Call the corresponding internal VOL routine */ if (H5VL__attr_close(vol_obj->data, vol_obj->connector->cls, dxpl_id, req) < 0) HGOTO_ERROR(H5E_VOL, H5E_CANTCLOSEOBJ, FAIL, "attribute close failed"); done: + /* Reset object wrapping info in API context */ + if (vol_wrapper_set && H5VL_reset_vol_wrapper() < 0) + HDONE_ERROR(H5E_VOL, H5E_CANTRESET, FAIL, "can't reset VOL wrapper info"); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5VL_attr_close() */ From 10597ee37cc1e46e20eddbb66a1456d1033208ab Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:47:54 -0700 Subject: [PATCH 35/94] Add missing C++ and Fortran to Intel oneAPI CI (#4761) * Add Fortran and C++ to Autotools * Add Fortran and C++ to Linux CMake * Add C++ to Windows CMake * Fix bad GitHub workspace variable --- .github/workflows/intel-auto.yml | 3 ++- .github/workflows/intel-cmake.yml | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/intel-auto.yml b/.github/workflows/intel-auto.yml index ea983c3a76b..6e0380efb4e 100644 --- a/.github/workflows/intel-auto.yml +++ b/.github/workflows/intel-auto.yml @@ -46,7 +46,8 @@ jobs: $GITHUB_WORKSPACE/configure \ --enable-build-mode=${{ inputs.build_mode }} \ --enable-shared \ - --disable-fortran + --enable-cxx \ + --enable-fortran - name: Autotools Build shell: bash diff --git a/.github/workflows/intel-cmake.yml b/.github/workflows/intel-cmake.yml index a8d5b7d49b8..fb703d480b3 100644 --- a/.github/workflows/intel-cmake.yml +++ b/.github/workflows/intel-cmake.yml @@ -43,13 +43,13 @@ jobs: run: | mkdir "${{ runner.workspace }}/build" cd "${{ runner.workspace }}/build" - cmake -C $GITHUB_WORKSPACE/config/cmake/cacheinit.cmake \ - -G Ninja \ - --log-level=VERBOSE \ + cmake -C $GITHUB_WORKSPACE/config/cmake/cacheinit.cmake -G Ninja --log-level=VERBOSE \ -DCMAKE_BUILD_TYPE=${{ inputs.build_mode }} \ + -DHDF5_BUILD_FORTRAN:BOOL=ON \ + -DHDF5_BUILD_CPP_LIB:BOOL=ON \ -DLIBAEC_USE_LOCALCONTENT=OFF \ -DZLIB_USE_LOCALCONTENT=OFF \ - $GITHUB_WORKSPACE + ${{ github.workspace }} - name: CMake Build (Linux) shell: bash @@ -97,7 +97,7 @@ jobs: run: | mkdir "${{ runner.workspace }}/build" Set-Location -Path "${{ runner.workspace }}\\build" - cmake -C ${{ github.workspace }}/config/cmake/cacheinit.cmake -G Ninja -DCMAKE_BUILD_TYPE=${{ inputs.build_mode }} -DHDF5_BUILD_FORTRAN=ON -DLIBAEC_USE_LOCALCONTENT=OFF -DZLIB_USE_LOCALCONTENT=OFF ${{ github.workspace }} + cmake -C ${{ github.workspace }}/config/cmake/cacheinit.cmake -G Ninja -DCMAKE_BUILD_TYPE=${{ inputs.build_mode }} -DHDF5_BUILD_FORTRAN=ON -DHDF5_BUILD_CPP_LIB=ON -DLIBAEC_USE_LOCALCONTENT=OFF -DZLIB_USE_LOCALCONTENT=OFF ${{ github.workspace }} - name: CMake Build (Windows) shell: pwsh From ff14dee3e910de7c99cb27e3d39ad89509422dc9 Mon Sep 17 00:00:00 2001 From: mattjala <124107509+mattjala@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:29:13 -0500 Subject: [PATCH 36/94] Remove early test exit (#4757) * Don't skip file tests * Remove test with invalid flag for H5Fopen * Verify that create/open of unseekable file fails * Remove failure verification --- test/tfile.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/test/tfile.c b/test/tfile.c index 1c8e6a04b1f..02f996f66a3 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -8104,45 +8104,38 @@ test_min_dset_ohdr(void) /**************************************************************** ** ** test_unseekable_file(): -** Test that attempting to open an unseekable file fails gracefully +** Test that attempting to create/open an unseekable file fails gracefully ** without a segfault (see hdf5#1498) ****************************************************************/ static void test_unseekable_file(void) { - hid_t file_id = H5I_INVALID_HID; /* File ID */ - /* Output message about test being performed */ MESSAGE(5, ("Testing creating/opening an unseekable file\n")); - /* Creation */ -#ifdef H5_HAVE_WIN32_API - file_id = H5Fcreate("NUL", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); -#else - file_id = H5Fcreate("/dev/null", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); -#endif - - H5Fclose(file_id); + /* Flush message in case this test segfaults */ + fflush(stdout); - /* Open, truncate */ + /* Creation */ #ifdef H5_HAVE_WIN32_API - file_id = H5Fopen("NUL", H5F_ACC_TRUNC, H5P_DEFAULT); + H5Fcreate("NUL", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); #else - file_id = H5Fopen("/dev/null", H5F_ACC_TRUNC, H5P_DEFAULT); + H5Fcreate("/dev/null", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); #endif - H5Fclose(file_id); + /* Should fail without segfault */ + /* TODO - Does not properly fail on all systems */ + /* VERIFY(file_id, H5I_INVALID_HID, "H5Fcreate"); */ - /* Open, RDWR */ + /* Opening */ #ifdef H5_HAVE_WIN32_API - file_id = H5Fopen("NUL", H5F_ACC_RDWR, H5P_DEFAULT); + H5Fopen("NUL", H5F_ACC_RDWR, H5P_DEFAULT); #else - file_id = H5Fopen("/dev/null", H5F_ACC_RDWR, H5P_DEFAULT); + H5Fopen("/dev/null", H5F_ACC_RDWR, H5P_DEFAULT); #endif - H5Fclose(file_id); - - exit(EXIT_SUCCESS); + /* TODO - Does not properly fail on all systems */ + /* VERIFY(file_id, H5I_INVALID_HID, "H5Fopen"); */ } /**************************************************************** ** From 00b0d3a670b4ac4d9a5c5af1a0d0523b924a4219 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:23:11 -0700 Subject: [PATCH 37/94] Restore Julia CI (#4763) Fixes #4539 --- .github/workflows/autotools.yml | 6 +++ .github/workflows/cmake.yml | 6 ++- .github/workflows/julia-auto.yml | 79 +++++++++++++++++++++++++++++ .github/workflows/julia-cmake.yml | 82 +++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/julia-auto.yml create mode 100644 .github/workflows/julia-cmake.yml diff --git a/.github/workflows/autotools.yml b/.github/workflows/autotools.yml index a430dc6b51c..a202076005a 100644 --- a/.github/workflows/autotools.yml +++ b/.github/workflows/autotools.yml @@ -100,6 +100,12 @@ jobs: name: "Autotools TestExpress Workflows" uses: ./.github/workflows/testxpr-auto.yml + call-release-auto-julia: + name: "Autotools Julia Workflows" + uses: ./.github/workflows/julia-auto.yml + with: + build_mode: "production" + # workflow-msys2-autotools: # name: "CMake msys2 Workflows" # uses: ./.github/workflows/msys2-auto.yml diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 21d201922de..7fe99c2f3cb 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -103,4 +103,8 @@ jobs: name: "CMake TestExpress Workflows" uses: ./.github/workflows/testxpr-cmake.yml - + call-release-cmake-julia: + name: "CMake Julia Workflows" + uses: ./.github/workflows/julia-cmake.yml + with: + build_mode: "Release" diff --git a/.github/workflows/julia-auto.yml b/.github/workflows/julia-auto.yml new file mode 100644 index 00000000000..a7dd2ab15b9 --- /dev/null +++ b/.github/workflows/julia-auto.yml @@ -0,0 +1,79 @@ +name: hdf5 dev autotools julia + +on: + workflow_call: + inputs: + build_mode: + description: "release vs. debug build" + required: true + type: string + +permissions: + contents: read + +jobs: + julia_build_and_test: + name: "julia ${{ inputs.build_mode }}" + runs-on: ubuntu-latest + steps: + - name: Get Sources + uses: actions/checkout@v4.1.1 + + - name: Install Dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install autoconf automake libtool libtool-bin libaec-dev + sudo apt-get install doxygen graphviz + sudo apt install -y zlib1g-dev libcurl4-openssl-dev libjpeg-dev wget curl bzip2 + sudo apt install -y m4 flex bison cmake libzip-dev openssl build-essential + + - name: Autotools Configure + shell: bash + run: | + sh ./autogen.sh + mkdir "${{ runner.workspace }}/build" + cd "${{ runner.workspace }}/build" + $GITHUB_WORKSPACE/configure \ + --enable-build-mode=${{ inputs.build_mode }} \ + --disable-fortran \ + --enable-shared \ + --disable-parallel \ + --prefix=/tmp + + - name: Autotools Build + shell: bash + run: | + make -j3 + working-directory: ${{ runner.workspace }}/build + + - name: Install HDF5 + shell: bash + run: | + make install + working-directory: ${{ runner.workspace }}/build + + - name: Install julia + uses: julia-actions/setup-julia@latest + with: + version: '1.6' + arch: 'x64' + + - name: Get julia hdf5 source + uses: actions/checkout@v4.1.1 + with: + repository: JuliaIO/HDF5.jl + path: . + + - name: Generate LocalPreferences + run: | + echo '[HDF5]' >> LocalPreferences.toml + echo 'libhdf5 = "/tmp/lib/libhdf5.so"' >> LocalPreferences.toml + echo 'libhdf5_hl = "/tmp/lib/libhdf5_hl.so"' >> LocalPreferences.toml + + - uses: julia-actions/julia-buildpkg@latest + + - name: Julia Run Tests + uses: julia-actions/julia-runtest@latest + env: + JULIA_DEBUG: Main diff --git a/.github/workflows/julia-cmake.yml b/.github/workflows/julia-cmake.yml new file mode 100644 index 00000000000..c1306d6a381 --- /dev/null +++ b/.github/workflows/julia-cmake.yml @@ -0,0 +1,82 @@ +name: hdf5 dev CMake julia + +on: + workflow_call: + inputs: + build_mode: + description: "release vs. debug build" + required: true + type: string + +permissions: + contents: read + +jobs: + julia_build_and_test: + name: "julia ${{ inputs.build_mode }}" + runs-on: ubuntu-latest + steps: + - name: Get Sources + uses: actions/checkout@v4.1.1 + + - name: Install Dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install ninja-build doxygen graphviz + sudo apt install libssl3 libssl-dev libcurl4 libcurl4-openssl-dev + sudo apt install -y libaec-dev zlib1g-dev wget curl bzip2 flex bison cmake libzip-dev openssl build-essential + + - name: CMake Configure + shell: bash + run: | + mkdir "${{ runner.workspace }}/build" + cd "${{ runner.workspace }}/build" + cmake -C $GITHUB_WORKSPACE/config/cmake/cacheinit.cmake -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ inputs.build_mode }} \ + -DHDF5_ENABLE_SZIP_SUPPORT:BOOL=OFF \ + -DHDF5_ENABLE_PARALLEL:BOOL=OFF \ + -DHDF5_BUILD_CPP_LIB:BOOL=OFF \ + -DLIBAEC_USE_LOCALCONTENT=OFF \ + -DZLIB_USE_LOCALCONTENT=OFF \ + -DHDF5_BUILD_FORTRAN:BOOL=OFF \ + -DHDF5_BUILD_JAVA:BOOL=OFF \ + -DCMAKE_INSTALL_PREFIX=/tmp \ + $GITHUB_WORKSPACE + + - name: CMake Build + shell: bash + run: | + cmake --build . --parallel 3 --config ${{ inputs.build_mode }} + working-directory: ${{ runner.workspace }}/build + + - name: Install HDF5 + shell: bash + run: | + cmake --install . + working-directory: ${{ runner.workspace }}/build + + - name: Install julia + uses: julia-actions/setup-julia@latest + with: + version: '1.6' + arch: 'x64' + + - name: Get julia hdf5 source + uses: actions/checkout@v4.1.1 + with: + repository: JuliaIO/HDF5.jl + path: . + + - name: Generate LocalPreferences + run: | + echo '[HDF5]' >> LocalPreferences.toml + echo 'libhdf5 = "/tmp/lib/libhdf5.so"' >> LocalPreferences.toml + echo 'libhdf5_hl = "/tmp/lib/libhdf5_hl.so"' >> LocalPreferences.toml + + - uses: julia-actions/julia-buildpkg@latest + + - name: Julia Run Tests + uses: julia-actions/julia-runtest@latest + env: + JULIA_DEBUG: Main From 04bf2dff85c7cec78d18b1619f4918af8ed3496b Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Mon, 26 Aug 2024 16:37:47 -0500 Subject: [PATCH 38/94] Capitalize f in (#4766) --- src/H5public.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5public.h b/src/H5public.h index e2a82b9bb14..9dd18cd5ff7 100644 --- a/src/H5public.h +++ b/src/H5public.h @@ -443,7 +443,7 @@ extern "C" { * \details H5open() initializes the HDF5 library. * * \details When the HDF5 library is used in a C application, the library is - * automatically initialized when the first HDf5 function call is + * automatically initialized when the first HDF5 function call is * issued. If one finds that an HDF5 library function is failing * inexplicably, H5open() can be called first. It is safe to call * H5open() before an application issues any other function calls to From 67e49890049edbdbd803b56e787e43b7e9258899 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Tue, 27 Aug 2024 00:18:01 -0700 Subject: [PATCH 39/94] Add testing to NVHPC CI actions (CMake & Autotools) (#4760) Turns on testing, both serial and parallel, but skips: * dt_arith and dtransform in CMake * All main library tests in the Autotools Due to dt_arith and dtransform segfaults when handling long doubles. --- .github/workflows/nvhpc-auto.yml | 20 ++++++++++++++++++++ .github/workflows/nvhpc-cmake.yml | 13 +++++++++++++ 2 files changed, 33 insertions(+) diff --git a/.github/workflows/nvhpc-auto.yml b/.github/workflows/nvhpc-auto.yml index bb986d3c800..bca490485d7 100644 --- a/.github/workflows/nvhpc-auto.yml +++ b/.github/workflows/nvhpc-auto.yml @@ -67,6 +67,26 @@ jobs: make -j3 working-directory: ${{ runner.workspace }}/build + # ph5diff tests are in the tools/tests directory so they will get run + # here, so leave NPROCS set here as well + - name: Autotools Run Tests + env: + NPROCS: 2 + run: | + export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin:$PATH + cd tools && make check -j2 && cd .. + cd hl && make check -j2 && cd .. + cd fortran && make check -j2 && cd .. + working-directory: ${{ runner.workspace }}/build + + - name: Autotools Run Parallel Tests + env: + NPROCS: 2 + run: | + export PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/comm_libs/openmpi4/bin:/opt/nvidia/hpc_sdk/Linux_x86_64/24.7/compilers/bin:$PATH + cd testpar && make check && cd .. + working-directory: ${{ runner.workspace }}/build + - name: Autotools Install shell: bash run: | diff --git a/.github/workflows/nvhpc-cmake.yml b/.github/workflows/nvhpc-cmake.yml index a0641fa3089..3dbefa22861 100644 --- a/.github/workflows/nvhpc-cmake.yml +++ b/.github/workflows/nvhpc-cmake.yml @@ -68,3 +68,16 @@ jobs: run: | cmake --build . --parallel 3 --config ${{ inputs.build_mode }} working-directory: ${{ runner.workspace }}/build + + # Skipping dt_arith and dtransform while we investigate long double failures + - name: CMake Run Tests + shell: bash + run: | + ctest . -E "MPI_TEST|H5TEST-dt_arith|H5TEST-dtransform" --parallel 2 -C ${{ inputs.build_mode }} -V + working-directory: ${{ runner.workspace }}/build + + - name: CMake Run Parallel Tests + shell: bash + run: | + ctest . -R MPI_TEST -C ${{ inputs.build_mode }} -V + working-directory: ${{ runner.workspace }}/build From e065e72c9b564134c7cf09cfc4e763a482944033 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Tue, 27 Aug 2024 03:41:00 -0700 Subject: [PATCH 40/94] Move 1.14.6 and 1.16.0 to correct date (#4772) --- doc/img/release-schedule.plantuml | 8 ++++---- doc/img/release-schedule.png | Bin 14159 -> 22892 bytes 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/img/release-schedule.plantuml b/doc/img/release-schedule.plantuml index 741160e31d3..d0fd79b1426 100644 --- a/doc/img/release-schedule.plantuml +++ b/doc/img/release-schedule.plantuml @@ -23,14 +23,14 @@ Project starts 2023-01-01 [1.12.3] happens 2023-11-30 [1.12] is colored in #88CCEE -[1.14] starts at 2023-01-01 and lasts 122 weeks +[1.14] starts at 2023-01-01 and lasts 118 weeks [1.14.1] happens at 2023-04-30 [1.14.2] happens at 2023-08-31 [1.14.3] happens at 2023-10-31 [1.14.4.2] happens at 2024-04-15 [1.14.4.3] happens at 2024-05-22 [1.14.5] happens at 2024-09-30 -[1.14.6] happens at 2025-04-30 +[1.14.6] happens at 2025-03-31 [1.14.1] displays on same row as [1.14.1] [1.14.2] displays on same row as [1.14.1] [1.14.3] displays on same row as [1.14.1] @@ -39,8 +39,8 @@ Project starts 2023-01-01 [1.14.6] displays on same row as [1.14.1] [1.14] is colored in #B187CF -[1.16] starts at 2025-04-30 and lasts 35 weeks -[1.16.0] happens at 2025-04-30 +[1.16] starts at 2025-03-31 and lasts 35 weeks +[1.16.0] happens at 2025-03-31 [1.16.1] happens at 2025-09-30 [1.16.1] displays on same row as [1.16.0] [1.16] is colored in #02BFA0 diff --git a/doc/img/release-schedule.png b/doc/img/release-schedule.png index 82e1cf5d495fe882bebede3966b963a122f0d5c1..20a0a55986d6bec975ec83a87d6987e4a516d49e 100644 GIT binary patch literal 22892 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 DEqUR* literal 14159 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 Date: Tue, 27 Aug 2024 06:05:47 -0700 Subject: [PATCH 41/94] Fix typo in H5T_order_t enum (#4773) 'bit endian' --> 'big endian' --- src/H5Tpublic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Tpublic.h b/src/H5Tpublic.h index 97ee27c7f46..57a5b6047c3 100644 --- a/src/H5Tpublic.h +++ b/src/H5Tpublic.h @@ -52,7 +52,7 @@ typedef enum H5T_class_t { typedef enum H5T_order_t { H5T_ORDER_ERROR = -1, /**< error */ H5T_ORDER_LE = 0, /**< little endian */ - H5T_ORDER_BE = 1, /**< bit endian */ + H5T_ORDER_BE = 1, /**< big endian */ H5T_ORDER_VAX = 2, /**< VAX mixed endian */ H5T_ORDER_MIXED = 3, /**< Compound type with mixed member orders */ H5T_ORDER_NONE = 4 /**< no particular order (strings, bits,..) */ From 90b07416a631258253a7cdbfc077680d1ce78cd5 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Tue, 27 Aug 2024 11:06:40 -0500 Subject: [PATCH 42/94] Remove dummy comments that repeat function names. (#4775) --- test/vol.c | 69 ------------------------------------------------------ 1 file changed, 69 deletions(-) diff --git a/test/vol.c b/test/vol.c index 041e0c9b88b..9fa4f06c1ca 100644 --- a/test/vol.c +++ b/test/vol.c @@ -914,11 +914,9 @@ test_basic_file_operation(const char *driver_name) TEST_ERROR; } - /* H5Fcreate */ if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) TEST_ERROR; - /* H5Fget_obj_count */ if ((obj_count = H5Fget_obj_count(fid, H5F_OBJ_FILE)) < 0) TEST_ERROR; if ((obj_count = H5Fget_obj_count(fid, H5F_OBJ_ALL)) < 0) @@ -926,7 +924,6 @@ test_basic_file_operation(const char *driver_name) if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATASET)) < 0) TEST_ERROR; - /* H5Fget_obj_ids */ if ((obj_count = H5Fget_obj_ids(fid, H5F_OBJ_ALL, 2, obj_id_list)) < 0) TEST_ERROR; if ((obj_count = H5Fget_obj_ids((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATASET, 2, obj_id_list)) < 0) @@ -937,7 +934,6 @@ test_basic_file_operation(const char *driver_name) strcmp(driver_name, "family") != 0 && strcmp(driver_name, "direct") != 0 && strcmp(driver_name, "core") != 0 && strcmp(driver_name, "core_paged") != 0 && strcmp(driver_name, "mpio") != 0 && strcmp(driver_name, "splitter") != 0)) { - /* H5Fget_access_plist */ if ((fapl_id2 = H5Fget_access_plist(fid)) < 0) TEST_ERROR; if (H5Pequal(fapl_id, fapl_id2) != true) @@ -946,53 +942,42 @@ test_basic_file_operation(const char *driver_name) TEST_ERROR; } /* end if */ - /* H5Fget_create_plist */ if ((fcpl_id = H5Fget_create_plist(fid)) < 0) TEST_ERROR; if (H5Pclose(fcpl_id) < 0) TEST_ERROR; - /* H5Fget_filesize */ if (H5Fget_filesize(fid, &file_size) < 0) TEST_ERROR; /* Can't retrieve VFD handle for split / multi / family VFDs */ if ((bool)(strcmp(driver_name, "split") != 0 && strcmp(driver_name, "multi") != 0 && strcmp(driver_name, "family") != 0)) { - /* H5Fget_vfd_handle */ if (H5Fget_vfd_handle(fid, H5P_DEFAULT, &os_file_handle) < 0) TEST_ERROR; } /* end if */ - /* H5Fget_intent */ if (H5Fget_intent(fid, &intent) < 0) TEST_ERROR; - /* H5Fget_info2 */ if (H5Fget_info2(fid, &finfo) < 0) TEST_ERROR; - /* H5Fget_name */ if (H5Fget_name(fid, name, 32) < 0) TEST_ERROR; - /* H5Fclear_elink_file_cache */ if (H5Fclear_elink_file_cache(fid) < 0) TEST_ERROR; - /* H5Fflush */ if (H5Fflush(fid, H5F_SCOPE_GLOBAL) < 0) TEST_ERROR; - /* H5Fclose */ if (H5Fclose(fid) < 0) TEST_ERROR; - /* H5Fis_accessible */ if (H5Fis_accessible(filename, fapl_id) < 0) TEST_ERROR; - /* H5Fopen */ if ((fid = H5Fopen(filename, H5F_ACC_RDWR, fapl_id)) < 0) TEST_ERROR; @@ -1001,7 +986,6 @@ test_basic_file_operation(const char *driver_name) strcmp(driver_name, "family") != 0 && strcmp(driver_name, "direct") != 0 && strcmp(driver_name, "core") != 0 && strcmp(driver_name, "core_paged") != 0 && strcmp(driver_name, "mpio") != 0 && strcmp(driver_name, "splitter") != 0)) { - /* H5Fget_access_plist */ if ((fapl_id2 = H5Fget_access_plist(fid)) < 0) TEST_ERROR; if (H5Pequal(fapl_id, fapl_id2) != true) @@ -1018,7 +1002,6 @@ test_basic_file_operation(const char *driver_name) strcmp(driver_name, "family") != 0 && strcmp(driver_name, "direct") != 0 && strcmp(driver_name, "core") != 0 && strcmp(driver_name, "core_paged") != 0 && strcmp(driver_name, "mpio") != 0 && strcmp(driver_name, "splitter") != 0)) { - /* H5Fget_access_plist */ if ((fapl_id2 = H5Fget_access_plist(fid_reopen)) < 0) TEST_ERROR; if (H5Pequal(fapl_id, fapl_id2) != true) @@ -1034,7 +1017,6 @@ test_basic_file_operation(const char *driver_name) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; @@ -1086,27 +1068,22 @@ test_basic_group_operation(void) if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) TEST_ERROR; - /* H5Gcreate */ if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Gget_create_plist */ if ((gcpl_id = H5Gget_create_plist(gid)) < 0) TEST_ERROR; if (H5Pclose(gcpl_id) < 0) TEST_ERROR; - /* H5Gget_info */ if (H5Gget_info(gid, &info) < 0) TEST_ERROR; if (H5Gget_info(fid, &info) < 0) TEST_ERROR; - /* H5Gget_info_by_name */ if (H5Gget_info_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, &info, H5P_DEFAULT) < 0) TEST_ERROR; - /* H5Gget_info_by_idx */ if (H5Gget_info_by_idx(fid, "/", H5_INDEX_NAME, H5_ITER_NATIVE, 0, &info, H5P_DEFAULT) < 0) TEST_ERROR; @@ -1117,19 +1094,15 @@ test_basic_group_operation(void) if (H5Gflush(gid) < 0) TEST_ERROR; - /* H5Gclose */ if (H5Gclose(gid) < 0) TEST_ERROR; - /* H5Gopen */ if ((gid = H5Gopen2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Gcreate_anon */ if ((gid_a = H5Gcreate_anon(fid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Grefresh */ if (H5Grefresh(gid) < 0) TEST_ERROR; @@ -1142,7 +1115,6 @@ test_basic_group_operation(void) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; @@ -1213,7 +1185,6 @@ test_basic_dataset_operation(void) out_buf[i] = 0; } - /* H5Dcreate */ curr_dims = 0; if ((sid = H5Screate_simple(1, &curr_dims, &max_dims)) < 0) TEST_ERROR; @@ -1226,7 +1197,6 @@ test_basic_dataset_operation(void) H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Dcreate_anon */ if ((did_a = H5Dcreate_anon(fid, H5T_NATIVE_INT, sid, dcpl_id, H5P_DEFAULT)) < 0) TEST_ERROR; @@ -1235,7 +1205,6 @@ test_basic_dataset_operation(void) if (H5Pclose(dcpl_id) < 0) TEST_ERROR; - /* H5Dset_extent */ curr_dims = N_ELEMENTS; if (H5Dset_extent(did, &curr_dims) < 0) TEST_ERROR; @@ -1247,35 +1216,28 @@ test_basic_dataset_operation(void) if (H5Dflush(did) < 0) TEST_ERROR; - /* H5Dwrite */ if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, in_buf) < 0) TEST_ERROR; - /* H5Drefresh */ if (H5Drefresh(did) < 0) TEST_ERROR; - /* H5Dclose */ if (H5Dclose(did) < 0) TEST_ERROR; if (H5Dclose(did_a) < 0) TEST_ERROR; - /* H5Dopen */ if ((did = H5Dopen2(fid, NATIVE_VOL_TEST_DATASET_NAME, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Dget_space */ if ((sid = H5Dget_space(did)) < 0) TEST_ERROR; if (H5Sclose(sid) < 0) TEST_ERROR; - /* H5Dget_space_status */ if (H5Dget_space_status(did, &status) < 0) TEST_ERROR; - /* H5Dget_type */ if ((tid = H5Dget_type(did)) < 0) TEST_ERROR; if (H5Tclose(tid) < 0) @@ -1287,13 +1249,11 @@ test_basic_dataset_operation(void) if (H5Tclose(tid) < 0) TEST_ERROR; - /* H5Dget_create_plist */ if ((dcpl_id = H5Dget_create_plist(did)) < 0) TEST_ERROR; if (H5Pclose(dcpl_id) < 0) TEST_ERROR; - /* H5Dget_access_plist */ if ((dapl_id = H5Dget_access_plist(did)) < 0) TEST_ERROR; if (H5Pclose(dapl_id) < 0) @@ -1311,7 +1271,6 @@ test_basic_dataset_operation(void) if (HADDR_UNDEF != (offset = H5Dget_offset(did))) TEST_ERROR; - /* H5Dread */ if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, out_buf) < 0) TEST_ERROR; @@ -1326,7 +1285,6 @@ test_basic_dataset_operation(void) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; @@ -1391,44 +1349,35 @@ test_basic_attribute_operation(void) if ((sid = H5Screate_simple(1, &dims, &dims)) < 0) TEST_ERROR; - /* H5Acreate */ if ((aid = H5Acreate2(fid, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Awrite */ if (H5Awrite(aid, H5T_NATIVE_INT, &data_in) < 0) TEST_ERROR; - /* H5Aread */ if (H5Aread(aid, H5T_NATIVE_INT, &data_out) < 0) TEST_ERROR; if (data_in != data_out) TEST_ERROR; - /* H5Aclose */ if (H5Aclose(aid) < 0) TEST_ERROR; - /* H5Aopen */ if ((aid = H5Aopen(fid, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Aclose(aid) < 0) TEST_ERROR; - /* H5Adelete */ if (H5Adelete(fid, NATIVE_VOL_TEST_ATTRIBUTE_NAME) < 0) TEST_ERROR; - /* H5Acreate_by_name */ if ((aid_name = H5Acreate_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Aclose */ if (H5Aclose(aid_name) < 0) TEST_ERROR; - /* H5Adelete_by_name */ if (H5Adelete_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5P_DEFAULT) < 0) TEST_ERROR; @@ -1441,7 +1390,6 @@ test_basic_attribute_operation(void) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; @@ -1495,23 +1443,19 @@ test_basic_object_operation(void) if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Oget_info */ if (H5Oget_info3(fid, &object_info, H5O_INFO_ALL) < 0) TEST_ERROR; //! [H5Oget_info_by_name3_snip] - /* H5Oget_info_by_name */ if (H5Oget_info_by_name3(fid, NATIVE_VOL_TEST_GROUP_NAME, &object_info, H5O_INFO_ALL, H5P_DEFAULT) < 0) TEST_ERROR; //! [H5Oget_info_by_name3_snip] - /* H5Oexists_by_name */ if (H5Oexists_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT) != true) TEST_ERROR; - /* H5Oopen/close */ if ((oid = H5Oopen(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) TEST_ERROR; if (H5Oclose(oid) < 0) @@ -1524,7 +1468,6 @@ test_basic_object_operation(void) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; @@ -1572,7 +1515,6 @@ test_basic_link_operation(void) if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Lcreate_hard */ if (H5Lcreate_hard(fid, "/", gid, NATIVE_VOL_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR; @@ -1580,18 +1522,15 @@ test_basic_link_operation(void) if (H5Lcreate_soft("/", fid, NATIVE_VOL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR; - /* H5Lexists */ if (H5Lexists(gid, NATIVE_VOL_TEST_HARD_LINK_NAME, H5P_DEFAULT) < 0) TEST_ERROR; if (H5Lexists(fid, NATIVE_VOL_TEST_SOFT_LINK_NAME, H5P_DEFAULT) < 0) TEST_ERROR; - /* H5Lcopy */ if (H5Lcopy(gid, NATIVE_VOL_TEST_HARD_LINK_NAME, fid, NATIVE_VOL_TEST_COPY_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR; - /* H5Lmove */ if (H5Lmove(fid, NATIVE_VOL_TEST_COPY_LINK_NAME, gid, NATIVE_VOL_TEST_MOVE_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR; @@ -1603,7 +1542,6 @@ test_basic_link_operation(void) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; @@ -1654,7 +1592,6 @@ test_basic_datatype_operation(void) if ((tid = H5Tcopy(H5T_NATIVE_INT)) < 0) TEST_ERROR; - /* H5Tcommit */ if (H5Tcommit2(fid, NATIVE_VOL_TEST_DATATYPE_NAME, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) TEST_ERROR; @@ -1665,23 +1602,18 @@ test_basic_datatype_operation(void) if (H5Tflush(tid) < 0) TEST_ERROR; - /* H5Trefresh */ if (H5Trefresh(tid) < 0) TEST_ERROR; - /* H5Tclose */ if (H5Tclose(tid) < 0) TEST_ERROR; - /* H5Topen */ if ((tid = H5Topen2(fid, NATIVE_VOL_TEST_DATATYPE_NAME, H5P_DEFAULT)) < 0) TEST_ERROR; - /* H5Tget_create_plist */ if ((tcpl_id = H5Tget_create_plist(tid)) < 0) TEST_ERROR; - /* H5Tcommit_anon */ if ((tid_anon = H5Tcopy(H5T_NATIVE_INT)) < 0) TEST_ERROR; if (H5Tcommit_anon(fid, tid_anon, H5P_DEFAULT, H5P_DEFAULT) < 0) @@ -1698,7 +1630,6 @@ test_basic_datatype_operation(void) h5_delete_test_file(FILENAME[0], fapl_id); - /* H5Pclose */ if (H5Pclose(fapl_id) < 0) TEST_ERROR; From b56873895ac34cb7dfff4e3eb3b4889439a90f92 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Tue, 27 Aug 2024 12:22:14 -0500 Subject: [PATCH 43/94] Fix grammar in H5Odtype.c comment block (#4777) --- src/H5Odtype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Odtype.c b/src/H5Odtype.c index 24671b02107..b2e6c8f65be 100644 --- a/src/H5Odtype.c +++ b/src/H5Odtype.c @@ -135,7 +135,7 @@ H5O__dtype_decode_helper(unsigned *ioflags /*in,out*/, const uint8_t **pp, H5T_t * that case is impossible. * * Instead of using our normal H5_IS_BUFFER_OVERFLOW macro, use - * H5_IS_KNOWN_BUFFER_OVERFLOW, which will skip the check when the + * H5_IS_KNOWN_BUFFER_OVERFLOW, which will skip the check when * we're decoding a buffer from H5Tconvert(). * * Even if this is fixed at some point in the future, as long as we From d4b0a157e6dfc97fb69f90bc7a7b458dc11e90d0 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:41:39 -0700 Subject: [PATCH 44/94] Add subfiling checks to the gcc action (#4776) --- .github/workflows/main-auto-par.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main-auto-par.yml b/.github/workflows/main-auto-par.yml index 3d5d7563a15..ad893d04724 100644 --- a/.github/workflows/main-auto-par.yml +++ b/.github/workflows/main-auto-par.yml @@ -63,6 +63,7 @@ jobs: --with-default-api-version=v114 \ --enable-shared \ --enable-parallel \ + --enable-subfiling-vfd \ --disable-cxx \ --enable-fortran \ --disable-java \ From 1f0bd7f8efeb6028349b2a6402c15172936daaaa Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:42:11 -0400 Subject: [PATCH 45/94] Replace non-VOL calls with VOL calls - part 3 (#4771) This PR switches H5I_object() to H5VL_vol_object() in H5O and H5T APIs. H5M is the last one and left out of this PR because it needs more work in documentation and there is no test for the API functions. Fixes GH-4730 --- src/H5Gdeprec.c | 5 +++-- src/H5O.c | 4 ++-- src/H5Odeprec.c | 2 +- src/H5Tcommit.c | 2 +- src/H5Tdeprec.c | 4 ++-- src/H5VLnative.c | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index e86bc82c738..72b328c730e 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -719,8 +719,9 @@ H5Gset_comment(hid_t loc_id, const char *name, const char *comment) * * Note: Deprecated in favor of H5Oget_comment/H5Oget_comment_by_name * - * Return: Success: Number of characters in the comment. The value - * returned may be larger than the BUFSIZE argument. + * Return: Success: Number of characters in the comment, excluding the + * NULL terminator character. The value returned may be + * larger than the BUFSIZE argument. * * Failure: Negative * diff --git a/src/H5O.c b/src/H5O.c index 26340aa567a..39887b51a29 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -359,7 +359,7 @@ H5Oopen_by_token(hid_t loc_id, H5O_token_t token) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "can't open H5O_TOKEN_UNDEF"); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Get object type */ @@ -436,7 +436,7 @@ H5O__copy_api_common(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, c HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set object access arguments"); /* get the object */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object(dst_loc_id))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object(dst_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); loc_params2.type = H5VL_OBJECT_BY_SELF; loc_params2.obj_type = H5I_get_type(dst_loc_id); diff --git a/src/H5Odeprec.c b/src/H5Odeprec.c index f74ec542d6f..37a3996c1e6 100644 --- a/src/H5Odeprec.c +++ b/src/H5Odeprec.c @@ -347,7 +347,7 @@ H5Oopen_by_addr(hid_t loc_id, haddr_t addr) FUNC_ENTER_API(H5I_INVALID_HID) /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Get object type */ diff --git a/src/H5Tcommit.c b/src/H5Tcommit.c index d64c4e82439..92853c63058 100644 --- a/src/H5Tcommit.c +++ b/src/H5Tcommit.c @@ -349,7 +349,7 @@ H5Tcommit_anon(hid_t loc_id, hid_t type_id, hid_t tcpl_id, hid_t tapl_id) loc_params.obj_type = H5I_get_type(loc_id); /* Get the file object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid file identifier"); /* Commit the datatype */ diff --git a/src/H5Tdeprec.c b/src/H5Tdeprec.c index cc998346cb4..3483597346e 100644 --- a/src/H5Tdeprec.c +++ b/src/H5Tdeprec.c @@ -116,7 +116,7 @@ H5Tcommit1(hid_t loc_id, const char *name, hid_t type_id) loc_params.obj_type = H5I_get_type(loc_id); /* get the object from the loc_id */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid object identifier"); /* Commit the datatype */ @@ -167,7 +167,7 @@ H5Topen1(hid_t loc_id, const char *name) loc_params.obj_type = H5I_get_type(loc_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Open the datatype */ diff --git a/src/H5VLnative.c b/src/H5VLnative.c index ceee7f16c43..6f6b2d0768d 100644 --- a/src/H5VLnative.c +++ b/src/H5VLnative.c @@ -393,7 +393,7 @@ H5VLnative_addr_to_token(hid_t loc_id, haddr_t addr, H5O_token_t *token) bool is_native_vol_obj; /* Get the location object */ - if (NULL == (vol_obj_container = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj_container = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL object is a native connector object */ @@ -486,7 +486,7 @@ H5VLnative_token_to_addr(hid_t loc_id, H5O_token_t token, haddr_t *addr) bool is_native_vol_obj; /* Get the location object */ - if (NULL == (vol_obj_container = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj_container = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL object is a native connector object */ From 6fbe13a66d020fb951a3de11b800e32be0d4510b Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:53:10 -0700 Subject: [PATCH 46/94] Add subfiling to CI more places where we test parallel (#4778) * CMake: gcc,, AOCC * Autotools: AOCC (gcc was added in a previous commit) NVHPC generates a lot of tools errors for some reason --- .github/workflows/aocc-auto.yml | 1 + .github/workflows/aocc-cmake.yml | 1 + .github/workflows/main-cmake-par.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/aocc-auto.yml b/.github/workflows/aocc-auto.yml index b556737e3b1..8b33173db53 100644 --- a/.github/workflows/aocc-auto.yml +++ b/.github/workflows/aocc-auto.yml @@ -74,6 +74,7 @@ jobs: --enable-build-mode=${{ inputs.build_mode }} \ --enable-shared \ --enable-parallel \ + --enable-subfiling-vfd \ LDFLAGS="-L/home/runner/work/hdf5/hdf5/aocc-compiler-4.2.0/lib \ -L/home/runner/work/hdf5/hdf5/openmpi-4.1.6-install/lib" diff --git a/.github/workflows/aocc-cmake.yml b/.github/workflows/aocc-cmake.yml index 92ac0d25fe8..d4cff890e63 100644 --- a/.github/workflows/aocc-cmake.yml +++ b/.github/workflows/aocc-cmake.yml @@ -71,6 +71,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{ inputs.build_mode }} \ -DHDF5_ENABLE_SZIP_SUPPORT:BOOL=OFF \ -DHDF5_ENABLE_PARALLEL:BOOL=ON \ + -DHDF5_ENABLE_SUBFILING_VFD:BOOL=ON \ -DHDF5_BUILD_CPP_LIB:BOOL=OFF \ -DLIBAEC_USE_LOCALCONTENT=OFF \ -DZLIB_USE_LOCALCONTENT=OFF \ diff --git a/.github/workflows/main-cmake-par.yml b/.github/workflows/main-cmake-par.yml index 55d79ecb776..c00caa713c9 100644 --- a/.github/workflows/main-cmake-par.yml +++ b/.github/workflows/main-cmake-par.yml @@ -47,6 +47,7 @@ jobs: -DBUILD_SHARED_LIBS=ON \ -DHDF5_ENABLE_ALL_WARNINGS=ON \ -DHDF5_ENABLE_PARALLEL:BOOL=ON \ + -DHDF5_ENABLE_SUBFILING_VFD:BOOL=ON \ -DHDF5_BUILD_CPP_LIB:BOOL=OFF \ -DHDF5_BUILD_FORTRAN=ON \ -DHDF5_BUILD_JAVA=OFF \ From d2be61826d7685ccd0f562ed716269544cca27ac Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 28 Aug 2024 12:06:33 -0500 Subject: [PATCH 47/94] Convert Collective Calls html file to doxygen (#4779) --- doxygen/dox/CollectiveCalls.dox | 1265 +++++++++++++++++++++++++++++++ doxygen/dox/IntroParHDF5.dox | 2 + 2 files changed, 1267 insertions(+) create mode 100644 doxygen/dox/CollectiveCalls.dox diff --git a/doxygen/dox/CollectiveCalls.dox b/doxygen/dox/CollectiveCalls.dox new file mode 100644 index 00000000000..9f26896262b --- /dev/null +++ b/doxygen/dox/CollectiveCalls.dox @@ -0,0 +1,1265 @@ +/** \page collective_calls Collective Calling Requirements in Parallel HDF5 Applications + * + * \section sec_collective_calls_intro Introduction + * This document addresses two topics of concern + in a parallel computing environment: +
    • HDF5 functions that must be called collectively and when +
    • Properties that must be used in a coordinated manner +
    + + The term @ref options in the "Additional notes" + column indicates that the first item in the "Function" + column of the same row is a macro that is selectively mapped to one + of the two immediately-following functions. + For example, #H5Acreate is a macro that can be mapped to + either #H5Acreate1 or #H5Acreate2. + This mapping is configurable and is explained in + \ref api-compat-macros. + The macro structure was introduced at HDF5 Release 1.8.0. + * + * \section sec_collective_calls_func Always collective + * The following functions must always be called collectively. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + API + + Function + + All processes: +
    + same datatype & dataspace +
    + All processes: +
    + same access properties +
    + All processes: +
    + same creation properties +
    + Available in releases since + + Additional notes +
    + H5A + + #H5Acreate +
    + #H5Acreate1 +
    + #H5Acreate2 +
    + X + + X + + X + + 1.8.x + + @ref options +
    + The function #H5Acreate was renamed to + #H5Acreate1 at Release 1.8.0. +
    + + #H5Acreate_by_name + + X + + X + + X + + 1.8.x + +
    + + #H5Adelete + + + + + +
    + + #H5Adelete_by_idx + + + + + 1.8.x + +
    + + #H5Adelete_by_name + + + + + 1.8.x + +
    + + #H5Arename + + + + + 1.6.x + +
    + + #H5Arename_by_name + + + + + 1.8.x + +
    + + #H5Awrite + + + + + + Because raw data for an attribute is cached locally, + all processes must participate in order to guarantee that + future #H5Aread calls return correct results + on all processes. +
    +
    + H5D + + #H5Dcreate +
    + #H5Dcreate1 +
    + #H5Dcreate2 +
    + X + + X + + X + + 1.8.x + + @ref options +
    + The function #H5Dcreate was renamed to + #H5Dcreate1 at Release 1.8.0. +
    + + #H5Dcreate_anon + + X + + X + + X + + 1.8.x + +
    + + #H5Dextend + + + + + + All processes must participate only if the number of chunks + in the dataset actually changes. +
    + All processes must use the same dataspace dimensions. +
    + + #H5Dset_extent + + + + + 1.6.x + + All processes must participate only if the number of chunks + in the dataset actually changes. +
    + All processes must use the same dataspace dimensions. +
    +
    + H5F + + #H5Fclose + + + + + + All processes must participate only if this is the + last reference to the file identifier. +
    + + #H5Fcreate + + + X + + X + + +
    + + #H5Fflush + + + + + +
    + + #H5Fmount + + + + + +
    + + #H5Fopen + + + X + + + +
    + + #H5Freopen + + + + + +
    + + #H5Funmount + + + + + +
    +
    + H5G + + #H5Gcreate +
    + #H5Gcreate1 +
    + #H5Gcreate2 +
    + + X + + X + + 1.8.x + + @ref options +
    + The function #H5Gcreate was renamed to + #H5Gcreate1 at Release 1.8.0. +
    + + #H5Gcreate_anon + + + X + + X + + 1.8.x + +
    + + #H5Glink + + + + + +
    + + #H5Glink2 + + + + + 1.6.x + +
    + + #H5Gmove + + + + + +
    + + #H5Gmove2 + + + + + 1.6.x + +
    + + #H5Gset_comment + + + + + +
    + + #H5Gunlink + + + + + +
    +
    + H5I + + #H5Idec_ref + + + + + 1.6.x + + This function may be called independently if the object identifier + does not refer to an object that was collectively opened. +
    + + #H5Iinc_ref + + + + + 1.6.x + + This function may be called independently if the object identifier + does not refer to an object that was collectively opened. +
    +
    + H5L + + #H5Lcopy + + + + + 1.8.x + +
    + + #H5Lcreate_external + + + + X + + 1.8.x + +
    + + #H5Lcreate_hard + + + + X + + 1.8.x + +
    + + #H5Lcreate_soft + + + + X + + 1.8.x + +
    + + #H5Lcreate_ud + + + + X + + 1.8.x + +
    + + #H5Ldelete + + + + + 1.8.x + +
    + + #H5Ldelete_by_idx + + + + + 1.8.x + +
    + + #H5Lmove + + + + + 1.8.x + +
    +
    + H5O + + #H5Ocopy + + + + + 1.8.x + +
    + + #H5Odecr_refcount + + + + + 1.8.x + +
    + + #H5Oincr_refcount + + + + + 1.8.x + +
    + + #H5Olink + + + + + 1.8.x + +
    + + #H5Oset_comment + + + + + 1.8.x + +
    + + #H5Oset_comment_by_name + + + + + 1.8.x + +
    +
    + H5R + + #H5Rcreate + + + + + +
    +
    + H5T + + #H5Tcommit +
    + #H5Tcommit1 +
    + #H5Tcommit2 +
    + + X + + X + + 1.8.x + + @ref options +
    + The function #H5Tcommit was renamed to + #H5Tcommit1 at Release 1.8.0. +
    + + #H5Tcommit_anon + + + X + + X + + 1.8.x + +
    + * + * \section sec_collective_calls_nomod Collective, unless target object will not be modified + * The following functions must normally be called collectively. + * If, however, the target object will not be modified, + * they may be called independently. + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + API + + Function + + All processes: +
    + same datatype & dataspace +
    + All processes: +
    + same access properties +
    + All processes: +
    + same creation properties +
    + Available in releases since + + Additional notes +
    + H5A + + #H5Aclose + + + + + + All processes must participate only if + all file identifiers for a file have been closed and + this is the last outstanding object identifier. +
    + + #H5Aopen + + + X + + + 1.8.x + +
    + + #H5Aopen_by_idx + + + X + + + 1.8.x + +
    + + #H5Aopen_by_name + + + X + + + 1.8.x + +
    + + #H5Aopen_idx + + + X + + + +
    + + #H5Aopen_name + + + X + + + +
    +
    + H5D + + #H5Dclose + + + + + + All processes must participate only if + all file identifiers for a file have been closed and + this is the last outstanding object identifier. +
    + + #H5Dopen +
    + #H5Dopen1 +
    + #H5Dopen2 +
    + + X + + + 1.8.x + + @ref options +
    + The function #H5Dopen was renamed to + #H5Dopen1 at Release 1.8.0. +
    +
    + H5G + + #H5Gclose + + + + + + All processes must participate only if + all file identifiers for a file have been closed and + this is the last outstanding object identifier. +
    + + #H5Gopen +
    + #H5Gopen1 +
    + #H5Gopen2 +
    + + X + + + 1.8.x + + @ref options +
    + The function #H5Gopen was renamed to + #H5Gopen1 at Release 1.8.0. +
    +
    + H5I + + #H5Iget_file_id + + + + + 1.8.x + +
    +
    + H5O + + #H5Oclose + + + + + 1.8.x + + All processes must participate only if + all file identifiers for a file have been closed and + this is the last outstanding object identifier. +
    + + #H5Oopen + + + X + + + 1.8.x + +
    + + #H5Oopen_by_addr + + + X + + + 1.8.x + +
    + + #H5Oopen_by_idx + + + X + + + 1.8.x + +
    +
    + H5R + + #H5Rdereference + + + + + +
    +
    + H5T + + #H5Tclose + + + + + + All processes must participate only if + the datatype is for a committed datatype, + all the file identifiers for the file have been closed, and + this is the last outstanding object identifier. +
    + + #H5Topen +
    + #H5Topen1 +
    + #H5Topen2 +
    + + X + + + 1.8.x + + @ref options +
    + The function #H5Topen was renamed to + #H5Topen1 at Release 1.8.0. +
    + * + * \section sec_collective_calls_props Properties + * The following properties must be set to the same values + * for an object or link in all cases where the object or link is accessed + * in a parallel program. + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Function + + Available in releases since +
    + Dataset creation properties +
    + #H5Pmodify_filter + + 1.8.x +
    + #H5Premove_filter + + 1.8.x +
    + #H5Pset_alloc_time + +
    + #H5Pset_chunk + +
    + #H5Pset_external + +
    + #H5Pset_fill_time + +
    + #H5Pset_fill_value + +
    + #H5Pset_filter + +
    + #H5Pset_fletcher32 + + 1.8.x +
    + #H5Pset_layout + +
    + #H5Pset_nbit + + 1.8.x +
    + #H5Pset_shuffle + +
    + #H5Pset_szip + +
    +
    + Dataset transfer properties + +
    + #H5Pset_btree_ratios + +
    + #H5Pset_buffer + +
    + #H5Pset_dxpl_mpio + +
    + #H5Pset_preserve + +
    +
    + File access properties + +
    + #H5Pset_alignment + +
    + #H5Pset_cache + +
    + #H5Pset_fapl_mpio + +
    + #H5Pset_fclose_degree + +
    + #H5Pset_gc_references + +
    + #H5Fset_latest_format + + 1.8.x +
    + #H5Pset_libver_bounds + + 1.8.x +
    + #H5Pset_mdc_config + +
    + #H5Pset_meta_block_size + +
    + #H5Pset_small_data_block_size + +
    + #H5Pset_sieve_buf_size + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Function + + Available in releases since +
    + File creation properties + +
    + #H5Pset_istore_k + +
    + #H5Pset_shared_mesg_index + + 1.8.x +
    + #H5Pset_shared_mesg_nindexes + + 1.8.x +
    + #H5Pset_shared_mesg_phase_change + + 1.8.x +
    + #H5Pset_sizes + +
    + #H5Pset_sym_k + +
    + #H5Pset_userblock + +
    +
    + Group creation properties + +
    + #H5Pset_est_link_info + + 1.8.x +
    + #H5Pset_link_creation_order + + 1.8.x +
    + #H5Pset_link_phase_change + + 1.8.x +
    + #H5Pset_local_heap_size_hint + + 1.8.x +
    +
    + Link creation properties + +
    + #H5Pset_char_encoding + + 1.8.x +
    + #H5Pset_create_intermediate_group + + 1.8.x +
    +
    + Object creation properties + +
    + #H5Pset_attr_phase_change + + 1.8.x +
    + #H5Pset_attr_creation_order + + 1.8.x +
    + #H5Pset_obj_track_times + + 1.8.x +
    +
    + Object copy properties + +
    + #H5Pset_copy_object + + 1.8.x +
    +
    + + */ diff --git a/doxygen/dox/IntroParHDF5.dox b/doxygen/dox/IntroParHDF5.dox index b8785d43c9d..58a6e7958b0 100644 --- a/doxygen/dox/IntroParHDF5.dox +++ b/doxygen/dox/IntroParHDF5.dox @@ -96,6 +96,8 @@ Once a file is opened by the processes of a communicator: \li Multiple processes write to the same dataset. \li Each process writes to an individual dataset. +@see \ref collective_calls + Please refer to the Supported Configuration Features Summary in the release notes for the current release of HDF5 for an up-to-date list of the platforms that we support Parallel HDF5 on. From c54d6018bc611fb380d9912a66bb150f8e0d738e Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Thu, 29 Aug 2024 07:28:50 -0500 Subject: [PATCH 48/94] Fix grammar in H5Fint.c comment block (#4782) --- src/H5Fint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Fint.c b/src/H5Fint.c index e9817b13048..190d1b25486 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -1786,7 +1786,7 @@ H5F__check_if_using_file_locks(H5P_genplist_t *fapl, bool *use_file_locking, boo * s: the open succeeds with flags combination from both the first and second opens * * NOTE: If the 'try' flag is true, not opening the file with the - * "non-tentative" VFD 'open' call is not treated an error; SUCCEED is + * "non-tentative" VFD 'open' call is not treated as an error; SUCCEED is * returned, with the file ptr set to NULL. If 'try' is false, failing * the "non-tentative" VFD 'open' call generates an error. * From d587796f2c04f9944221d898cf38d7544597b679 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Thu, 29 Aug 2024 11:00:03 -0500 Subject: [PATCH 49/94] Improve the consistency of configure help messages (#4783) Fix grammar in configure message --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index d2406ed81d2..c51e19ddca3 100644 --- a/configure.ac +++ b/configure.ac @@ -3833,10 +3833,10 @@ AC_DEFINE_UNQUOTED([DEFAULT_PLUGINDIR], ["$default_plugindir"], ## for the speed optimization of hard conversions. Soft conversions can ## actually benefit little. ## -AC_MSG_CHECKING([whether exception handling functions is checked during data conversions]) +AC_MSG_CHECKING([whether exception handling functions are checked during data conversions]) AC_ARG_ENABLE([dconv-exception], [AS_HELP_STRING([--enable-dconv-exception], - [if exception handling functions is checked during + [Check exception handling functions during data conversions [default=yes]])], [DCONV_EXCEPTION=$enableval], [DCONV_EXCEPTION=yes]) @@ -3857,7 +3857,7 @@ fi AC_MSG_CHECKING([whether data accuracy is guaranteed during data conversions]) AC_ARG_ENABLE([dconv-accuracy], [AS_HELP_STRING([--enable-dconv-accuracy], - [if data accuracy is guaranteed during + [Guarantee data accuracy during data conversions [default=yes]])], [DATA_ACCURACY=$enableval], [DATA_ACCURACY=yes]) From 7e7d3b30e1ecd04da527d381fe935e64c9115c3c Mon Sep 17 00:00:00 2001 From: Scot Breitenfeld Date: Thu, 29 Aug 2024 14:58:16 -0500 Subject: [PATCH 50/94] Fixes Fortran parallel build race condition for tests (#4789) --- hl/fortran/test/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hl/fortran/test/Makefile.am b/hl/fortran/test/Makefile.am index a74f8ef0fbf..adaa59db4cc 100644 --- a/hl/fortran/test/Makefile.am +++ b/hl/fortran/test/Makefile.am @@ -15,7 +15,9 @@ ## # # HDF5 High-Level Fortran Makefile(.in) - +# +# Autoconf cannot figure out dependencies between modules; disable parallel make +.NOTPARALLEL: include $(top_srcdir)/config/commence.am AM_CPPFLAGS+=-I$(top_srcdir)/src -I$(top_builddir)/src -I$(top_srcdir)/hl/src From bca28060550bbdbaf0babb97a19cd44f18c04723 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:27:44 -0500 Subject: [PATCH 51/94] Update URL documentation links to support site (#4781) --- CITATION.cff | 2 +- HDF5Examples/README.md | 12 +- README.md | 2 +- config/cmake/README.md.cmake.in | 2 +- doc/parallel-compression.md | 55 +- doxygen/aliases | 21 +- doxygen/dox/About.dox | 2 +- doxygen/dox/DDLBNF110.dox | 2 - doxygen/dox/DDLBNF112.dox | 2 - doxygen/dox/DDLBNF114.dox | 2 - doxygen/dox/ExamplesAPI.dox | 141 ++-- doxygen/dox/GettingStarted.dox | 4 +- doxygen/dox/IntroHDF5.dox | 6 +- doxygen/dox/LearnBasics.dox | 8 +- doxygen/dox/LearnBasics3.dox | 16 +- doxygen/dox/LearnHDFView.dox | 4 +- doxygen/dox/Overview.dox | 6 +- doxygen/dox/Specifications.dox | 2 +- doxygen/dox/TechnicalNotes.dox | 269 +++++++- .../ThreadSafe.dox} | 613 ++++++------------ doxygen/dox/ViewTools.dox | 2 +- doxygen/dox/high_level/extension.dox | 12 +- doxygen/examples/FileFormat.html | 1 - doxygen/examples/Filters.html | 450 ------------- doxygen/examples/H5.format.1.0.html | 4 +- doxygen/examples/H5.format.1.1.html | 6 +- doxygen/examples/H5DS_Spec.pdf | Bin 0 -> 746769 bytes doxygen/examples/IOFlow.html | 1 - .../LibraryReleaseVersionNumbers.html | 2 +- doxygen/examples/intro_SWMR.html | 103 --- doxygen/examples/intro_VDS.html | 72 -- doxygen/examples/tables/propertyLists.dox | 8 +- doxygen/hdf5doxy_layout.xml | 6 +- hl/src/H5DOpublic.h | 2 +- hl/src/H5DSpublic.h | 6 +- hl/src/H5LTpublic.h | 10 +- java/src/hdf/overview.html | 2 +- java/src/jni/exceptionImp.c | 6 - java/src/jni/h5Constants.c | 6 - java/src/jni/h5Imp.c | 6 - java/src/jni/h5aImp.c | 6 - java/src/jni/h5dImp.c | 6 - java/src/jni/h5eImp.c | 3 - java/src/jni/h5fImp.c | 6 - java/src/jni/h5gImp.c | 6 - java/src/jni/h5iImp.c | 6 - java/src/jni/h5jni.h | 6 - java/src/jni/h5lImp.c | 6 - java/src/jni/h5oImp.c | 6 - java/src/jni/h5pACPLImp.c | 6 - java/src/jni/h5pDAPLImp.c | 6 - java/src/jni/h5pDCPLImp.c | 6 - java/src/jni/h5pDXPLImp.c | 6 - java/src/jni/h5pFAPLImp.c | 6 - java/src/jni/h5pFCPLImp.c | 6 - java/src/jni/h5pGAPLImp.c | 6 - java/src/jni/h5pGCPLImp.c | 6 - java/src/jni/h5pImp.c | 6 - java/src/jni/h5pLAPLImp.c | 6 - java/src/jni/h5pLCPLImp.c | 6 - java/src/jni/h5pOCPLImp.c | 6 - java/src/jni/h5pOCpyPLImp.c | 6 - java/src/jni/h5pStrCPLImp.c | 6 - java/src/jni/h5plImp.c | 6 - java/src/jni/h5rImp.c | 5 - java/src/jni/h5sImp.c | 6 - java/src/jni/h5tImp.c | 6 - java/src/jni/h5util.c | 6 - java/src/jni/h5util.h | 6 - java/src/jni/h5vlImp.c | 6 - java/src/jni/h5zImp.c | 6 - java/src/jni/nativeData.c | 5 - release_docs/INSTALL | 2 +- release_docs/INSTALL_Autotools.txt | 4 +- release_docs/INSTALL_CMake.txt | 2 +- release_docs/INSTALL_parallel | 2 +- release_docs/RELEASE.txt | 6 +- release_docs/RELEASE_PROCESS.md | 66 +- src/H5Amodule.h | 24 +- src/H5Dmodule.h | 8 +- src/H5Emodule.h | 91 ++- src/H5Fmodule.h | 29 +- src/H5Gmodule.h | 2 +- src/H5PLmodule.h | 8 +- src/H5Pmodule.h | 4 +- src/H5Ppublic.h | 2 +- src/H5Smodule.h | 203 +++++- src/H5Tmodule.h | 13 +- src/H5module.h | 8 +- tools/src/h5dump/h5dump.c | 2 +- tools/test/h5dump/expected/h5dump-help.txt | 2 +- .../pbits/tnofilename-with-packed-bits.ddl | 2 +- .../expected/pbits/tpbitsIncomplete.ddl | 2 +- .../expected/pbits/tpbitsLengthExceeded.ddl | 2 +- .../expected/pbits/tpbitsLengthPositive.ddl | 2 +- .../expected/pbits/tpbitsMaxExceeded.ddl | 2 +- .../expected/pbits/tpbitsOffsetExceeded.ddl | 2 +- .../expected/pbits/tpbitsOffsetNegative.ddl | 2 +- 98 files changed, 948 insertions(+), 1607 deletions(-) rename doxygen/{examples/ThreadSafeLibrary.html => dox/ThreadSafe.dox} (62%) delete mode 100644 doxygen/examples/Filters.html create mode 100644 doxygen/examples/H5DS_Spec.pdf delete mode 100644 doxygen/examples/intro_SWMR.html delete mode 100644 doxygen/examples/intro_VDS.html diff --git a/CITATION.cff b/CITATION.cff index 4e611a57468..f7eaf133318 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,4 +9,4 @@ authors: website: 'https://www.hdfgroup.org' repository-code: 'https://github.com/HDFGroup/hdf5' url: 'https://www.hdfgroup.org/HDF5/' -repository-artifact: 'https://www.hdfgroup.org/downloads/hdf5/' +repository-artifact: 'https://support.hdfgroup.org/downloads/HDF5' diff --git a/HDF5Examples/README.md b/HDF5Examples/README.md index 2f0090ba02c..e70a1a792d0 100644 --- a/HDF5Examples/README.md +++ b/HDF5Examples/README.md @@ -48,17 +48,17 @@ HDF5 SNAPSHOTS, PREVIOUS RELEASES AND SOURCE CODE -------------------------------------------- Full Documentation and Programming Resources for this HDF5 can be found at - https://portal.hdfgroup.org/documentation/index.html + https://support.hdfgroup.org/documentation/HDF5/index.html Periodically development code snapshots are provided at the following URL: - - https://gamma.hdfgroup.org/ftp/pub/outgoing/hdf5/snapshots/ + + https://github.com/HDFGroup/hdf5/releases Source packages for current and previous releases are located at: - - https://portal.hdfgroup.org/downloads/ + + https://support.hdfgroup.org/releases/hdf5/downloads/ Development code is available at our Github location: - + https://github.com/HDFGroup/hdf5.git diff --git a/README.md b/README.md index 36f853c6990..1be794abcb1 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ Periodically development code snapshots are provided at the following URL: Source packages for current and previous releases are located at: - https://portal.hdfgroup.org/Downloads + https://support.hdfgroup.org/downloads/HDF5 Development code is available at our Github location: diff --git a/config/cmake/README.md.cmake.in b/config/cmake/README.md.cmake.in index 7f6af3646a2..3f541e4e8a3 100644 --- a/config/cmake/README.md.cmake.in +++ b/config/cmake/README.md.cmake.in @@ -75,6 +75,6 @@ For more information see USING_CMake_Examples.txt in the install folder. =========================================================================== Documentation for this release can be found at the following URL: - https://portal.hdfgroup.org/documentation/index.html#hdf5 + https://support.hdfgroup.org/hdf5/@HDF5_PACKAGE_NAME@-@HDF5_PACKAGE_VERSION@/documentation/doxygen/index.html Bugs should be reported to help@hdfgroup.org. diff --git a/doc/parallel-compression.md b/doc/parallel-compression.md index 48ed4c3c37d..77126d6acf6 100644 --- a/doc/parallel-compression.md +++ b/doc/parallel-compression.md @@ -64,9 +64,9 @@ H5Dwrite(..., dxpl_id, ...); The following are two simple examples of using the parallel compression feature: -[ph5_filtered_writes.c](https://github.com/HDFGroup/hdf5/blob/develop/HDF5Examples/C/H5PAR/ph5_filtered_writes.c) +[ph5_filtered_writes.c][u1] -[ph5_filtered_writes_no_sel.c](https://github.com/HDFGroup/hdf5/blob/develop/HDF5Examples/C/H5PAR/ph5_filtered_writes_no_sel.c) +[ph5_filtered_writes_no_sel.c][u2] The former contains simple examples of using the parallel compression feature to write to compressed datasets, while the @@ -79,7 +79,7 @@ participate in the collective write call. ## Multi-dataset I/O support The parallel compression feature is supported when using the -multi-dataset I/O API routines ([H5Dwrite_multi](https://hdfgroup.github.io/hdf5/develop/group___h5_d.html#gaf6213bf3a876c1741810037ff2bb85d8)/[H5Dread_multi](https://hdfgroup.github.io/hdf5/develop/group___h5_d.html#ga8eb1c838aff79a17de385d0707709915)), but the +multi-dataset I/O API routines ([H5Dwrite_multi][u3]/[H5Dread_multi][u4]), but the following should be kept in mind: - Parallel writes to filtered datasets **must** still be collective, @@ -99,7 +99,7 @@ following should be kept in mind: ## Incremental file space allocation support -HDF5's [file space allocation time](https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga85faefca58387bba409b65c470d7d851) +HDF5's [file space allocation time][u5] is a dataset creation property that can have significant effects on application performance, especially if the application uses parallel HDF5. In a serial HDF5 application, the default file space @@ -118,7 +118,7 @@ While this strategy has worked in the past, it has some noticeable drawbacks. For one, the larger the chunked dataset being created, the more noticeable overhead there will be during dataset creation as all of the data chunks are being allocated in the HDF5 file. -Further, these data chunks will, by default, be [filled](https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga4335bb45b35386daa837b4ff1b9cd4a4) +Further, these data chunks will, by default, be [filled][u6] with HDF5's default fill data value, leading to extraordinary dataset creation overhead and resulting in pre-filling large portions of a dataset that the application might have been planning @@ -126,12 +126,12 @@ to overwrite anyway. Even worse, there will be more initial overhead from compressing that fill data before writing it out, only to have it read back in, unfiltered and modified the first time a chunk is written to. In the past, it was typically suggested that parallel -HDF5 applications should use [H5Pset_fill_time](https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga6bd822266b31f86551a9a1d79601b6a2) +HDF5 applications should use [H5Pset_fill_time][u7] with a value of `H5D_FILL_TIME_NEVER` in order to disable writing of the fill value to dataset chunks, but this isn't ideal if the application actually wishes to make use of fill values. -With [improvements made](https://www.hdfgroup.org/2022/03/parallel-compression-improvements-in-hdf5-1-13-1/) +With [improvements made][u8] to the parallel compression feature for the HDF5 1.13.1 release, "incremental" file space allocation is now the default for datasets created in parallel *only if they have filters applied to them*. @@ -154,7 +154,7 @@ optimal performance out of the parallel compression feature. ### Begin with a good chunking strategy -[Starting with a good chunking strategy](https://portal.hdfgroup.org/documentation/hdf5-docs/chunking_in_hdf5.html) +[Starting with a good chunking strategy][u9] will generally have the largest impact on overall application performance. The different chunking parameters can be difficult to fine-tune, but it is essential to start with a well-performing @@ -166,7 +166,7 @@ chosen chunk size becomes a very important factor when compression is involved, as data chunks have to be completely read and re-written to perform partial writes to the chunk. -[Improving I/O performance with HDF5 compressed datasets](https://docs.hdfgroup.org/archive/support/HDF5/doc/TechNotes/TechNote-HDF5-ImprovingIOPerformanceCompressedDatasets.pdf) +[Improving I/O performance with HDF5 compressed datasets][u10] is a useful reference for more information on getting good performance when using a chunked dataset layout. @@ -220,14 +220,14 @@ chunks to end up at addresses in the file that do not align well with the underlying file system, possibly leading to poor performance. As an example, Lustre performance is generally good when writes are aligned with the chosen stripe size. -The HDF5 application can use [H5Pset_alignment](https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a) +The HDF5 application can use [H5Pset_alignment][u11] to have a bit more control over where objects in the HDF5 file end up. However, do note that setting the alignment of objects generally wastes space in the file and has the potential to dramatically increase its resulting size, so caution should be used when choosing the alignment parameters. -[H5Pset_alignment](https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a) +[H5Pset_alignment][u11] has two parameters that control the alignment of objects in the HDF5 file, the "threshold" value and the alignment value. The threshold value specifies that any object greater @@ -264,19 +264,19 @@ in a file, this can create significant amounts of free space in the file over its lifetime and eventually cause performance issues. -An HDF5 application can use [H5Pset_file_space_strategy](https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#ga167ff65f392ca3b7f1933b1cee1b9f70) +An HDF5 application can use [H5Pset_file_space_strategy][u12] with a value of `H5F_FSPACE_STRATEGY_PAGE` to enable the paged aggregation feature, which can accumulate metadata and raw data for dataset data chunks into well-aligned, configurably sized "pages" for better performance. However, note that using the paged aggregation feature will cause any setting from -[H5Pset_alignment](https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a) +[H5Pset_alignment][u11] to be ignored. While an application should be able to get -comparable performance effects by [setting the size of these pages](https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#gad012d7f3c2f1e1999eb1770aae3a4963) to be equal to the value that -would have been set for [H5Pset_alignment](https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a), +comparable performance effects by [setting the size of these pages][u13] +to be equal to the value that would have been set for [H5Pset_alignment][u11], this may not necessarily be the case and should be studied. -Note that [H5Pset_file_space_strategy](https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#ga167ff65f392ca3b7f1933b1cee1b9f70) +Note that [H5Pset_file_space_strategy][u12] has a `persist` parameter. This determines whether or not the file free space manager should include extra metadata in the HDF5 file about free space sections in the file. If this @@ -300,12 +300,12 @@ hid_t file_id = H5Fcreate("file.h5", H5F_ACC_TRUNC, fcpl_id, fapl_id); While the parallel compression feature requires that the HDF5 application set and maintain collective I/O at the application -interface level (via [H5Pset_dxpl_mpio](https://hdfgroup.github.io/hdf5/develop/group___d_x_p_l.html#ga001a22b64f60b815abf5de8b4776f09e)), +interface level (via [H5Pset_dxpl_mpio][u14]), it does not require that the actual MPI I/O that occurs at the lowest layers of HDF5 be collective; independent I/O may perform better depending on the application I/O patterns and parallel file system performance, among other factors. The -application may use [H5Pset_dxpl_mpio_collective_opt](https://hdfgroup.github.io/hdf5/develop/group___d_x_p_l.html#gacb30d14d1791ec7ff9ee73aa148a51a3) +application may use [H5Pset_dxpl_mpio_collective_opt][u15] to control this setting and see which I/O method provides the best performance. @@ -318,7 +318,7 @@ H5Dwrite(..., dxpl_id, ...); ### Runtime HDF5 Library version -An HDF5 application can use the [H5Pset_libver_bounds](https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gacbe1724e7f70cd17ed687417a1d2a910) +An HDF5 application can use the [H5Pset_libver_bounds][u16] routine to set the upper and lower bounds on library versions to use when creating HDF5 objects. For parallel compression specifically, setting the library version to the latest available @@ -332,3 +332,20 @@ H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); hid_t file_id = H5Fcreate("file.h5", H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); ... ``` + +[u1]: https://github.com/HDFGroup/hdf5/blob/develop/HDF5Examples/C/H5PAR/ph5_filtered_writes.c +[u2]: https://github.com/HDFGroup/hdf5/blob/develop/HDF5Examples/C/H5PAR/ph5_filtered_writes_no_sel.c +[u3]: https://hdfgroup.github.io/hdf5/develop/group___h5_d.html#gaf6213bf3a876c1741810037ff2bb85d8 +[u4]: https://hdfgroup.github.io/hdf5/develop/group___h5_d.html#ga8eb1c838aff79a17de385d0707709915 +[u5]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga85faefca58387bba409b65c470d7d851 +[u6]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga4335bb45b35386daa837b4ff1b9cd4a4 +[u7]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga6bd822266b31f86551a9a1d79601b6a2 +[u8]: https://support.hdfgroup.org/documentation/HDF5/parallel-compression-improvements-in-hdf5-1-13-1 +[u9]: https://support.hdfgroup.org/documentation/HDF5/chunking_in_hdf5.html +[u10]: https://support.hdfgroup.org/documentation/HDF5/technotes/TechNote-HDF5-ImprovingIOPerformanceCompressedDatasets.pdf +[u11]: https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a +[u12]: https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#ga167ff65f392ca3b7f1933b1cee1b9f70 +[u13]: https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#gad012d7f3c2f1e1999eb1770aae3a4963 +[u14]: https://hdfgroup.github.io/hdf5/develop/group___d_x_p_l.html#ga001a22b64f60b815abf5de8b4776f09e +[u15]: https://hdfgroup.github.io/hdf5/develop/group___d_x_p_l.html#gacb30d14d1791ec7ff9ee73aa148a51a3 +[u16]: https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gacbe1724e7f70cd17ed687417a1d2a910 diff --git a/doxygen/aliases b/doxygen/aliases index 4bb6e8c0792..24a496c2203 100644 --- a/doxygen/aliases +++ b/doxygen/aliases @@ -4,17 +4,16 @@ ALIASES += THG="The HDF Group" # Default URLs (Note that md files do not use any aliases) ################################################################################ # Default URL for HDF Group Files -ALIASES += HDFURL="docs.hdfgroup.org/hdf5" +ALIASES += HDFURL="support.hdfgroup.org" # URL for archived files -ALIASES += ARCURL="docs.hdfgroup.org/archive/support/HDF5/doc" +ALIASES += ARCURL="\HDFURL/archive/support/HDF5/doc" # URL for RFCs -ALIASES += RFCURL="docs.hdfgroup.org/hdf5/rfc" +ALIASES += RFCURL="\HDFURL/hdf5/rfc" # URL for documentation -ALIASES += DSPURL="portal.hdfgroup.org/display/HDF5" -ALIASES += DOCURL="portal.hdfgroup.org/documentation/hdf5-docs" +ALIASES += DOCURL="\HDFURL/releases/hdf5/documentation" # URL for downloads -ALIASES += DWNURL="portal.hdfgroup.org/downloads" -ALIASES += AEXURL="support.hdfgroup.org/ftp/HDF5/examples" +ALIASES += DWNURL="\HDFURL/releases/hdf5/downloads" +ALIASES += AEXURL="\HDFURL/archive/support/ftp/HDF5/examples" # doxygen subdir (develop, v1_14) ALIASES += DOXURL="hdfgroup.github.io/hdf5/develop" #branch name (develop, hdf5_1_14) @@ -259,13 +258,13 @@ ALIASES += sa_metadata_ops="\sa \li H5Pget_all_coll_metadata_ops() \li H5Pget_co ALIASES += ref_cons_semantics="
    Enabling a Strict Consistency Semantics Model in Parallel HDF5" ALIASES += ref_file_image_ops="HDF5 File Image Operations" -ALIASES += ref_filter_pipe="Data Flow Pipeline for H5Dread()" +ALIASES += ref_filter_pipe="Data Flow Pipeline for H5Dread()" ALIASES += ref_group_impls="Group implementations in HDF5" ALIASES += ref_h5lib_relver="HDF5 Library Release Version Numbers" -ALIASES += ref_mdc_in_hdf5="Metadata Caching in HDF5" -ALIASES += ref_mdc_logging="Metadata Cache Logging" +ALIASES += ref_mdc_in_hdf5="Metadata Caching in HDF5" +ALIASES += ref_mdc_logging="Metadata Cache Logging" ALIASES += ref_news_112="New Features in HDF5 Release 1.12" -ALIASES += ref_h5ocopy="Copying Committed Datatypes with H5Ocopy()" +ALIASES += ref_h5ocopy="Copying Committed Datatypes with H5Ocopy()" ALIASES += ref_sencode_fmt_change="RFC H5Sencode() / H5Sdecode() Format Change" ALIASES += ref_vlen_strings="\Emph{Creating variable-length string datatypes}" ALIASES += ref_vol_doc="VOL documentation" diff --git a/doxygen/dox/About.dox b/doxygen/dox/About.dox index e145516a30e..73010b0c3de 100644 --- a/doxygen/dox/About.dox +++ b/doxygen/dox/About.dox @@ -83,7 +83,7 @@ as a general reference. All custom commands for this project are located in the aliases -file in the doxygen +file in the doxygen subdirectory of the main HDF5 repo. The custom commands are grouped in sections. Find a suitable section for your command or diff --git a/doxygen/dox/DDLBNF110.dox b/doxygen/dox/DDLBNF110.dox index 6d6b67ef7fd..b392526417a 100644 --- a/doxygen/dox/DDLBNF110.dox +++ b/doxygen/dox/DDLBNF110.dox @@ -1,7 +1,5 @@ /** \page DDLBNF110 DDL in BNF through HDF5 1.10 -\todo Revise this & break it up! - \section intro110 Introduction This document contains the data description language (DDL) for an HDF5 file. The diff --git a/doxygen/dox/DDLBNF112.dox b/doxygen/dox/DDLBNF112.dox index cfe34c321f9..c6463c23d5c 100644 --- a/doxygen/dox/DDLBNF112.dox +++ b/doxygen/dox/DDLBNF112.dox @@ -1,7 +1,5 @@ /** \page DDLBNF112 DDL in BNF for HDF5 1.12 through HDF5 1.14.3 -\todo Revise this & break it up! - \section intro112 Introduction This document contains the data description language (DDL) for an HDF5 file. The diff --git a/doxygen/dox/DDLBNF114.dox b/doxygen/dox/DDLBNF114.dox index 61e9157e560..baa7a57fea6 100644 --- a/doxygen/dox/DDLBNF114.dox +++ b/doxygen/dox/DDLBNF114.dox @@ -1,7 +1,5 @@ /** \page DDLBNF114 DDL in BNF for HDF5 1.14.4 and above -\todo Revise this & break it up! - \section intro114 Introduction This document contains the data description language (DDL) for an HDF5 file. The diff --git a/doxygen/dox/ExamplesAPI.dox b/doxygen/dox/ExamplesAPI.dox index c48b00e6dbb..dbd24f4d888 100644 --- a/doxygen/dox/ExamplesAPI.dox +++ b/doxygen/dox/ExamplesAPI.dox @@ -30,7 +30,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_alloc.h5 @@ -43,7 +43,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_checksum.h5 @@ -56,7 +56,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_chunk.h5 @@ -69,7 +69,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_compact.h5 @@ -82,7 +82,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_extern.h5 @@ -95,7 +95,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_fillval.h5 @@ -108,7 +108,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_gzip.h5 @@ -121,7 +121,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_hyper.h5 @@ -134,7 +134,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_nbit.h5 @@ -147,7 +147,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_rdwrc.h5 @@ -160,7 +160,7 @@ Languages are C, Fortran, Java (JHI5), Java Object Package, Python (High Level), C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_shuffle.h5 @@ -173,7 +173,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_sofloat.h5 @@ -186,7 +186,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_soint.h5 @@ -199,7 +199,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_szip.h5 @@ -212,7 +212,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_transform.h5 @@ -225,7 +225,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_unlimadd.h5 @@ -238,7 +238,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_unlimgzip.h5 @@ -251,7 +251,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_d_unlimmod.h5 @@ -275,7 +275,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_compact.h5 @@ -289,7 +289,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_corder.h5 @@ -302,7 +302,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_create.h5 @@ -315,7 +315,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_intermediate.h5 @@ -328,7 +328,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_iterate.h5 @@ -341,7 +341,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_phase.h5 @@ -366,7 +366,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_g_visit.h5 @@ -388,9 +388,9 @@ FORTRAN Read / Write Array (Attribute) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_arrayatt.h5 @@ -401,9 +401,9 @@ FORTRAN Read / Write Array (Dataset) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_array.h5 @@ -414,9 +414,9 @@ FORTRAN Read / Write Bitfield (Attribute) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_bitatt.h5 @@ -427,9 +427,9 @@ FORTRAN Read / Write Bitfield (Dataset) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_bit.h5 @@ -440,9 +440,9 @@ FORTRAN Read / Write Compound (Attribute) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_cmpdatt.h5 @@ -453,9 +453,9 @@ FORTRAN Read / Write Compound (Dataset) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_cmpd.h5 @@ -468,7 +468,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_commit.h5 @@ -533,7 +533,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_floatatt.h5 @@ -546,7 +546,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_float.h5 @@ -559,7 +559,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_intatt.h5 @@ -572,7 +572,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_int.h5 @@ -585,7 +585,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_objrefatt.h5 @@ -598,7 +598,7 @@ FORTRAN C FORTRAN Java - JavaObj + JavaObj MATLAB PyHigh PyLow h5ex_t_objref.h5 @@ -611,7 +611,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_opaqueatt.h5 @@ -624,7 +624,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_opaque.h5 @@ -637,7 +637,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_regrefatt.h5 @@ -650,7 +650,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_regref.h5 @@ -661,9 +661,9 @@ FORTRAN Read / Write String (Attribute) C -FORTRAN +FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_stringatt.h5 @@ -676,7 +676,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_string.h5 @@ -709,8 +709,7 @@ FORTRAN Read / Write Variable Length String (Attribute) C -FORTRAN - Java JavaObj MATLAB PyHigh PyLow + FORTRAN Java JavaObj MATLAB PyHigh PyLow h5ex_t_vlstringatt.h5 h5ex_t_vlstringatt.tst @@ -722,7 +721,7 @@ FORTRAN C FORTRAN Java -JavaObj +JavaObj MATLAB PyHigh PyLow h5ex_t_vlstring.h5 @@ -843,7 +842,7 @@ FORTRAN Create/Read/Write an Attribute Java -JavaObj +JavaObj HDF5AttributeCreate.txt @@ -851,7 +850,7 @@ FORTRAN Create Datasets Java -JavaObj +JavaObj HDF5DatasetCreate.txt @@ -859,7 +858,7 @@ FORTRAN Read/Write Datasets Java -JavaObj +JavaObj HDF5DatasetRead.txt @@ -867,7 +866,7 @@ FORTRAN Create an Empty File Java -JavaObj +JavaObj HDF5FileCreate.txt @@ -883,9 +882,9 @@ FORTRAN Create Groups Java -JavaObj +JavaObj -HDF5GroupCreate.txt +HDF5GroupCreate.txt Select a Subset of a Dataset @@ -899,9 +898,9 @@ FORTRAN Create Two Datasets Within Groups Java -JavaObj +JavaObj -HDF5GroupDatasetCreate.txt +HDF5GroupDatasetCreate.txt @@ -918,7 +917,7 @@ FORTRAN Creating and Accessing a File C -FORTRAN +FORTRAN MATLAB PyHigh PyLow ph5_.h5 @@ -928,7 +927,7 @@ FORTRAN Creating and Accessing a Dataset C -FORTRAN +FORTRAN MATLAB PyHigh PyLow ph5_.h5 @@ -938,7 +937,7 @@ FORTRAN Writing and Reading Contiguous Hyperslabs C -FORTRAN +FORTRAN MATLAB PyHigh PyLow ph5_.h5 @@ -948,7 +947,7 @@ FORTRAN Writing and Reading Regularly Spaced Data Hyperslabs C -FORTRAN +FORTRAN MATLAB PyHigh PyLow ph5_.h5 @@ -958,7 +957,7 @@ FORTRAN Writing and Reading Pattern Hyperslabs C -FORTRAN +FORTRAN MATLAB PyHigh PyLow ph5_.h5 @@ -968,7 +967,7 @@ FORTRAN Writing and Reading Chunk Hyperslabs C -FORTRAN +FORTRAN MATLAB PyHigh PyLow ph5_.h5 @@ -978,7 +977,8 @@ FORTRAN Using the Subfiling VFD to Write a File Striped Across Multiple Subfiles C - FORTRAN MATLAB PyHigh PyLow +FORTRAN + MATLAB PyHigh PyLow ph5_.h5 ph5_.tst @@ -996,7 +996,8 @@ FORTRAN Collectively Write Datasets with Filters and Not All Ranks have Data C - FORTRAN MATLAB PyHigh PyLow +FORTRAN + MATLAB PyHigh PyLow ph5_.h5 ph5_.tst diff --git a/doxygen/dox/GettingStarted.dox b/doxygen/dox/GettingStarted.dox index aa81ca28744..274598c9537 100644 --- a/doxygen/dox/GettingStarted.dox +++ b/doxygen/dox/GettingStarted.dox @@ -38,7 +38,7 @@ Step by step instructions for learning HDF5 that include programming examples \subsection subsec_learn_tutor The HDF Group Tutorials and Examples These tutorials and examples are available for learning about the HDF5 High Level APIs, tools, -Parallel HDF5, and the HDF5-1.10 VDS and SWMR new features: +Parallel HDF5, and the VDS and SWMR features: - @@ -91,7 +91,7 @@ These examples (C, C++, Fortran, Java, Python) are provided in the HDF5 source c - @@ -107,7 +107,7 @@ These examples (C, C++, Fortran, Java, Python) are provided in the HDF5 source c - @@ -131,7 +131,7 @@ These examples (C, C++, Fortran, Java, Python) are provided in the HDF5 source c - diff --git a/doxygen/dox/LearnBasics3.dox b/doxygen/dox/LearnBasics3.dox index 3e9dd8ea090..d853c83d742 100644 --- a/doxygen/dox/LearnBasics3.dox +++ b/doxygen/dox/LearnBasics3.dox @@ -183,7 +183,7 @@ to a new with a new layout. \section secLBDsetLayoutSource Sources of Information Chunking in HDF5 (See the documentation on Advanced Topics in HDF5) -\see \ref sec_plist in the HDF5 \ref UG. +see \ref sec_plist in the HDF5 \ref UG.
    Previous Chapter \ref LBPropsList - Next Chapter \ref LBExtDset @@ -251,7 +251,7 @@ The following operations are required in order to create a compressed dataset: \li Create the dataset. \li Close the dataset creation property list and dataset. -For more information on compression, see the FAQ question on Using Compression in HDF5. +For more information on compression, see the FAQ question on Using Compression in HDF5. \section secLBComDsetProg Programming Example @@ -720,7 +720,7 @@ Previous Chapter \ref LBQuiz - Next Chapter \ref LBCompiling Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics -/** @page LBCompiling Compiling HDF5 Applications +@page LBCompiling Compiling HDF5 Applications Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics
    @@ -969,13 +969,13 @@ or on WINDOWS you may need to add the path to the bin folder to PATH. \subsection subsecLBCompilingCMakeScripts CMake Scripts for Building Applications Simple scripts are provided for building applications with different languages and options. -See CMake Scripts for Building Applications. +See CMake Scripts for Building Applications. For a more complete script (and to help resolve issues) see the script provided with the HDF5 Examples project. \subsection subsecLBCompilingCMakeExamples HDF5 Examples The installed HDF5 can be verified by compiling the HDF5 Examples project, included with the CMake built HDF5 binaries -in the share folder or you can go to the HDF5 Examples github repository. +in the share folder or you can go to the HDF5 Examples in the HDF5 github repository. Go into the share directory and follow the instructions in USING_CMake_examples.txt to build the examples. @@ -1035,9 +1035,11 @@ Previous Chapter \ref LBQuizAnswers - Next Chapter \ref LBTraining Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics -*/ +@page LBTraining Training Videos + +Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics -/ref LBTraining +Training Videos
    Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics diff --git a/doxygen/dox/LearnHDFView.dox b/doxygen/dox/LearnHDFView.dox index 2f0a0782e60..cfe11e19137 100644 --- a/doxygen/dox/LearnHDFView.dox +++ b/doxygen/dox/LearnHDFView.dox @@ -7,7 +7,7 @@ This tutorial enables you to get a feel for HDF5 by using the HDFView browser. I any programming experience. \section sec_learn_hv_install HDFView Installation -\li Download and install HDFView. It can be downloaded from the Download HDFView page. +\li Download and install HDFView. It can be downloaded from the Download HDFView page. \li Obtain the storm1.txt text file, used in the tutorial. \section sec_learn_hv_begin Begin Tutorial @@ -246,7 +246,7 @@ in the file). Please note that the chunk sizes used in this topic are for demonstration purposes only. For information on chunking and specifying an appropriate chunk size, see the -Chunking in HDF5 documentation. +Chunking in HDF5 documentation. Also see the HDF5 Tutorial topic on \ref secLBComDsetCreate.
      diff --git a/doxygen/dox/Overview.dox b/doxygen/dox/Overview.dox index c84ce0a9a60..1f68f7c50a3 100644 --- a/doxygen/dox/Overview.dox +++ b/doxygen/dox/Overview.dox @@ -9,19 +9,19 @@ the entire HDF5 ecosystem in one place, and you should also consult the document sets of the many outstanding community projects. For a first contact with HDF5, the best place is to have a look at the \link -GettingStarted getting started\endlink page that shows you how to write and +GettingStarted getting started \endlink page that shows you how to write and compile your first program with HDF5. The \b main \b documentation is organized by documentation flavor. Most technical documentation consists to varying degrees of information related to tasks, concepts, or reference material. As its title -suggests, the \link RM Reference Manual\endlink is 100% reference material, +suggests, the \link RM Reference Manual \endlink is 100% reference material, while the \link Cookbook \endlink is focused on tasks. The different guide-type documents cover a mix of tasks, concepts, and reference, to help a specific audience succeed. \par Offline reading - You can download it as an archive for offline reading. + You can download it as an archive for offline reading. \par ToDo List There is plenty of unfinished business. diff --git a/doxygen/dox/Specifications.dox b/doxygen/dox/Specifications.dox index 42f06d23099..7807fa3ba11 100644 --- a/doxygen/dox/Specifications.dox +++ b/doxygen/dox/Specifications.dox @@ -17,7 +17,7 @@ \li \ref IMG \li \ref TBL -\li +\li HDF5 Dimension Scale Specification */ diff --git a/doxygen/dox/TechnicalNotes.dox b/doxygen/dox/TechnicalNotes.dox index 1737b60ab0b..3ea6af63a25 100644 --- a/doxygen/dox/TechnicalNotes.dox +++ b/doxygen/dox/TechnicalNotes.dox @@ -4,10 +4,10 @@ \li \ref APPDBG \li \ref FMTDISC \li \ref FILEIMGOPS -\li \ref FILTER +\li \ref subsubsec_dataset_transfer_filter \li \ref IOFLOW \li \ref TNMDC -\li \ref MT +\li \ref thread-safe-lib \li \ref SWMR \li \ref VDS \li \ref RELVERSION @@ -17,12 +17,6 @@ */ -/** \page MT HDF5 Thread Safe library - -\htmlinclude ThreadSafeLibrary.html - -*/ - /** \page IOFLOW HDF5 Raw I/O Flow Notes \htmlinclude IOFlow.html @@ -53,12 +47,6 @@ */ -/** \page FILTER HDF5 Filters - -\htmlinclude Filters.html - -*/ - /** \page APPDBG Debugging HDF5 Applications \htmlinclude DebuggingHDF5Applications.html @@ -67,13 +55,262 @@ /** \page SWMR Introduction to Single-Writer/Multiple-Reader (SWMR) -\htmlinclude intro_SWMR.html +\section sec_swmr_intro Introduction to SWMR +The Single-Writer / Multiple-Reader (SWMR) feature enables multiple processes to read an HDF5 file +while it is being written to (by a single process) without using locks or requiring communication between processes. +tutr-swmr1.png + +All communication between processes must be performed via the HDF5 file. The HDF5 file under SWMR access must +reside on a system that complies with POSIX write() semantics. + +The basic engineering challenge for this to work was to ensure that the readers of an HDF5 file always +see a coherent (though possibly not up to date) HDF5 file. + +The issue is that when writing data there is information in the metadata cache in addition to the physical file on disk: +tutr-swmr2.png + +However, the readers can only see the state contained in the physical file: +tutr-swmr3.png + +The SWMR solution implements dependencies on when the metadata can be flushed to the file. This ensures that metadata cache +flush operations occur in the proper order, so that there will never be internal file pointers in the physical file +that point to invalid (unflushed) file addresses. + +A beneficial side effect of using SWMR access is better fault tolerance. It is more difficult to corrupt a file when using SWMR. + +\subsection subsec_swmr_doc Documentation +\subsubsection subsubsec_swmr_doc_guide User Guide +SWMR User Guide + +\subsubsection subsubsec_swmr_doc_apis HDF5 Library APIs +
        +
      • #H5Fstart_swmr_write — Enables SWMR writing mode for a file
      • +
      • #H5DOappend — Appends data to a dataset along a specified dimension
      • +
      • #H5Pset_object_flush_cb — Sets a callback function to invoke when an object flush occurs in the file
      • +
      • #H5Pget_object_flush_cb — Retrieves the object flush property values from the file access property list
      • +
      • #H5Odisable_mdc_flushes — Prevents metadata entries for an HDF5 object from being flushed from the metadata cache to storage
      • +
      • #H5Oenable_mdc_flushes — Enables flushing of dirty metadata entries from a file’s metadata cache
      • +
      • #H5Oare_mdc_flushes_disabled — Determines if an HDF5 object has had flushes of metadata entries disabled
      • +
      + +\subsubsection subsubsec_swmr_doc_tools Tools +\li h5watch — Outputs new records appended to a dataset as the dataset grows +\li h5format_convert — Converts the layout format version and chunked indexing types of datasets created with +HDF5-1.10 so that applications built with HDF5-1.8 can access them +\li h5clear — Clears superblock status_flags field, removes metadata cache image, prints EOA and EOF, or sets EOA of a file + +\subsubsection subsubsec_swmr_doc_design Design Documents + +\subsection subsec_swmr_model Programming Model +Please be aware that the SWMR feature requires that an HDF5 file be created with the latest file format. See +#H5Pset_libver_bounds for more information. + +To use SWMR follow the the general programming model for creating and accessing HDF5 files and objects along with the steps described below. + +\subsubsection subsubsec_swmr_model_writer SWMR Writer +The SWMR writer either opens an existing file and objects or creates them as follows. + +Open an existing file: +Call #H5Fopen using the #H5F_ACC_SWMR_WRITE flag. +Begin writing datasets. +Periodically flush data. + +Create a new file: +Call #H5Fcreate using the latest file format. +Create groups, datasets and attributes, and then close the attributes. +Call #H5Fstart_swmr_write to start SWMR access to the file. +Periodically flush data. + +

      Example Code:

      +Create the file using the latest file format property: +\code + fapl = H5Pcreate (H5P_FILE_ACCESS); + status = H5Pset_libver_bounds (fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + fid = H5Fcreate (filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + // Create objects (files, datasets, ...). + // Close any attributes and named datatype objects. + // Groups and datasets may remain open before starting SWMR access to them. + + // Start SWMR access to the file: + status = H5Fstart_swmr_write (fid); + + // Reopen the datasets and then start writing, periodically flushing data: + status = H5Dwrite (dset_id, ...); + status = H5Dflush (dset_id); +\endcode + +\subsubsection subsubsec_swmr_model_reader SWMR Reader +The SWMR reader must continually poll for new data: + +Call #H5Fopen using the #H5F_ACC_SWMR_READ flag. +Poll, checking the size of the dataset to see if there is new data available for reading. +Read new data, if any. + +

      Example Code:

      +\code + // Open the file using the SWMR read flag: + fid = H5Fopen (filename, H5F_ACC_RDONLY | H5F_ACC_SWMR_READ, H5P_DEFAULT); + // Open the dataset and then repeatedly poll the dataset, by getting the dimensions, reading new data, and refreshing: + dset_id = H5Dopen (...); + space_id = H5Dget_space (...); + while (...) { + status = H5Dread (dset_id, ...); + status = H5Drefresh (dset_id); + space_id = H5Dget_space (...); + } +\endcode + +\subsection subsec_swmr_scope Limitations and Scope +An HDF5 file under SWMR access must reside on a system that complies with POSIX write() +semantics. It is also limited in scope as follows. + +The writer process is only allowed to modify raw data of existing datasets by; +Appending data along any unlimited dimension. +Modifying existing data +The following operations are not allowed (and the corresponding HDF5 files will fail) +\li The writer cannot add new objects to the file. +\li The writer cannot delete objects in the file. +\li The writer cannot modify or append data with variable length, string or region reference datatypes. +\li File space recycling is not allowed. As a result the size of a file modified by a SWMR writer may be larger than a file modified by a non-SWMR writer.

      + +\subsection subsec_swmr_tools Tools for Working with SWMR +Two new tools, h5watch and h5clear, are available for use with SWMR. The other HDF5 utilities have also been modified to recognize SWMR +\li The h5watch tool allows a user to monitor the growth of a dataset. +\li The h5clear tool clears the status flags in the superblock of an HDF5 file. +\li The rest of the HDF5 tools will exit gracefully but not work with SWMR otherwise. + +\subsection subsec_swmr_example Programming Example +A good example of using SWMR is included with the HDF5 tests in the source code. You can run it while reading +the file it creates. If you then interrupt the application and reader and look at the resulting file, you will +see that the file is still valid. Follow these steps: +\li Download the HDF5 source code to a local directory on a filesystem (that complies with POSIX write() semantics). +Build the software. No special configuration options are needed to use SWMR. +\li Invoke two command terminal windows. In one window go into the bin directory of the built binaries. +In the other window go into the test directory of the HDF5-1.10 source code that was just built. +\li In the window in the test directory compile and run use_append_chunk.c. The example writes a three +dimensional dataset by planes (with chunks of size 1 x 256 x 256). +\li In the other window (in the bin directory) run h5watch on the file created by +use_append_chunk.c (use_append_chunk.h5). It should be run while use_append_chunk is executing and you +will see valid data displayed with h5watch. +\li Interrupt use_append_chunk while it is running, and stop h5watch. +\li Use h5clear to clear the status flags in the superblock of the HDF5 file (use_append_chunk.h5). +\li View the file with h5dump. You will see that it is a valid file even though the application did not +close properly. It will contain data up to the point that it was interrupted. */ /** \page VDS Introduction to the Virtual Dataset - VDS -\htmlinclude intro_VDS.html +\section sec_vds_intro Introduction to VDS +The HDF5 Virtual Dataset (VDS) feature enables users to access data in a collection of HDF5 files as a +single HDF5 dataset and to use the HDF5 APIs to work with that dataset. + +For example, your data may be collected into four files: +tutrvds-multimgs.png + +You can map the datasets in the four files into a single VDS that can be accessed just like any other dataset: +tutrvds-snglimg.png + +The mapping between a VDS and the HDF5 source datasets is persistent and transparent to an application. If a source +file is missing the fill value will be displayed. + +See the Virtual (VDS) Documentation for complete details regarding the VDS feature. + +The VDS feature was implemented using hyperslab selection (#H5Sselect_hyperslab). See the tutorial on +Reading From or Writing to a Subset of a Dataset for more information on selecting hyperslabs. + +\subsection subsec_vds_intro_model Programming Model +To create a Virtual Dataset you simply follow the HDF5 programming model and add a few additional API calls +to map the source code datasets to the VDS. + +Following are the steps for creating a Virtual Dataset: +\li Create the source datasets that will comprise the VDS +\li Create the VDS: ‐ Define a datatype and dataspace (can be unlimited) +\li Define the dataset creation property list (including fill value) +\li (Repeat for each source dataset) Map elements from the source dataset to elements of the VDS +\li Select elements in the source dataset (source selection) +\li Select elements in the virtual dataset (destination selection) +\li Map destination selections to source selections (see Functions for Working with a VDS) +\li Call H5Dcreate using the properties defined above +\li Access the VDS as a regular HDF5 dataset +\li Close the VDS when finished + +

      Functions for Working with a VDS

      +The #H5Pset_virtual API sets the mapping between virtual and source datasets. This is a dataset creation property list. +Using this API will change the layout of the dataset to #H5D_VIRTUAL. As with specifying any dataset creation property +list, an instance of the property list is created, modified, passed into the dataset creation call and then closed: +\code + dcpl = H5Pcreate (H5P_DATASET_CREATE); + src_space = H5screate_simple ... + status = H5Sselect_hyperslab (space, ... + status = H5Pset_virtual (dcpl, space, SRC_FILE[i], SRC_DATASET[i], src_space); + dset = H5Dcreate2 (file, DATASET, H5T_NATIVE_INT, space, H5P_DEFAULT, dcpl, H5P_DEFAULT); + status = H5Pclose (dcpl); +\endcode + +There are several other APIs introduced with Virtual Datasets, including query functions. For details +see the complete list of HDF5 library APIs that support Virtual Datasets. + +

      Limitations

      +This feature was introduced in HDF5-1.10. + +The number of source datasets is unlimited. However, there is a limit on the size of each source dataset. + +\subsection subsec_vds_intro_examples Programming Examples +Example 1 +This example creates three HDF5 files, each with a one-dimensional dataset of 6 elements. The datasets in these files +are the source datasets that are then used to create a 4 x 6 Virtual Dataset with a fill value of -1. The first three +rows of the VDS are mapped to the data from the three source datasets as shown below: +tutrvds-ex.png + +In this example the three source datasets are mapped to the VDS with this code: +\code> +src_space = H5Screate_simple (RANK1, dims, NULL); +for (i = 0; i < 3; i++) { + start[0] = (hsize_t)i; + // Select i-th row in the virtual dataset; selection in the source datasets is the same. + status = H5Sselect_hyperslab (space, H5S_SELECT_SET, start, NULL, count, block); + status = H5Pset_virtual (dcpl, space, SRC_FILE[i], SRC_DATASET[i], src_space); +} +endcode> + +After the VDS is created and closed, it is reopened. The property list is then queried to determine the +layout of the dataset and its mappings, and the data in the VDS is read and printed. + +This example is in the HDF5 source code and can be obtained from here: +

      C Example

      +For details on compiling an HDF5 application: [ Compiling HDF5 Applications ] + +

      Example 2

      +This example shows how to use a C-style printf statement for specifying multiple source datasets as one virtual +dataset. Only one mapping is required. In other words only one #H5Pset_virtual call is needed to map multiple datasets. +It creates a 2-dimensional unlimited VDS. Then it re-opens the file, makes queries, and reads the virtual dataset. + +The source datasets are specified as A-0, A-1, A-2, and A-3. These are mapped to the virtual dataset with one call: +\code +status = H5Pset_virtual (dcpl, vspace, SRCFILE, "A-%b", src_space); +\endcode + +The %b indicates that the block count of the selection in the dimension should be used. + +

      C Example

      +For details on compiling an HDF5 application: [ Compiling HDF5 Applications ] + +Using h5dump with a VDS +The h5dump utility can be used to view a VDS. The h5dump output for a VDS looks exactly like that for any other dataset. +If h5dump cannot find a source dataset then the fill value will be displayed. + +You can determine that a dataset is a VDS by looking at its properties with +\code + h5dump -p +\endcode + It will display each source dataset mapping, beginning with Mapping 0. Below is an excerpt of the output of +\code + h5dump -p +\endcode +on the vds.h5 file created in Example 1.You can see that the entire source file a.h5 is mapped to the first row of the VDS dataset. + +tutrvds-map.png */ diff --git a/doxygen/examples/ThreadSafeLibrary.html b/doxygen/dox/ThreadSafe.dox similarity index 62% rename from doxygen/examples/ThreadSafeLibrary.html rename to doxygen/dox/ThreadSafe.dox index 5824dc6feac..73365120527 100644 --- a/doxygen/examples/ThreadSafeLibrary.html +++ b/doxygen/dox/ThreadSafe.dox @@ -1,155 +1,95 @@ - - - - Thread Safe Library - +/** \page thread-safe-lib Thread Safe Library -

      1. Library header files and conditional compilation

      - -

      +\section sec_tsafe_compilation Library header files and conditional compilation The following code is placed at the beginning of H5private.h: -

      - -
      -
      +\code
         #ifdef H5_HAVE_THREADSAFE
      -  #include <pthread.h>
      +  #include 
         #endif
      -  
      -
      +\endcode -

      H5_HAVE_THREADSAFE is defined when the HDF5 library is -compiled with the --enable-threadsafe configuration option. In general, +compiled with the --enable-threadsafe configuration option using autotools or +HDF5_ENABLE_THREADSAFE=ON using CMake. In general, code for the non-threadsafe version of HDF5 library are placed within -the #else part of the conditional compilation. The exception +the # else part of the conditional compilation. The exception to this rule are the changes to the FUNC_ENTER (in H5private.h), HRETURN and HRETURN_ERROR (in -H5Eprivate.h) macros (see section 3.2). +H5Eprivate.h) macros (see section \ref subsec_tsafe_macro_ret).

      +\section sec_tsafe_global Global variables/structures -

      2. Global variables/structures

      - -

      2.1 Global library initialization variable

      - -

      +\subsection subsec_tsafe_global_var Global library initialization variable In the threadsafe implementation, the global library initialization variable H5_libinit_g is changed to a global structure consisting of the variable with its associated lock (locks are explained -in section 4.1): -

      - -
      -
      +in section \ref subsec_tsafe_impl_locks):
      +\code
           hbool_t  H5_libinit_g = FALSE;
      -  
      -
      +\endcode -

      becomes -

      - -
      -
      +\code
           H5_api_t H5_g;
      -  
      -
      +\endcode -

      where H5_api_t is -

      - -
      -
      +\code
           typedef struct H5_api_struct {
      -      H5_mutex_t init_lock;           /* API entrance mutex */
      +      H5_mutex_t init_lock;           // API entrance mutex
             hbool_t H5_libinit_g;
           } H5_api_t;
      -  
      -
      +\endcode -

      All former references to H5_libinit_g in the library are now made using the macro H5_INIT_GLOBAL. If the threadsafe library is to be used, the macro is set to H5_g.H5_libinit_g instead. -

      -

      2.2 Global serialization variable

      - -

      +\subsection subsec_tsafe_global_serial Global serialization variable A new global boolean variable H5_allow_concurrent_g is used to determine if multiple threads are allowed to an API call simultaneously. This is set to FALSE. -

      -

      All APIs that are allowed to do so have their own local variable that shadows the global variable and is set to TRUE. In phase 1, no such APIs exist. -

      -

      It is defined in H5.c as follows: -

      - -
      -
      +\code
           hbool_t H5_allow_concurrent_g = FALSE;
      -  
      -
      - -

      2.3 Global thread initialization variable

      +\endcode -

      +\subsection subsec_tsafe_global_init Global thread initialization variable The global variable H5_first_init_g of type pthread_once_t is used to allow only the first thread in the application process to call an initialization function using pthread_once. All subsequent calls to pthread_once by any thread are disregarded. -

      -

      The call sets up the mutex in the global structure H5_g (see -section 3.1) via an initialization function +section \ref subsec_tsafe_global_var) via an initialization function H5_first_thread_init. The first thread initialization -function is described in section 4.2. -

      +function is described in section \ref subsec_tsafe_impl_first. -

      H5_first_init_g is defined in H5.c as follows: -

      - -
      -
      +\code
           pthread_once_t H5_first_init_g = PTHREAD_ONCE_INIT;
      -  
      -
      - -

      2.4 Global key for per-thread error stacks

      +\endcode -

      +\subsection subsec_tsafe_global_key Global key for per-thread error stacks A global pthread-managed key H5_errstk_key_g is used to allow pthreads to maintain a separate error stack (of type H5E_t) for each thread. This is defined in H5.c as: -

      - -
      -
      +\code
           pthread_key_t H5_errstk_key_g;
      -  
      -
      - -

      -Error stack management is described in section 4.3. -

      +\endcode -

      2.5 Global structure and key for thread cancellation prevention

      +Error stack management is described in section \ref subsec_tsafe_impl_err. -

      +\subsection subsec_tsafe_global_cancel Global structure and key for thread cancellation prevention We need to preserve the thread cancellation status of each thread individually by using a key H5_cancel_key_g. The status is preserved using a structure (of type H5_cancel_t) which @@ -157,32 +97,21 @@

      2.5 Global structure and key for thread cancellation prevention

      library and a count (which works very much like the recursive lock counter) which keeps track of the number of API calls the thread makes within the library. -

      -

      The structure is defined in H5private.h as: -

      - -
      -
      -    /* cancellability structure */
      +\code
      +    // cancellability structure
           typedef struct H5_cancel_struct {
             int previous_state;
             unsigned int cancel_count;
           } H5_cancel_t;
      -  
      -
      - -

      -Thread cancellation is described in section 4.4. -

      +\endcode +Thread cancellation is described in section \ref subsec_tsafe_impl_cancel. -

      3. Changes to Macro expansions

      +\section sec_tsafe_macro Changes to Macro expansions -

      3.1 Changes to FUNC_ENTER

      - -

      +\subsection subsec_tsafe_macro_fe Changes to FUNC_ENTER The FUNC_ENTER macro is now extended to include macro calls to initialize first threads, disable cancellability and wraps a lock operation around the checking of the global initialization flag. It @@ -191,458 +120,345 @@

      3.1 Changes to FUNC_ENTER

      possibility that the thread be cancelled just after it has acquired the lock on the library and in that scenario, if the cleanup routines are not properly set, the library would be permanently locked out. -

      -

      The additional macro code and new macro definitions can be found in -Appendix E.1 to E.5. The changes are made in H5private.h. -

      - -

      3.2 Changes to HRETURN and HRETURN_ERROR

      +Appendix \ref subsec_tsafe_app_E. The changes are made in H5private.h. -

      +\subsection subsec_tsafe_macro_ret Changes to HRETURN and HRETURN_ERROR The HRETURN and HRETURN_ERROR macros are the counterparts to the FUNC_ENTER macro described in section -3.1. FUNC_LEAVE makes a macro call to HRETURN, +\ref subsec_tsafe_macro_fe. FUNC_LEAVE makes a macro call to HRETURN, so it is also covered here. -

      -

      The basic changes to these two macros involve adding macro calls to call an unlock operation and re-enable cancellability if necessary. It should be noted that the cancellability should be re-enabled only after the thread has released the lock to the library. The consequence of doing -otherwise would be similar to that described in section 3.1. -

      +otherwise would be similar to that described in section \ref subsec_tsafe_macro_fe. -

      The additional macro code and new macro definitions can be found in -Appendix E.9 to E.9. The changes are made in H5Eprivate.h. -

      - -

      4. Implementation of threadsafe functionality

      +Appendix \ref subsec_tsafe_app_E. The changes are made in H5Eprivate.h. -

      4.1 Recursive Locks

      +\section sec_tsafe_impl Implementation of threadsafe functionality -

      +\subsection subsec_tsafe_impl_locks Recursive Locks A recursive mutex lock m allows a thread t1 to successfully lock m more than once without blocking t1. Another thread t2 will block if t2 tries to lock m while t1 holds the lock to m. If t1 makes k lock calls on m, then it also needs to make k unlock calls on m before it releases the lock. -

      -

      Our implementation of recursive locks is built on top of a pthread mutex lock (which is not recursive). It makes use of a pthread condition variable to have unsuccessful threads wait on the mutex. Waiting threads are awaken by a signal from the final unlock call made by the thread holding the lock. -

      -

      Recursive locks are defined to be the following type (H5private.h): -

      - -
      -
      +\code
           typedef struct H5_mutex_struct {
      -      pthread_t owner_thread;         /* current lock owner */
      -      pthread_mutex_t atomic_lock;    /* lock for atomicity of new mechanism */
      -      pthread_cond_t cond_var;        /* condition variable */
      +      pthread_t owner_thread;         // current lock owner
      +      pthread_mutex_t atomic_lock;    // lock for atomicity of new mechanism
      +      pthread_cond_t cond_var;        // condition variable
             unsigned int lock_count;
           } H5_mutex_t;
      -  
      -
      +\endcode -

      -Detailed implementation code can be found in Appendix A. The +Detailed implementation code can be found in Appendix \ref subsec_tsafe_app_A. The implementation changes are made in H5TS.c. -

      - -

      4.2 First thread initialization

      -

      +\subsection subsec_tsafe_impl_first First thread initialization Because the mutex lock associated with a recursive lock cannot be statically initialized, a mechanism is required to initialize the recursive lock associated with H5_g so that it can be used for the first time. -

      -

      The pthreads library allows this through the pthread_once call which as -described in section 3.3 allows only the first thread accessing the +described in section \ref subsec_tsafe_global_init allows only the first thread accessing the library in an application to initialize H5_g. -

      -

      In addition to initializing H5_g, it also initializes the -key (see section 3.4) for use with per-thread error stacks (see section -4.3). -

      +key (see section \ref subsec_tsafe_global_key) for use with per-thread error stacks (see section +\ref subsec_tsafe_impl_err). -

      The first thread initialization mechanism is implemented as the function call H5_first_thread_init() in H5TS.c. This is described in appendix B. -

      -

      4.3 Per-thread error stack management

      - -

      +\subsection subsec_tsafe_impl_err Per-thread error stack management Pthreads allows individual threads to access dynamic and persistent per-thread data through the use of keys. Each key is associated with a table that maps threads to data items. Keys can be initialized by -pthread_key_create() in pthreads (see sections 3.4 and 4.2). +pthread_key_create() in pthreads (see sections \ref subsec_tsafe_global_key and \ref subsec_tsafe_impl_first). Per-thread data items are accessed using a key through the pthread_getspecific() and pthread_setspecific() calls to read and write to the association table respectively. -

      -

      Per-thread error stacks are accessed through the key H5_errstk_key_g which is initialized by the first thread -initialization call (see section 4.2). -

      +initialization call (see section \ref subsec_tsafe_impl_first). -

      In the non-threadsafe version of the library, there is a global stack variable H5E_stack_g[1] which is no longer defined in the threadsafe version. At the same time, the macro call to gain access to the error stack H5E_get_my_stack is changed from: -

      - -
      -
      +\code
           #define H5E_get_my_stack() (H5E_stack_g+0)
      -  
      -
      +\endcode -

      to: -

      - -
      -
      +\code
           #define H5E_get_my_stack() H5E_get_stack()
      -  
      -
      +\endcode -

      where H5E_get_stack() is a surrogate function that does the following operations: -

      -
        -
      1. if a thread is attempting to get an error stack for the first - time, the error stack is dynamically allocated for the thread and - associated with H5_errstk_key_g using - pthread_setspecific(). The way we detect if it is the - first time is through pthread_getspecific() which - returns NULL if no previous value is associated with - the thread using the key.
      2. - -
      3. if pthread_getspecific() returns a non-null value, - then that is the pointer to the error stack associated with the - thread and the stack can be used as usual.
      4. +
      5. if a thread is attempting to get an error stack for the first +time, the error stack is dynamically allocated for the thread and +associated with H5_errstk_key_g using +pthread_setspecific(). The way we detect if it is the +first time is through pthread_getspecific() which +returns NULL if no previous value is associated with +the thread using the key.
      6. + +
      7. if pthread_getspecific() returns a non-null value, +then that is the pointer to the error stack associated with the +thread and the stack can be used as usual.
      -

      A final change to the error reporting routines is as follows; the current implementation reports errors to always be detected at thread 0. In the threadsafe implementation, this is changed to report the number returned by a call to pthread_self(). -

      -

      The change in code (reflected in H5Eprint of file H5E.c) is as follows: -

      - -
      -
      +\code
           #ifdef H5_HAVE_THREADSAFE
      -      fprintf (stream, "HDF5-DIAG: Error detected in thread %d."
      -               ,pthread_self());
      +      fprintf (stream, "HDF5-DIAG: Error detected in thread %d." ,pthread_self());
           #else
             fprintf (stream, "HDF5-DIAG: Error detected in thread 0.");
           #endif
      -  
      -
      +\endcode -

      -Code for H5E_get_stack() can be found in Appendix C. All the +Code for H5E_get_stack() can be found in Appendix \ref subsec_tsafe_app_C. All the above changes were made in H5E.c. -

      - -

      4.4 Thread Cancellation safety

      -

      +\subsection subsec_tsafe_impl_cancel Thread Cancellation safety To prevent thread cancellations from killing a thread while it is in the library, we maintain per-thread information about the cancellability status of the thread before it entered the library so that we can restore that same status when the thread leaves the library. -

      -

      By enter and leave the library, we mean the points when a thread makes an API call from a user application and the time that API call returns. Other API or callback function calls made from within that API call are considered within the library. -

      -

      Because other API calls may be made from within the first API call, we need to maintain a counter to determine which was the first and correspondingly the last return. -

      -

      When a thread makes an API call, the macro H5_API_SET_CANCEL calls the worker function H5_cancel_count_inc() which does the following: -

      -
        -
      1. if this is the first time the thread has entered the library, - a new cancellability structure needs to be assigned to it.
      2. -
      3. if the thread is already within the library when the API call is - made, then cancel_count is simply incremented. Otherwise, we set - the cancellability state to PTHREAD_CANCEL_DISABLE - while storing the previous state into the cancellability structure. - cancel_count is also incremented in this case.
      4. +
      5. if this is the first time the thread has entered the library, +a new cancellability structure needs to be assigned to it.
      6. +
      7. if the thread is already within the library when the API call is +made, then cancel_count is simply incremented. Otherwise, we set +the cancellability state to PTHREAD_CANCEL_DISABLE +while storing the previous state into the cancellability structure. +cancel_count is also incremented in this case.
      -

      When a thread leaves an API call, the macro H5_API_UNSET_CANCEL calls the worker function H5_cancel_count_dec() which does the following: -

      -
        -
      1. if cancel_count is greater than 1, indicating that the - thread is not yet about to leave the library, then - cancel_count is simply decremented.
      2. -
      3. otherwise, we reset the cancellability state back to its original - state before it entered the library and decrement the count (back - to zero).
      4. +
      5. if cancel_count is greater than 1, indicating that the +thread is not yet about to leave the library, then +cancel_count is simply decremented.
      6. +
      7. otherwise, we reset the cancellability state back to its original +state before it entered the library and decrement the count (back +to zero).
      -

      H5_cancel_count_inc and H5_cancel_count_dec are -described in Appendix D and may be found in H5TS.c. -

      +described in Appendix \ref subsec_tsafe_app_D and may be found in H5TS.c. -

      5. Test programs

      - -

      +\section sec_tsafe_test Test programs Except where stated, all tests involve 16 simultaneous threads that make use of HDF5 API calls without any explicit synchronization typically required in a non-threadsafe environment. -

      -

      5.1 Data set create and write

      - -

      +\subsection subsec_tsafe_test_create Data set create and write The test program sets up 16 threads to simultaneously create 16 different datasets named from zero to fifteen for a single file and then writing an integer value into that dataset equal to the dataset's named value. -

      -

      The main thread would join with all 16 threads and attempt to match the resulting HDF5 file with expected results - that each dataset contains the correct value (0 for zero, 1 for one etc ...) and all datasets were correctly created. -

      -

      The test is implemented in the file ttsafe_dcreate.c. -

      - -

      5.2 Test on error stack

      -

      +\subsection subsec_tsafe_test_err Test on error stack The error stack test is one in which 16 threads simultaneously try to create datasets with the same name. The result, when properly serialized, should be equivalent to 16 attempts to create the dataset with the same name. -

      -

      The error stack implementation runs correctly if it reports 15 instances of the dataset name conflict error and finally generates a correct HDF5 containing that single dataset. Each thread should report its own stack of errors with a thread number associated with it. -

      -

      The test is implemented in the file ttsafe_error.c. -

      - -

      5.3 Test on cancellation safety

      -

      +\subsection subsec_tsafe_test_cancel Test on cancellation safety The main idea in thread cancellation safety is as follows; a child thread is spawned to create and write to a dataset. Following that, it makes a H5Diterate call on that dataset which activates a callback function. -

      -

      A deliberate barrier is invoked at the callback function which waits for both the main and child thread to arrive at that point. After that happens, the main thread proceeds to make a thread cancel call on the child thread while the latter sleeps for 3 seconds before proceeding to write a new value to the dataset. -

      -

      After the iterate call, the child thread logically proceeds to wait another 3 seconds before writing another newer value to the dataset. -

      -

      The test is correct if the main thread manages to read the second value at the end of the test. This means that cancellation did not take place until the end of the iteration call despite of the 3 second wait within the iteration callback and the extra dataset write operation. Furthermore, the cancellation should occur before the child can proceed to write the last value into the dataset. -

      -

      5.4 Test on attribute creation

      - -

      +\subsection subsec_tsafe_test_attr Test on attribute creation A main thread makes 16 threaded calls to H5Acreate with a generated name for each attribute. Sixteen attributes should be created for the single dataset in random (chronological) order and receive values depending on its generated attribute name (e.g. attrib010 would receive the value 10). -

      -

      After joining with all child threads, the main thread proceeds to read each attribute by generated name to see if the value tallies. Failure is detected if the attribute name does not exist (meaning they were never created) or if the wrong values were read back. -

      -

      A. Recursive Lock implementation code

      +\section sec_tsafe_app Appendix -
      -
      +\subsection subsec_tsafe_app_A Recursive Lock implementation code
      +\code
         void H5_mutex_init(H5_mutex_t *H5_mutex)
         {
      -    H5_mutex->owner_thread = NULL;
      -    pthread_mutex_init(&H5_mutex->atomic_lock, NULL);
      -    pthread_cond_init(&H5_mutex->cond_var, NULL);
      +     H5_mutex->owner_thread = NULL;
      +     pthread_mutex_init(&H5_mutex->atomic_lock, NULL);
      +     pthread_cond_init(&H5_mutex->cond_var, NULL);
           H5_mutex->lock_count = 0;
         }
       
         void H5_mutex_lock(H5_mutex_t *H5_mutex)
         {
      -    pthread_mutex_lock(&H5_mutex->atomic_lock);
      -
      -    if (pthread_equal(pthread_self(), H5_mutex->owner_thread)) {
      -    	/* already owned by self - increment count */
      -    	H5_mutex->lock_count++;
      -    } else {
      -    	if (H5_mutex->owner_thread == NULL) {
      -    		/* no one else has locked it - set owner and grab lock */
      -    		H5_mutex->owner_thread = pthread_self();
      -    		H5_mutex->lock_count = 1;
      -    	} else {
      -    		/* if already locked by someone else */
      -    		while (1) {
      -    			pthread_cond_wait(&H5_mutex->cond_var, &H5_mutex->atomic_lock);
      -
      -    			if (H5_mutex->owner_thread == NULL) {
      -    				H5_mutex->owner_thread = pthread_self();
      -    				H5_mutex->lock_count = 1;
      -    				break;
      -    			} /* else do nothing and loop back to wait on condition*/
      -    		}
      -    	}
      -    }
      -
      -    pthread_mutex_unlock(&H5_mutex->atomic_lock);
      +     pthread_mutex_lock(&H5_mutex->atomic_lock);
      +
      +     if (pthread_equal(pthread_self(), H5_mutex->owner_thread)) {
      +        // already owned by self - increment count
      +        H5_mutex->lock_count++;
      +     } 
      +     else {
      +        if (H5_mutex->owner_thread == NULL) {
      +            // no one else has locked it - set owner and grab lock
      +            H5_mutex->owner_thread = pthread_self();
      +            H5_mutex->lock_count = 1;
      +        } 
      +        else {
      +            /* if already locked by someone else */
      +            while (1) {
      +                pthread_cond_wait(&H5_mutex->cond_var, &H5_mutex->atomic_lock);
      +
      +                if (H5_mutex->owner_thread == NULL) {
      +                    H5_mutex->owner_thread = pthread_self();
      +                    H5_mutex->lock_count = 1;
      +                    break;
      +                } // else do nothing and loop back to wait on condition
      +            }
      +        }
      +     }
      +
      +     pthread_mutex_unlock(&H5_mutex->atomic_lock);
         }
       
         void H5_mutex_unlock(H5_mutex_t *H5_mutex)
         {
      -    pthread_mutex_lock(&H5_mutex->atomic_lock);
      -    H5_mutex->lock_count--;
      -
      -    if (H5_mutex->lock_count == 0) {
      -    	H5_mutex->owner_thread = NULL;
      -    	pthread_cond_signal(&H5_mutex->cond_var);
      -    }
      -    pthread_mutex_unlock(&H5_mutex->atomic_lock);
      +     pthread_mutex_lock(&H5_mutex->atomic_lock);
      +     H5_mutex->lock_count--;
      +
      +     if (H5_mutex->lock_count == 0) {
      +        H5_mutex->owner_thread = NULL;
      +        pthread_cond_signal(&H5_mutex->cond_var);
      +     }
      +     pthread_mutex_unlock(&H5_mutex->atomic_lock);
         }
      -  
      -
      - -

      B. First thread initialization

      +\endcode -
      -
      +\subsection subsec_tsafe_app_B First thread initialization
      +\code
         void H5_first_thread_init(void)
         {
      -    /* initialize global API mutex lock                      */
      +    // initialize global API mutex lock
           H5_g.H5_libinit_g = FALSE;
           H5_g.init_lock.owner_thread = NULL;
           pthread_mutex_init(&H5_g.init_lock.atomic_lock, NULL);
           pthread_cond_init(&H5_g.init_lock.cond_var, NULL);
           H5_g.init_lock.lock_count = 0;
       
      -    /* initialize key for thread-specific error stacks       */
      +    // initialize key for thread-specific error stacks
           pthread_key_create(&H5_errstk_key_g, NULL);
       
      -    /* initialize key for thread cancellability mechanism    */
      +    // initialize key for thread cancellability mechanism
           pthread_key_create(&H5_cancel_key_g, NULL);
         }
      -  
      -
      - +\endcode -

      C. Per-thread error stack acquisition

      - -
      -
      +\subsection subsec_tsafe_app_C Per-thread error stack acquisition
      +\code
         H5E_t *H5E_get_stack(void)
         {
           H5E_t *estack;
       
           if (estack = pthread_getspecific(H5_errstk_key_g)) {
      -    	return estack;
      -    } else {
      -    	/* no associated value with current thread - create one */
      -    	estack = (H5E_t *)malloc(sizeof(H5E_t));
      -    	pthread_setspecific(H5_errstk_key_g, (void *)estack);
      -    	return estack;
      +        return estack;
      +    } 
      +    else {
      +        // no associated value with current thread - create one
      +        estack = (H5E_t *)malloc(sizeof(H5E_t));
      +        pthread_setspecific(H5_errstk_key_g, (void *)estack);
      +        return estack;
           }
         }
      -  
      -
      +\endcode -

      D. Thread cancellation mechanisms

      - -
      -
      +\subsection subsec_tsafe_app_D Thread cancellation mechanisms
      +\code
         void H5_cancel_count_inc(void)
         {
           H5_cancel_t *cancel_counter;
       
           if (cancel_counter = pthread_getspecific(H5_cancel_key_g)) {
      -      /* do nothing here */
      -    } else {
      -      /*
      -       * first time thread calls library - create new counter and
      -       * associate with key
      -       */
      +      // do nothing here
      +    } 
      +    else {
      +      // first time thread calls library - create new counter and
      +      // associate with key
             cancel_counter = (H5_cancel_t *)malloc(sizeof(H5_cancel_t));
             cancel_counter->cancel_count = 0;
             pthread_setspecific(H5_cancel_key_g, (void *)cancel_counter);
      @@ -650,8 +466,7 @@ 

      D. Thread cancellation mechanisms

      if (cancel_counter->cancel_count == 0) { /* thread entering library */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, - &(cancel_counter->previous_state)); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &(cancel_counter->previous_state)); } cancel_counter->cancel_count++; @@ -666,22 +481,19 @@

      D. Thread cancellation mechanisms

      cancel_counter->cancel_count--; } -
      -
      +\endcode -

      E. Macro expansion codes

      +\subsection subsec_tsafe_app_E Macro expansion codes -

      E.1 FUNC_ENTER

      - -
      -
      -  /* Initialize the library */                                \
      +\subsubsection subsubsec_tsafe_app_E1 FUNC_ENTER
      +\code
      +  // Initialize the library                                   \
         H5_FIRST_THREAD_INIT                                        \
         H5_API_UNSET_CANCEL                                         \
         H5_API_LOCK_BEGIN                                           \
           if (!(H5_INIT_GLOBAL)) {                                  \
             H5_INIT_GLOBAL = TRUE;                                  \
      -        if (H5_init_library() < 0) {                          \
      +        if (H5_init_library() < 0) {                       \
                 HRETURN_ERROR (H5E_FUNC, H5E_CANTINIT, err,         \
                               "library initialization failed");     \
               }                                                     \
      @@ -690,56 +502,37 @@ 

      E.1 FUNC_ENTER

      : : : -
      -
      +\endcode -

      E.2 H5_FIRST_THREAD_INIT

      - -
      -
      -  /* Macro for first thread initialization */
      +\subsubsection subsubsec_tsafe_app_E2 H5_FIRST_THREAD_INIT
      +\code
      +  // Macro for first thread initialization
         #define H5_FIRST_THREAD_INIT                                \
           pthread_once(&H5_first_init_g, H5_first_thread_init);
      -  
      -
      - - -

      E.3 H5_API_UNSET_CANCEL

      +\endcode -
      -
      +\subsubsection subsubsec_tsafe_app_E3 H5_API_UNSET_CANCEL
      +\code
         #define H5_API_UNSET_CANCEL                                 \
           if (H5_IS_API(__func__)) {                                \
             H5_cancel_count_inc();                                  \
           }
      -  
      -
      - - -

      E.4 H5_API_LOCK_BEGIN

      +\endcode -
      -
      +\subsubsection subsubsec_tsafe_app_E4 H5_API_LOCK_BEGIN
      +\code
         #define H5_API_LOCK_BEGIN                                   \
            if (H5_IS_API(__func__)) {                               \
              H5_mutex_lock(&H5_g.init_lock);
      -  
      -
      - +\endcode -

      E.5 H5_API_LOCK_END

      - -
      -
      +\subsubsection subsubsec_tsafe_app_E5 H5_API_LOCK_END
      +\code
         #define H5_API_LOCK_END }
      -  
      -
      - - -

      E.6 HRETURN and HRETURN_ERROR

      +\endcode -
      -
      +\subsubsection subsubsec_tsafe_app_E6 HRETURN and HRETURN_ERROR
      +\code
                   :
                   :
           H5_API_UNLOCK_BEGIN                                       \
      @@ -747,41 +540,27 @@ 

      E.6 HRETURN and HRETURN_ERROR

      H5_API_SET_CANCEL \ return ret_val; \ } -
      -
      - -

      E.7 H5_API_UNLOCK_BEGIN

      +\endcode -
      -
      +\subsubsection subsubsec_tsafe_app_E7 H5_API_UNLOCK_BEGIN
      +\code
         #define H5_API_UNLOCK_BEGIN                                 \
           if (H5_IS_API(__func__)) {                                \
             H5_mutex_unlock(&H5_g.init_lock);
      -  
      -
      - -

      E.8 H5_API_UNLOCK_END

      +\endcode -
      -
      +\subsubsection subsubsec_tsafe_app_E8 H5_API_UNLOCK_END
      +\code
         #define H5_API_UNLOCK_END }
         
      -
      +\endcode - -

      E.9 H5_API_SET_CANCEL

      - -
      -
      +\subsubsection subsubsec_tsafe_app_E9 H5_API_SET_CANCEL
      +\code
         #define H5_API_SET_CANCEL                                   \
           if (H5_IS_API(__func__)) {                                \
             H5_cancel_count_dec();                                  \
           }
      -  
      -
      - -

      By Chee Wai Lee

      -

      By Bill Wendling

      +\endcode - - + */ diff --git a/doxygen/dox/ViewTools.dox b/doxygen/dox/ViewTools.dox index 9ae42fe9f40..43686751bfb 100644 --- a/doxygen/dox/ViewTools.dox +++ b/doxygen/dox/ViewTools.dox @@ -986,7 +986,7 @@ See this section for more info \subsubsection subsubsecViewToolsViewDtypes_newref New References References were reworked in HDF5 1.12.0. The new reference datatype is #H5T_STD_REF. The old reference datatypes are deprecated. -@see sec_reference. +see @ref sec_reference. \subsubsection subsubsecViewToolsViewDtypes_objref Object Reference An Object Reference is a reference to an entire object (attribute, dataset, group, or named datatype). diff --git a/doxygen/dox/high_level/extension.dox b/doxygen/dox/high_level/extension.dox index 20a099a0e0b..fc0da48ee83 100644 --- a/doxygen/dox/high_level/extension.dox +++ b/doxygen/dox/high_level/extension.dox @@ -7,23 +7,23 @@ * for working with region references, hyperslab selections, and bit-fields. * These functions were created as part of a project supporting * NPP/NPOESS Data Production and Exploitation ( - * - * project, + * + * project, * software ). * While they were written to facilitate access to NPP, NPOESS, and JPSS * data in the HDF5 format, these functions may be useful to anyone working * with region references, hyperslab selections, or bit-fields. * * Note that these functions are not part of the standard HDF5 distribution; - * the + * the * software * must be separately downloaded and installed. * * A comprehensive guide to this library, - * + * * User Guide to the HDF5 High-level Library for Handling Region References and Hyperslab Selections * is available at - * https://support.hdfgroup.org/projects/jpss/documentation/HL/UG/NPOESS_HL-UG.pdf. + * https://\PRJURL/jpss/documentation/HL/UG/NPOESS_HL-UG.pdf. * * - \ref H5LRcopy_reference * \n Copies data from the specified dataset to a new location and creates a reference to it. @@ -297,7 +297,7 @@ H5_HLRDLL herr_t H5LRcopy_region(hid_t obj_id, * - #H5_ITER_NATIVE Fastest available order * * For more detailed information on these two parameters, - * @see H5Lvisit(). + * see H5Lvisit(). * * \p ref_type specifies the type of the reference to be used. * Valid values include the following: diff --git a/doxygen/examples/FileFormat.html b/doxygen/examples/FileFormat.html index e5a796e4f7b..40d21138eb2 100644 --- a/doxygen/examples/FileFormat.html +++ b/doxygen/examples/FileFormat.html @@ -1,5 +1,4 @@ - HDF5 File Format Discussion diff --git a/doxygen/examples/Filters.html b/doxygen/examples/Filters.html deleted file mode 100644 index 27207d5d962..00000000000 --- a/doxygen/examples/Filters.html +++ /dev/null @@ -1,450 +0,0 @@ - - - Filters -

      Filters in HDF5

      - - Note: Transient pipelines described in this document have not - been implemented. - -

      Introduction

      - -

      HDF5 allows chunked data to pass through user-defined filters - on the way to or from disk. The filters operate on chunks of an - H5D_CHUNKED dataset can be arranged in a pipeline - so output of one filter becomes the input of the next filter. - -

      Each filter has a two-byte identification number (type - H5Z_filter_t) allocated by The HDF Group and can also be - passed application-defined integer resources to control its - behavior. Each filter also has an optional ASCII comment - string. - -

      -
    @@ -68,7 +68,7 @@ A brief introduction to Parallel HDF5. If you are new to HDF5 please see the @re
    -HDF5-1.10 New Features +New Features since HDF5-1.10 \li \ref VDS diff --git a/doxygen/dox/IntroHDF5.dox b/doxygen/dox/IntroHDF5.dox index 9ef55d3a573..6f3938ed8b2 100644 --- a/doxygen/dox/IntroHDF5.dox +++ b/doxygen/dox/IntroHDF5.dox @@ -262,7 +262,7 @@ FORTRAN routines are similar; they begin with “h5*” and end with “_f”.
  • Java routines are similar; the routine names begin with “H5*” and are prefixed with “H5.” as the class. Constants are in the HDF5Constants class and are prefixed with "HDF5Constants.". The function arguments -are usually similar, @see @ref HDF5LIB +are usually similar, see @ref HDF5LIB
  • For example: @@ -616,8 +616,8 @@ on the HDF-EOS Tools and Information Center pag \section secHDF5Examples Examples \li \ref LBExamples \li \ref ExAPI -\li Examples in the Source Code -\li Other Examples +\li Examples in the Source Code +\li Other Examples \section secHDF5ExamplesCompile How To Compile For information on compiling in C, C++ and Fortran, see: \ref LBCompiling diff --git a/doxygen/dox/LearnBasics.dox b/doxygen/dox/LearnBasics.dox index ed83b367b6b..4db515c1a57 100644 --- a/doxygen/dox/LearnBasics.dox +++ b/doxygen/dox/LearnBasics.dox @@ -59,7 +59,7 @@ These examples (C, C++, Fortran, Java, Python) are provided in the HDF5 source c
    Create a file C Fortran C++ Java Python +C Fortran C++ Java Python
    Create a group C Fortran C++ Java Python +C Fortran C++ Java Python
    Create datasets in a group C Fortran C++ Java Python +C Fortran C++ Java Python
    Create a chunked and compressed dataset C Fortran C++ Java Python +C Fortran C++ Java Python
    - - - - - - - - - - - - - - - - - - -
    Values for H5Z_filter_tDescription
    0-255These values are reserved for filters predefined and - registered by the HDF5 library and of use to the general - public. They are described in a separate section - below.
    256-511Filter numbers in this range are used for testing only - and can be used temporarily by any organization. No - attempt is made to resolve numbering conflicts since all - definitions are by nature temporary.
    512-65535Reserved for future assignment. Please contact the - HDF5 development team - to reserve a value or range of values for - use by your filters.
    - -

    Defining and Querying the Filter Pipeline

    - -

    Two types of filters can be applied to raw data I/O: permanent - filters and transient filters. The permanent filter pipeline is - defined when the dataset is created while the transient pipeline - is defined for each I/O operation. During an - H5Dwrite() the transient filters are applied first - in the order defined and then the permanent filters are applied - in the order defined. For an H5Dread() the - opposite order is used: permanent filters in reverse order, then - transient filters in reverse order. An H5Dread() - must result in the same amount of data for a chunk as the - original H5Dwrite(). - -

    The permanent filter pipeline is defined by calling - H5Pset_filter() for a dataset creation property - list while the transient filter pipeline is defined by calling - that function for a dataset transfer property list. - -

    -
    herr_t H5Pset_filter (hid_t plist, - H5Z_filter_t filter, unsigned int flags, - size_t cd_nelmts, const unsigned int - cd_values[]) -
    This function adds the specified filter and - corresponding properties to the end of the transient or - permanent output filter pipeline (depending on whether - plist is a dataset creation or dataset transfer - property list). The flags argument specifies certain - general properties of the filter and is documented below. The - cd_values is an array of cd_nelmts integers - which are auxiliary data for the filter. The integer values - will be stored in the dataset object header as part of the - filter information. -
    int H5Pget_nfilters (hid_t plist) -
    This function returns the number of filters defined in the - permanent or transient filter pipeline depending on whether - plist is a dataset creation or dataset transfer - property list. In each pipeline the filters are numbered from - 0 through N-1 where N is the value returned - by this function. During output to the file the filters of a - pipeline are applied in increasing order (the inverse is true - for input). Zero is returned if there are no filters in the - pipeline and a negative value is returned for errors. -
    H5Z_filter_t H5Pget_filter (hid_t plist, - int filter_number, unsigned int *flags, - size_t *cd_nelmts, unsigned int - *cd_values, size_t namelen, char name[]) -
    This is the query counterpart of - H5Pset_filter() and returns information about a - particular filter number in a permanent or transient pipeline - depending on whether plist is a dataset creation or - dataset transfer property list. On input, cd_nelmts - indicates the number of entries in the cd_values - array allocated by the caller while on exit it contains the - number of values defined by the filter. The - filter_number should be a value between zero and - N-1 as described for H5Pget_nfilters() - and the function will return failure (a negative value) if the - filter number is out of range. If name is a pointer - to an array of at least namelen bytes then the filter - name will be copied into that array. The name will be null - terminated if the namelen is large enough. The - filter name returned will be the name appearing in the file or - else the name registered for the filter or else an empty string. -
    - -

    The flags argument to the functions above is a bit vector of - the following fields: - -

    - - - - - - - - - - -
    Values for flagsDescription
    H5Z_FLAG_OPTIONALIf this bit is set then the filter is optional. If - the filter fails (see below) during an - H5Dwrite() operation then the filter is - just excluded from the pipeline for the chunk for which - it failed; the filter will not participate in the - pipeline during an H5Dread() of the chunk. - This is commonly used for compression filters: if the - compression result would be larger than the input then - the compression filter returns failure and the - uncompressed data is stored in the file. If this bit is - clear and a filter fails then the - H5Dwrite() or H5Dread() also - fails.
    - -

    Defining Filters

    - -

    Each filter is bidirectional, handling both input and output to - the file, and a flag is passed to the filter to indicate the - direction. In either case the filter reads a chunk of data from - a buffer, usually performs some sort of transformation on the - data, places the result in the same or new buffer, and returns - the buffer pointer and size to the caller. If something goes - wrong the filter should return zero to indicate a failure. - -

    During output, a filter that fails or isn't defined and is - marked as optional is silently excluded from the pipeline and - will not be used when reading that chunk of data. A required - filter that fails or isn't defined causes the entire output - operation to fail. During input, any filter that has not been - excluded from the pipeline during output and fails or is not - defined will cause the entire input operation to fail. - -

    Filters are defined in two phases. The first phase is to - define a function to act as the filter and link the function - into the application. The second phase is to register the - function, associating the function with an - H5Z_filter_t identification number and a comment. - -

    -
    typedef size_t (*H5Z_func_t)(unsigned int - flags, size_t cd_nelmts, const unsigned int - cd_values[], size_t nbytes, size_t - *buf_size, void **buf) -
    The flags, cd_nelmts, and - cd_values are the same as for the - H5Pset_filter() function with the additional flag - H5Z_FLAG_REVERSE which is set when the filter is - called as part of the input pipeline. The input buffer is - pointed to by *buf and has a total size of - *buf_size bytes but only nbytes are valid - data. The filter should perform the transformation in place if - possible and return the number of valid bytes or zero for - failure. If the transformation cannot be done in place then - the filter should allocate a new buffer with - malloc() and assign it to *buf, - assigning the allocated size of that buffer to - *buf_size. The old buffer should be freed - by calling free(). - -

    -
    herr_t H5Zregister (H5Z_filter_t filter_id, - const char *comment, H5Z_func_t - filter) -
    The filter function is associated with a filter - number and a short ASCII comment which will be stored in the - hdf5 file if the filter is used as part of a permanent - pipeline during dataset creation. -
    - -

    Predefined Filters

    - -

    If zlib version 1.1.2 or later was found - during configuration then the library will define a filter whose - H5Z_filter_t number is - H5Z_FILTER_DEFLATE. Since this compression method - has the potential for generating compressed data which is larger - than the original, the H5Z_FLAG_OPTIONAL flag - should be turned on so such cases can be handled gracefully by - storing the original data instead of the compressed data. The - cd_nvalues should be one with cd_value[0] - being a compression aggression level between zero and nine, - inclusive (zero is the fastest compression while nine results in - the best compression ratio). - -

    A convenience function for adding the - H5Z_FILTER_DEFLATE filter to a pipeline is: - -

    -
    herr_t H5Pset_deflate (hid_t plist, unsigned - aggression) -
    The deflate compression method is added to the end of the - permanent or transient filter pipeline depending on whether - plist is a dataset creation or dataset transfer - property list. The aggression is a number between - zero and nine (inclusive) to indicate the tradeoff between - speed and compression ratio (zero is fastest, nine is best - ratio). -
    - -

    Even if the zlib isn't detected during - configuration the application can define - H5Z_FILTER_DEFLATE as a permanent filter. If the - filter is marked as optional (as with - H5Pset_deflate()) then it will always fail and be - automatically removed from the pipeline. Applications that read - data will fail only if the data is actually compressed; they - won't fail if H5Z_FILTER_DEFLATE was part of the - permanent output pipeline but was automatically excluded because - it didn't exist when the data was written. - -

    zlib can be acquired from - - https://zlib.net. - -

    Example

    - -

    This example shows how to define and register a simple filter - that adds a checksum capability to the data stream. - -

    The function that acts as the filter always returns zero - (failure) if the md5() function was not detected at - configuration time (left as an exercise for the reader). - Otherwise the function is broken down to an input and output - half. The output half calculates a checksum, increases the size - of the output buffer if necessary, and appends the checksum to - the end of the buffer. The input half calculates the checksum - on the first part of the buffer and compares it to the checksum - already stored at the end of the buffer. If the two differ then - zero (failure) is returned, otherwise the buffer size is reduced - to exclude the checksum. - -

    - - - - -
    -

    
    -                  size_t
    -                  md5_filter(unsigned int flags, size_t cd_nelmts,
    -                  const unsigned int cd_values[], size_t nbytes,
    -                  size_t *buf_size, void **buf)
    -                  {
    -                  #ifdef HAVE_MD5
    -                  unsigned char       cksum[16];
    -
    -                  if (flags & H5Z_REVERSE) {
    -                  /* Input */
    -                  assert(nbytes>=16);
    -                  md5(nbytes-16, *buf, cksum);
    -
    -                  /* Compare */
    -                  if (memcmp(cksum, (char*)(*buf)+nbytes-16, 16)) {
    -                  return 0; /*fail*/
    -                  }
    -
    -                  /* Strip off checksum */
    -                  return nbytes-16;
    -
    -                  } else {
    -                  /* Output */
    -                  md5(nbytes, *buf, cksum);
    -
    -                  /* Increase buffer size if necessary */
    -                  if (nbytes+16>*buf_size) {
    -                  *buf_size = nbytes + 16;
    -                  *buf = realloc(*buf, *buf_size);
    -                  }
    -
    -                  /* Append checksum */
    -                  memcpy((char*)(*buf)+nbytes, cksum, 16);
    -                  return nbytes+16;
    -                  }
    -                  #else
    -                  return 0; /*fail*/
    -                  #endif
    -                  }
    -	          
    -
    - -

    Once the filter function is defined it must be registered so - the HDF5 library knows about it. Since we're testing this - filter we choose one of the H5Z_filter_t numbers - from the reserved range. We'll randomly choose 305. - -

    -

    - - - - -
    -

    
    -                  #define FILTER_MD5 305
    -                  herr_t status = H5Zregister(FILTER_MD5, "md5 checksum", md5_filter);
    -	          
    -
    - -

    Now we can use the filter in a pipeline. We could have added - the filter to the pipeline before defining or registering the - filter as long as the filter was defined and registered by time - we tried to use it (if the filter is marked as optional then we - could have used it without defining it and the library would - have automatically removed it from the pipeline for each chunk - written before the filter was defined and registered). - -

    -

    - - - - -
    -

    
    -                  hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE);
    -                  hsize_t chunk_size[3] = {10,10,10};
    -                  H5Pset_chunk(dcpl, 3, chunk_size);
    -                  H5Pset_filter(dcpl, FILTER_MD5, 0, 0, NULL);
    -                  hid_t dset = H5Dcreate(file, "dset", H5T_NATIVE_DOUBLE, space, dcpl);
    -	          
    -
    - -

    6. Filter Diagnostics

    - -

    If the library is compiled with debugging turned on for the H5Z - layer (usually as a result of configure - --enable-debug=z) then filter statistics are printed when - the application exits normally or the library is closed. The - statistics are written to the standard error stream and include - two lines for each filter that was used: one for input and one - for output. The following fields are displayed: - -

    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Field NameDescription
    MethodThis is the name of the method as defined with - H5Zregister() with the characters - "< or ">" prepended to indicate - input or output.
    TotalThe total number of bytes processed by the filter - including errors. This is the maximum of the - nbytes argument or the return value. -
    ErrorsThis field shows the number of bytes of the Total - column which can be attributed to errors.
    User, System, ElapsedThese are the amount of user time, system time, and - elapsed time in seconds spent in the filter function. - Elapsed time is sensitive to system load. These times - may be zero on operating systems that don't support the - required operations.
    BandwidthThis is the filter bandwidth which is the total - number of bytes processed divided by elapsed time. - Since elapsed time is subject to system load the - bandwidth numbers cannot always be trusted. - Furthermore, the bandwidth includes bytes attributed to - errors which may significantly taint the value if the - function is able to detect errors without much - expense.
    - -

    -

    - - - - - -
    - Example: Filter Statistics -
    -

    H5Z: filter statistics accumulated ov=
    -                  er life of library:
    -                  Method     Total  Errors  User  System  Elapsed Bandwidth
    -                  ------     -----  ------  ----  ------  ------- ---------
    -                  >deflate  160000   40000  0.62    0.74     1.33 117.5 kBs
    -                  <deflate  120000       0  0.11    0.00     0.12 1.000 MBs
    -	          
    -
    - -
    - - -

    Footnote 1: Dataset chunks can be compressed - through the use of filters. Developers should be aware that - reading and rewriting compressed chunked data can result in holes - in an HDF5 file. In time, enough such holes can increase the - file size enough to impair application or library performance - when working with that file. See - - Freespace Management - in the chapter - - Performance Analysis and Issues.

    - diff --git a/doxygen/examples/H5.format.1.0.html b/doxygen/examples/H5.format.1.0.html index 32e377d4323..00da963c48e 100644 --- a/doxygen/examples/H5.format.1.0.html +++ b/doxygen/examples/H5.format.1.0.html @@ -3441,8 +3441,8 @@

    Name: Data Storage - Filter Pipeline

    library. Values 256 through 511 have been set aside for use when developing/testing new filters. The remaining values are allocated to specific filters by contacting the - HDF5 Development - Team. + HDF5 development team. + diff --git a/doxygen/examples/H5.format.1.1.html b/doxygen/examples/H5.format.1.1.html index 707bdc7c281..418afd5ab88 100644 --- a/doxygen/examples/H5.format.1.1.html +++ b/doxygen/examples/H5.format.1.1.html @@ -5558,9 +5558,9 @@

    Name: Data Storage - Filter Pipeline

    1If you are reading an earlier version of this document, this link may have changed. If the link does not work, use the latest version of this document - on The HDF Group’s website, - - https://support.hdfgroup.org/HDF5/doc/H5.format.html; + on The HDF Group’s website, + + H5.format.html; the link there will always be correct. (Return)

    diff --git a/doxygen/examples/H5DS_Spec.pdf b/doxygen/examples/H5DS_Spec.pdf new file mode 100644 index 0000000000000000000000000000000000000000..813f4ded3e12700cd8394157247151d33e5df959 GIT binary patch literal 746769 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
      M0N;QE| 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 z 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

      ~$k>Wwmc8t;x0&uWm3qb@g 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℞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 literal 0 HcmV?d00001 diff --git a/doxygen/examples/IOFlow.html b/doxygen/examples/IOFlow.html index e890edbb766..b33196d502a 100644 --- a/doxygen/examples/IOFlow.html +++ b/doxygen/examples/IOFlow.html @@ -1,5 +1,4 @@ - HDF5 Raw I/O Flow Notes diff --git a/doxygen/examples/LibraryReleaseVersionNumbers.html b/doxygen/examples/LibraryReleaseVersionNumbers.html index 57b211cd61b..dedbece0c11 100644 --- a/doxygen/examples/LibraryReleaseVersionNumbers.html +++ b/doxygen/examples/LibraryReleaseVersionNumbers.html @@ -241,7 +241,7 @@

      Version Support from the Library<

      For more information on these and other function calls and macros, - see the HDF5 Reference Manual.

      + see the HDF5 Reference Manual.

      Use Cases

      diff --git a/doxygen/examples/intro_SWMR.html b/doxygen/examples/intro_SWMR.html deleted file mode 100644 index b1adb62bdb5..00000000000 --- a/doxygen/examples/intro_SWMR.html +++ /dev/null @@ -1,103 +0,0 @@ - - - Introduction to Single-Writer_Multiple-Reader (SWMR) - -

      Introduction to SWMR

      -

      The Single-Writer / Multiple-Reader (SWMR) feature enables multiple processes to read an HDF5 file while it is being written to (by a single process) without using locks or requiring communication between processes.

      -

      tutr-swmr1.png -

      All communication between processes must be performed via the HDF5 file. The HDF5 file under SWMR access must reside on a system that complies with POSIX write() semantics.

      -

      The basic engineering challenge for this to work was to ensure that the readers of an HDF5 file always see a coherent (though possibly not up to date) HDF5 file.

      -

      The issue is that when writing data there is information in the metadata cache in addition to the physical file on disk:

      -

      tutr-swmr2.png -

      However, the readers can only see the state contained in the physical file:

      -

      tutr-swmr3.png -

      The SWMR solution implements dependencies on when the metadata can be flushed to the file. This ensures that metadata cache flush operations occur in the proper order, so that there will never be internal file pointers in the physical file that point to invalid (unflushed) file addresses.

      -

      A beneficial side effect of using SWMR access is better fault tolerance. It is more difficult to corrupt a file when using SWMR.

      -

      Documentation

      -

      SWMR User's Guide

      -

      HDF5 Library APIs

      -
        -
      • H5F_START_SWMR_WRITE — Enables SWMR writing mode for a file
      • -
      • H5DO_APPEND — Appends data to a dataset along a specified dimension
      • -
      • H5P_SET_OBJECT_FLUSH_CB — Sets a callback function to invoke when an object flush occurs in the file
      • -
      • H5P_GET_OBJECT_FLUSH_CB — Retrieves the object flush property values from the file access property list
      • -
      • H5O_DISABLE_MDC_FLUSHES — Prevents metadata entries for an HDF5 object from being flushed from the metadata cache to storage
      • -
      • H5O_ENABLE_MDC_FLUSHES — Enables flushing of dirty metadata entries from a file’s metadata cache
      • -
      • H5O_ARE_MDC_FLUSHES_DISABLED — Determines if an HDF5 object has had flushes of metadata entries disabled
      • -
      -

      Tools

      -
        -
      • h5watch — Outputs new records appended to a dataset as the dataset grows
      • -
      • h5format_convert — Converts the layout format version and chunked indexing types of datasets created with HDF5-1.10 so that applications built with HDF5-1.8 can access them
      • -
      • h5clear — Clears superblock status_flags field, removes metadata cache image, prints EOA and EOF, or sets EOA of a file
      • -
      -

      Design Documents

      -

      Error while fetching page properties report data:

      -

      Programming Model

      -

      Please be aware that the SWMR feature requires that an HDF5 file be created with the latest file format. See H5P_SET_LIBVER_BOUNDS for more information.

      -

      To use SWMR follow the the general programming model for creating and accessing HDF5 files and objects along with the steps described below.

      -

      SWMR Writer:

      -

      The SWMR writer either opens an existing file and objects or creates them as follows.

      -

      Open an existing file:

      -

      Call H5Fopen using the H5F_ACC_SWMR_WRITE flag. -Begin writing datasets. -Periodically flush data. -Create a new file:

      -

      Call H5Fcreate using the latest file format. -Create groups, datasets and attributes, and then close the attributes. -Call H5F_START_SWMR_WRITE to start SWMR access to the file. -Periodically flush data.

      -

      Example Code:

      -

      Create the file using the latest file format property:

      -

      - fapl = H5Pcreate (H5P_FILE_ACCESS); - status = H5Pset_libver_bounds (fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); - fid = H5Fcreate (filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); -[Create objects (files, datasets, ...). Close any attributes and named datatype objects. Groups and datasets may remain open before starting SWMR access to them.]

      -

      Start SWMR access to the file:

      -

      status = H5Fstart_swmr_write (fid); -Reopen the datasets and start writing, periodically flushing data:

      -

      status = H5Dwrite (dset_id, ...); - status = H5Dflush (dset_id);

      -

      SWMR Reader:

      -

      The SWMR reader must continually poll for new data:

      -

      Call H5Fopen using the H5F_ACC_SWMR_READ flag. -Poll, checking the size of the dataset to see if there is new data available for reading. -Read new data, if any.

      -

      Example Code:

      -

      Open the file using the SWMR read flag:

      -

      fid = H5Fopen (filename, H5F_ACC_RDONLY | H5F_ACC_SWMR_READ, H5P_DEFAULT); -Open the dataset and then repeatedly poll the dataset, by getting the dimensions, reading new data, and refreshing:

      -

      dset_id = H5Dopen (...); - space_id = H5Dget_space (...); - while (...) { - status = H5Dread (dset_id, ...); - status = H5Drefresh (dset_id); - space_id = H5Dget_space (...); - }

      -

      Limitations and Scope

      -

      An HDF5 file under SWMR access must reside on a system that complies with POSIX write() semantics. It is also limited in scope as follows:

      -

      The writer process is only allowed to modify raw data of existing datasets by;

      -

      Appending data along any unlimited dimension. -Modifying existing data -The following operations are not allowed (and the corresponding HDF5 files will fail):

      -

      The writer cannot add new objects to the file. -The writer cannot delete objects in the file. -The writer cannot modify or append data with variable length, string or region reference datatypes. -File space recycling is not allowed. As a result the size of a file modified by a SWMR writer may be larger than a file modified by a non-SWMR writer.

      -

      Tools for Working with SWMR

      -

      Two new tools, h5watch and h5clear, are available for use with SWMR. The other HDF5 utilities have also been modified to recognize SWMR:

      -

      The h5watch tool allows a user to monitor the growth of a dataset. -The h5clear tool clears the status flags in the superblock of an HDF5 file. -The rest of the HDF5 tools will exit gracefully but not work with SWMR otherwise.

      -

      Programming Example

      -

      A good example of using SWMR is included with the HDF5 tests in the source code. You can run it while reading the file it creates. If you then interrupt the application and reader and look at the resulting file, you will see that the file is still valid. Follow these steps:

      -

      Download the HDF5-1.10 source code to a local directory on a filesystem (that complies with POSIX write() semantics). Build the software. No special configuration options are needed to use SWMR.

      -

      Invoke two command terminal windows. In one window go into the bin/ directory of the built binaries. In the other window go into the test/ directory of the HDF5-1.10 source code that was just built.

      -

      In the window in the test/ directory compile and run use_append_chunk.c. The example writes a three dimensional dataset by planes (with chunks of size 1 x 256 x 256).

      -

      In the other window (in the bin/ directory) run h5watch on the file created by use_append_chunk.c (use_append_chunk.h5). It should be run while use_append_chunk is executing and you will see valid data displayed with h5watch.

      -

      Interrupt use_append_chunk while it is running, and stop h5watch.

      -

      Use h5clear to clear the status flags in the superblock of the HDF5 file (use_append_chunk.h5).

      -

      View the file with h5dump. You will see that it is a valid file even though the application did not close properly. It will contain data up to the point that it was interrupted.

      - - diff --git a/doxygen/examples/intro_VDS.html b/doxygen/examples/intro_VDS.html deleted file mode 100644 index 6e573b9b75c..00000000000 --- a/doxygen/examples/intro_VDS.html +++ /dev/null @@ -1,72 +0,0 @@ - - - Introduction to the Virtual Dataset - VDS - -

      The HDF5 Virtual Dataset (VDS) feature enables users to access data in a collection of HDF5 files as a single HDF5 dataset and to use the HDF5 APIs to work with that dataset.

      -

      For example, your data may be collected into four files:

      - -

      tutrvds-multimgs.png - -

      You can map the datasets in the four files into a single VDS that can be accessed just like any other dataset:

      - -

      tutrvds-snglimg.png - -

      The mapping between a VDS and the HDF5 source datasets is persistent and transparent to an application. If a source file is missing the fill value will be displayed.

      -

      See the Virtual (VDS) Documentation for complete details regarding the VDS feature.

      -

      The VDS feature was implemented using hyperslab selection (H5S_SELECT_HYPERSLAB). See the tutorial on Reading From or Writing to a Subset of a Dataset for more information on selecting hyperslabs.

      -

      Programming Model -To create a Virtual Dataset you simply follow the HDF5 programming model and add a few additional API calls to map the source code datasets to the VDS.

      -

      Following are the steps for creating a Virtual Dataset:

      -

      Create the source datasets that will comprise the VDS -Create the VDS: ‐ Define a datatype and dataspace (can be unlimited) -‐ Define the dataset creation property list (including fill value) -‐ (Repeat for each source dataset) Map elements from the source dataset to elements of the VDS: -Select elements in the source dataset (source selection) -Select elements in the virtual dataset (destination selection) -Map destination selections to source selections (see Functions for Working with a VDS)

      -

      ‐ Call H5Dcreate using the properties defined above -Access the VDS as a regular HDF5 dataset -Close the VDS when finished

      -

      Functions for Working with a VDS -The H5P_SET_VIRTUAL API sets the mapping between virtual and source datasets. This is a dataset creation property list. Using this API will change the layout of the dataset to H5D_VIRTUAL. As with specifying any dataset creation property list, an instance of the property list is created, modified, passed into the dataset creation call and then closed:

      -

      dcpl = H5Pcreate (H5P_DATASET_CREATE);

      -

      src_space = H5screate_simple ... - status = H5Sselect_hyperslab (space, ... - status = H5Pset_virtual (dcpl, space, SRC_FILE[i], SRC_DATASET[i], src_space);

      -

      dset = H5Dcreate2 (file, DATASET, H5T_NATIVE_INT, space, H5P_DEFAULT, dcpl, H5P_DEFAULT);

      -

      status = H5Pclose (dcpl); -There are several other APIs introduced with Virtual Datasets, including query functions. For details see the complete list of HDF5 library APIs that support Virtual Datasets

      -

      Limitations -This feature requires HDF5-1.10. -The number of source datasets is unlimited. However, there is a limit on the size of each source dataset.

      -

      Programming Examples -Example 1 -This example creates three HDF5 files, each with a one-dimensional dataset of 6 elements. The datasets in these files are the source datasets that are then used to create a 4 x 6 Virtual Dataset with a fill value of -1. The first three rows of the VDS are mapped to the data from the three source datasets as shown below:

      -

      tutrvds-ex.png

      -

      In this example the three source datasets are mapped to the VDS with this code:

      -
      src\_space = H5Screate\_simple (RANK1, dims, NULL);
      -for (i = 0; i < 3; i++) {
      -    start[0] = (hsize\_t)i;
      -    /* Select i-th row in the virtual dataset; selection in the source datasets is the same. */
      -    status = H5Sselect\_hyperslab (space, H5S\_SELECT\_SET, start, NULL, count, block);
      -    status = H5Pset\_virtual (dcpl, space, SRC\_FILE[i], SRC\_DATASET[i], src\_space);
      -}
      -
      -

      After the VDS is created and closed, it is reopened. The property list is then queried to determine the layout of the dataset and its mappings, and the data in the VDS is read and printed.

      -

      This example is in the HDF5 source code and can be obtained from here:

      -

      C Example

      -

      For details on compiling an HDF5 application: [ Compiling HDF5 Applications ]

      -

      Example 2 -This example shows how to use a C-style printf statement for specifying multiple source datasets as one virtual dataset. Only one mapping is required. In other words only one H5P_SET_VIRTUAL call is needed to map multiple datasets. It creates a 2-dimensional unlimited VDS. Then it re-opens the file, makes queries, and reads the virtual dataset.

      -

      The source datasets are specified as A-0, A-1, A-2, and A-3. These are mapped to the virtual dataset with one call:

      -
      status = H5Pset\_virtual (dcpl, vspace, SRCFILE, "/A-%b", src\_space);
      -
      -

      The %b indicates that the block count of the selection in the dimension should be used.

      -

      C Example

      -

      For details on compiling an HDF5 application: [ Compiling HDF5 Applications ]

      -

      Using h5dump with a VDS -The h5dump utility can be used to view a VDS. The h5dump output for a VDS looks exactly like that for any other dataset. If h5dump cannot find a source dataset then the fill value will be displayed.

      -

      You can determine that a dataset is a VDS by looking at its properties with h5dump -p. It will display each source dataset mapping, beginning with Mapping 0. Below is an excerpt of the output of h5dump -p on the vds.h5 file created in Example 1.You can see that the entire source file a.h5 is mapped to the first row of the /VDS dataset:

      - -

      tutrvds-map.png

      - diff --git a/doxygen/examples/tables/propertyLists.dox b/doxygen/examples/tables/propertyLists.dox index 340e13c26a5..76727b58a59 100644 --- a/doxygen/examples/tables/propertyLists.dox +++ b/doxygen/examples/tables/propertyLists.dox @@ -490,12 +490,12 @@ and one raw data file. #H5Pget_filter Returns information about a filter in a pipeline. -The C function is a macro: \see \ref api-compat-macros. +The C function is a macro: @see @ref api-compat-macros. #H5Pget_filter_by_id Returns information about the specified filter. -The C function is a macro: \see \ref api-compat-macros. +The C function is a macro: @see @ref api-compat-macros. #H5Pmodify_filter @@ -739,12 +739,12 @@ of the library for reading or writing the actual data. #H5Pget_filter Returns information about a filter in a pipeline. The -C function is a macro: \see \ref api-compat-macros. +C function is a macro: @see @ref api-compat-macros. #H5Pget_filter_by_id Returns information about the specified filter. The -C function is a macro: \see \ref api-compat-macros. +C function is a macro: @see @ref api-compat-macros. #H5Pget_nfilters diff --git a/doxygen/hdf5doxy_layout.xml b/doxygen/hdf5doxy_layout.xml index d895b2dd5bd..20e951856c7 100644 --- a/doxygen/hdf5doxy_layout.xml +++ b/doxygen/hdf5doxy_layout.xml @@ -5,12 +5,12 @@ - + + --> diff --git a/hl/src/H5DOpublic.h b/hl/src/H5DOpublic.h index 661ca7a2abe..09a8f64829f 100644 --- a/hl/src/H5DOpublic.h +++ b/hl/src/H5DOpublic.h @@ -161,7 +161,7 @@ H5_HLDLL herr_t H5DOappend(hid_t dset_id, hid_t dxpl_id, unsigned axis, size_t e * from one datatype to another, and the filter pipeline to write the chunk. * Developers should have experience with these processes before * using this function. Please see - * + * * Using the Direct Chunk Write Function * for more information. * diff --git a/hl/src/H5DSpublic.h b/hl/src/H5DSpublic.h index 4afe51180f9..6a08be8e5c2 100644 --- a/hl/src/H5DSpublic.h +++ b/hl/src/H5DSpublic.h @@ -117,7 +117,7 @@ H5_HLDLL herr_t H5DSwith_new_ref(hid_t obj_id, hbool_t *with_new_ref); * * Entries are created in the #DIMENSION_LIST and * #REFERENCE_LIST attributes, as defined in section 4.2 of - * + * * HDF5 Dimension Scale Specification. * * Fails if: @@ -147,7 +147,7 @@ H5_HLDLL herr_t H5DSattach_scale(hid_t did, hid_t dsid, unsigned int idx); * dimension \p idx of dataset \p did. This deletes the entries in the * #DIMENSION_LIST and #REFERENCE_LIST attributes, * as defined in section 4.2 of - * + * * HDF5 Dimension Scale Specification. * * Fails if: @@ -180,7 +180,7 @@ H5_HLDLL herr_t H5DSdetach_scale(hid_t did, hid_t dsid, unsigned int idx); * as defined above. Creates the CLASS attribute, set to the value * "DIMENSION_SCALE" and an empty #REFERENCE_LIST attribute, * as described in - * + * * HDF5 Dimension Scale Specification. * (PDF, see section 4.2). * diff --git a/hl/src/H5LTpublic.h b/hl/src/H5LTpublic.h index 18f7502209f..514fe244e10 100644 --- a/hl/src/H5LTpublic.h +++ b/hl/src/H5LTpublic.h @@ -1386,8 +1386,8 @@ H5_HLDLL herr_t H5LTget_attribute_info(hid_t loc_id, const char *obj_name, const * \p lang_type definition of HDF5 datatypes. * Currently, only the DDL(#H5LT_DDL) is supported. * The complete DDL definition of HDF5 datatypes can be found in - * the last chapter of the - * + * the specifications chapter of the + * * HDF5 User's Guide. * * \par Example @@ -1424,8 +1424,8 @@ H5_HLDLL hid_t H5LTtext_to_dtype(const char *text, H5LT_lang_t lang_type); * * Currently only DDL (#H5LT_DDL) is supported for \p lang_type. * The complete DDL definition of HDF5 data types can be found in - * the last chapter of the - * + * the specifications chapter of the + * * HDF5 User's Guide. * * \par Example @@ -1625,7 +1625,7 @@ H5_HLDLL htri_t H5LTpath_valid(hid_t loc_id, const char *path, hbool_t check_obj * \note **Recommended Reading:** * \note This function is part of the file image operations feature set. * It is highly recommended to study the guide - * + * * HDF5 File Image Operations before using this feature set.\n * See the “See Also” section below for links to other elements of * HDF5 file image operations. diff --git a/java/src/hdf/overview.html b/java/src/hdf/overview.html index 84e945b2f87..8329277cda7 100644 --- a/java/src/hdf/overview.html +++ b/java/src/hdf/overview.html @@ -91,6 +91,6 @@

      and the HDF5 library.

      To Obtain

      -The JHI5 is included with the HDF5 library. +The JHI5 is included with the HDF5 library. diff --git a/java/src/jni/exceptionImp.c b/java/src/jni/exceptionImp.c index 4cf03ac9f28..6b2004ddeb4 100644 --- a/java/src/jni/exceptionImp.c +++ b/java/src/jni/exceptionImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5Constants.c b/java/src/jni/h5Constants.c index 41395a4413f..aeec71fb9f4 100644 --- a/java/src/jni/h5Constants.c +++ b/java/src/jni/h5Constants.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5Imp.c b/java/src/jni/h5Imp.c index 898b52ad3ed..6092419c256 100644 --- a/java/src/jni/h5Imp.c +++ b/java/src/jni/h5Imp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5aImp.c b/java/src/jni/h5aImp.c index 54c862eff6c..b6ed1c4c3e1 100644 --- a/java/src/jni/h5aImp.c +++ b/java/src/jni/h5aImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5dImp.c b/java/src/jni/h5dImp.c index f6318b222d4..363936b76e9 100644 --- a/java/src/jni/h5dImp.c +++ b/java/src/jni/h5dImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5eImp.c b/java/src/jni/h5eImp.c index d52a4f72cd0..89c9362626f 100644 --- a/java/src/jni/h5eImp.c +++ b/java/src/jni/h5eImp.c @@ -21,9 +21,6 @@ extern "C" { * Each routine wraps a single HDF entry point, generally with the * analogous arguments and return codes. * - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * */ #include diff --git a/java/src/jni/h5fImp.c b/java/src/jni/h5fImp.c index 9295383ef4d..6bd17a786cb 100644 --- a/java/src/jni/h5fImp.c +++ b/java/src/jni/h5fImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5gImp.c b/java/src/jni/h5gImp.c index fce68022649..54b72b6c09a 100644 --- a/java/src/jni/h5gImp.c +++ b/java/src/jni/h5gImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5iImp.c b/java/src/jni/h5iImp.c index de70e1e424f..728c3b14ed5 100644 --- a/java/src/jni/h5iImp.c +++ b/java/src/jni/h5iImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5jni.h b/java/src/jni/h5jni.h index ad867083ba9..b1bd968ba7c 100644 --- a/java/src/jni/h5jni.h +++ b/java/src/jni/h5jni.h @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #include #include "H5version.h" #include diff --git a/java/src/jni/h5lImp.c b/java/src/jni/h5lImp.c index 0d9ac7dfc01..7d487999f96 100644 --- a/java/src/jni/h5lImp.c +++ b/java/src/jni/h5lImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5oImp.c b/java/src/jni/h5oImp.c index 15daeafde6b..60a6e4fbf90 100644 --- a/java/src/jni/h5oImp.c +++ b/java/src/jni/h5oImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pACPLImp.c b/java/src/jni/h5pACPLImp.c index 4635fa7373b..7c9895a6de1 100644 --- a/java/src/jni/h5pACPLImp.c +++ b/java/src/jni/h5pACPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pDAPLImp.c b/java/src/jni/h5pDAPLImp.c index 01c3983c2cc..44378a1dc5e 100644 --- a/java/src/jni/h5pDAPLImp.c +++ b/java/src/jni/h5pDAPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pDCPLImp.c b/java/src/jni/h5pDCPLImp.c index a624fd96987..ebe12cb5455 100644 --- a/java/src/jni/h5pDCPLImp.c +++ b/java/src/jni/h5pDCPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pDXPLImp.c b/java/src/jni/h5pDXPLImp.c index 31f6d02b860..3b519ef2709 100644 --- a/java/src/jni/h5pDXPLImp.c +++ b/java/src/jni/h5pDXPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pFAPLImp.c b/java/src/jni/h5pFAPLImp.c index af56336fb55..24b7f357e50 100644 --- a/java/src/jni/h5pFAPLImp.c +++ b/java/src/jni/h5pFAPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pFCPLImp.c b/java/src/jni/h5pFCPLImp.c index 7c1b44add5f..56b4e921aae 100644 --- a/java/src/jni/h5pFCPLImp.c +++ b/java/src/jni/h5pFCPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pGAPLImp.c b/java/src/jni/h5pGAPLImp.c index 0ee65710ac5..b38bd4b3b23 100644 --- a/java/src/jni/h5pGAPLImp.c +++ b/java/src/jni/h5pGAPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pGCPLImp.c b/java/src/jni/h5pGCPLImp.c index 49d79dc2366..b71558012ce 100644 --- a/java/src/jni/h5pGCPLImp.c +++ b/java/src/jni/h5pGCPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pImp.c b/java/src/jni/h5pImp.c index c952ccb9dff..6c17984ae24 100644 --- a/java/src/jni/h5pImp.c +++ b/java/src/jni/h5pImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pLAPLImp.c b/java/src/jni/h5pLAPLImp.c index 3048c155413..36813e33fc9 100644 --- a/java/src/jni/h5pLAPLImp.c +++ b/java/src/jni/h5pLAPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pLCPLImp.c b/java/src/jni/h5pLCPLImp.c index ecabadd29bc..e27a9eb1570 100644 --- a/java/src/jni/h5pLCPLImp.c +++ b/java/src/jni/h5pLCPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pOCPLImp.c b/java/src/jni/h5pOCPLImp.c index 7cd9b5c721f..a743cbaa7f4 100644 --- a/java/src/jni/h5pOCPLImp.c +++ b/java/src/jni/h5pOCPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pOCpyPLImp.c b/java/src/jni/h5pOCpyPLImp.c index c4d2ed7fd14..a78aaa259f0 100644 --- a/java/src/jni/h5pOCpyPLImp.c +++ b/java/src/jni/h5pOCpyPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5pStrCPLImp.c b/java/src/jni/h5pStrCPLImp.c index 0045efa342e..3382f0aea30 100644 --- a/java/src/jni/h5pStrCPLImp.c +++ b/java/src/jni/h5pStrCPLImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5plImp.c b/java/src/jni/h5plImp.c index 3c87fd52a99..9632e9e2609 100644 --- a/java/src/jni/h5plImp.c +++ b/java/src/jni/h5plImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5rImp.c b/java/src/jni/h5rImp.c index f97f803f90e..4ccad5457a2 100644 --- a/java/src/jni/h5rImp.c +++ b/java/src/jni/h5rImp.c @@ -10,11 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5sImp.c b/java/src/jni/h5sImp.c index 55fb268434f..738db67ffee 100644 --- a/java/src/jni/h5sImp.c +++ b/java/src/jni/h5sImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5tImp.c b/java/src/jni/h5tImp.c index 309454b16e4..316455715ac 100644 --- a/java/src/jni/h5tImp.c +++ b/java/src/jni/h5tImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5util.c b/java/src/jni/h5util.c index 9c441729a39..fb619aa619d 100644 --- a/java/src/jni/h5util.c +++ b/java/src/jni/h5util.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5util.h b/java/src/jni/h5util.h index 5af96afaee9..011aaec428f 100644 --- a/java/src/jni/h5util.h +++ b/java/src/jni/h5util.h @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifndef H5UTIL_H__ #define H5UTIL_H__ diff --git a/java/src/jni/h5vlImp.c b/java/src/jni/h5vlImp.c index 2bf0b8d6b0a..47e532a5609 100644 --- a/java/src/jni/h5vlImp.c +++ b/java/src/jni/h5vlImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/h5zImp.c b/java/src/jni/h5zImp.c index e6d37bfa3af..9c387fa33ee 100644 --- a/java/src/jni/h5zImp.c +++ b/java/src/jni/h5zImp.c @@ -10,12 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ - #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/java/src/jni/nativeData.c b/java/src/jni/nativeData.c index d25951ff436..d014b64579d 100644 --- a/java/src/jni/nativeData.c +++ b/java/src/jni/nativeData.c @@ -10,11 +10,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* - * For details of the HDF libraries, see the HDF Documentation at: - * https://portal.hdfgroup.org/documentation/index.html - * - */ /* * This module contains the implementation of all the native methods * used for number conversion. This is represented by the Java diff --git a/release_docs/INSTALL b/release_docs/INSTALL index 9373192912b..63f2115fdd6 100644 --- a/release_docs/INSTALL +++ b/release_docs/INSTALL @@ -49,7 +49,7 @@ CONTENTS include the Szip library with the encoder enabled. These can be found here: - https://www.hdfgroup.org/downloads/hdf5/ + https://support.hdfgroup.org/downloads/HDF5 Please notice that if HDF5 configure cannot find a valid Szip library, configure will not fail; in this case, the compression filter will diff --git a/release_docs/INSTALL_Autotools.txt b/release_docs/INSTALL_Autotools.txt index a2c948198e8..0a2400dc096 100644 --- a/release_docs/INSTALL_Autotools.txt +++ b/release_docs/INSTALL_Autotools.txt @@ -334,7 +334,7 @@ III. Full installation instructions for source distributions (or '--with-pthread=DIR') flag to the configure script. For further information, see: - https://portal.hdfgroup.org/display/knowledge/Questions+about+thread-safety+and+concurrent+access + https://support.hdfgroup.org/documentation/HDF5/Questions+about+thread-safety+and+concurrent+access The high-level, C++, Fortran and Java interfaces are not compatible with the thread-safety option because the lock is not hoisted @@ -492,7 +492,7 @@ IV. Using the Library For information on using HDF5 see the documentation, tutorials and examples found here: - https://portal.hdfgroup.org/documentation/index.html + https://support.hdfgroup.org/documentation/HDF5/index.html A summary of the features included in the built HDF5 installation can be found in the libhdf5.settings file in the same directory as the static and/or diff --git a/release_docs/INSTALL_CMake.txt b/release_docs/INSTALL_CMake.txt index a86bae4bab6..b2bd84c20f3 100644 --- a/release_docs/INSTALL_CMake.txt +++ b/release_docs/INSTALL_CMake.txt @@ -59,7 +59,7 @@ HDF Group recommends using the ctest script mode to build HDF5. ------------------------------------------------------------------------- Individual files needed as mentioned in this document ------------------------------------------------------------------------- -Download from https://github.com/HDFGroup/hdf5/tree/master/config/cmake/scripts: +Download from https://github.com/HDFGroup/hdf5/blob/develop/config/cmake/scripts: CTestScript.cmake -- CMake build script HDF5config.cmake -- CMake configuration script diff --git a/release_docs/INSTALL_parallel b/release_docs/INSTALL_parallel index 9eb486f79d2..df255c6e0ad 100644 --- a/release_docs/INSTALL_parallel +++ b/release_docs/INSTALL_parallel @@ -90,7 +90,7 @@ nodes. They would probably work for other Cray systems but have not been verified. Obtain the HDF5 source code: - https://portal.hdfgroup.org/display/support/Downloads + https://support.hdfgroup.org/downloads/HDF5 The entire build process should be done on a MOM node in an interactive allocation and on a file system accessible by all compute nodes. Request an interactive allocation with qsub: diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index aa681ddf791..89ed27fa5dc 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -15,16 +15,16 @@ final release. Links to HDF5 documentation can be found on: - https://portal.hdfgroup.org/documentation/ + https://support.hdfgroup.org/documentation/HDF5 The official HDF5 releases can be obtained from: - https://www.hdfgroup.org/downloads/hdf5/ + https://support.hdfgroup.org/downloads/HDF5/ Changes from Release to Release and New Features in the HDF5-1.16.x release series can be found at: - https://portal.hdfgroup.org/documentation/hdf5-docs/release_specific_info.html + https://support.hdfgroup.org/documentation/HDF5/release_specific_info.html If you have any questions or comments, please send them to the HDF Help Desk: diff --git a/release_docs/RELEASE_PROCESS.md b/release_docs/RELEASE_PROCESS.md index 047183b6026..3e876d34369 100644 --- a/release_docs/RELEASE_PROCESS.md +++ b/release_docs/RELEASE_PROCESS.md @@ -18,7 +18,7 @@ Maintenance releases are always forward compatible with regards to the HDF5 file - HDF5 libraries and command line utilities can access files created by future maintenance versions of the library. Note that maintenance releases are NOT guaranteed to be interface-compatible, meaning that, on occasion, application source code will need updated and re-compiled against a new maintenance release when the interface changes. Interface changes are only made when absolutely necessary as deemed by the HDF5 product manager(s), and interface compatibility reports are published with each release to inform customers and users of any incompatibilities in the interface. -For more information on the HDF5 versioning and backward and forward compatibility issues, see the [API Compatibility Macros](https://hdfgroup.github.io/hdf5/develop/api-compat-macros.html) on the public website. +For more information on the HDF5 versioning and backward and forward compatibility issues, see the [API Compatibility Macros][u13] on the public website. ## Participants: - Product Manager — The individual responsible for the overall direction and development of a software product at The HDF Group. @@ -35,21 +35,21 @@ For more information on the HDF5 versioning and backward and forward compatibili ### 3. Prepare Release Notes (Release Manager) 1. Confirm that all non-trivial changes made to the source are reflected in the release notes. Verify the following: - [HDF5 Milestones Projects](https://github.com/HDFGroup/hdf5/milestones) - - Each entry in [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt) traces to one or more resolved GH issues marked with FixVersion="X.Y.Z". - - Each resolved GH milestone issue traces to an entry in [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt). + - Each entry in [RELEASE.txt][u1] traces to one or more resolved GH issues marked with FixVersion="X.Y.Z". + - Each resolved GH milestone issue traces to an entry in [RELEASE.txt][u1]. - Each resolved GH milestone issue traces to one or more revisions to the HDF5 source. - Each resolved GH milestone issue traces to one or more pull requests. -2. For each previously authored KNOWN ISSUE in the [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt), if the issue has been resolved or can no longer be confirmed, remove the issue from the [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt). +2. For each previously authored KNOWN ISSUE in the [RELEASE.txt][u1], if the issue has been resolved or can no longer be confirmed, remove the issue from the [RELEASE.txt][u1]. - Document any new known issues at the top of the list. -3. Update the TESTED CONFIGURATION FEATURES SUMMARY in [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt) to correspond to features and options that have been tested during the maintenance period by the automated daily regression tests. +3. Update the TESTED CONFIGURATION FEATURES SUMMARY in [RELEASE.txt][u1] to correspond to features and options that have been tested during the maintenance period by the automated daily regression tests. - **See: Testing/Testing Systems(this is a page in confluence)** -4. Update current compiler information for each platform in the PLATFORMS TESTED section of [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt). -5. Review the [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt) for formatting and language to verify that it corresponds to guidelines found in **[Writing Notes in a RELEASE.txt(this is missing)]()** File. -6. Review and update, if needed, the [README](https://github.com/HDFGroup/hdf5/blob/develop/README.md) and [COPYING](https://github.com/HDFGroup/hdf5/blob/develop/COPYING) files. -7. Review and update all INSTALL_* files in [release_docs](https://github.com/HDFGroup/hdf5/tree/develop/release_docs), if needed. - - [INSTALL](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL) should be general info and not require extensive changes - - [INSTALL_Autotools.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_Autotools.txt) are the instructions for building under autotools. - - [INSTALL_CMake.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_CMake.txt) are the instructions for building under CMake. +4. Update current compiler information for each platform in the PLATFORMS TESTED section of [RELEASE.txt][u1]. +5. Review the [RELEASE.txt][u1] for formatting and language to verify that it corresponds to guidelines found in **[Writing Notes in a RELEASE.txt(this is missing)]()** File. +6. Review and update, if needed, the [README][u2] and [COPYING][u3] files. +7. Review and update all INSTALL_* files in [release_docs][u4], if needed. + - [INSTALL][u5] should be general info and not require extensive changes + - [INSTALL_Autotools.txt][u6] are the instructions for building under autotools. + - [INSTALL_CMake.txt][u7] are the instructions for building under CMake. ### 4. Freeze Code (Release Manager | Test Automation Team) 1. Transition from performing maintenance on software to preparing for its delivery. @@ -62,14 +62,14 @@ For more information on the HDF5 versioning and backward and forward compatibili ### 5. Update Interface Version (Release Manager | Product Manager) 1. Verify interface additions, changes, and removals, and update the shared library interface version number. 2. Execute the CI snapshot workflow. - - Actions - “[hdf5 release build](https://github.com/HDFGroup/hdf5/blob/develop/.github/workflows/release.yml)” workflow and use the defaults. + - Actions - “[hdf5 release build][u8]” workflow and use the defaults. 3. Download and inspect release build source and binary files. Downloaded source files should build correctly, one or more binaries should install and run correctly. There should be nothing missing nor any extraneous files that aren’t meant for release. -4. Verify the interface compatibility reports between the current source and the previous release on the Github [Snapshots](https://github.com/HDFGroup/hdf5/releases/tag/snapshot-1.14) page. - - The compatibility reports are produced by the CI and are viewable in the Github [Releases/snapshot](https://github.com/HDFGroup/hdf5/releases/tag/snapshot) section. -5. Verify the interface compatibility reports between the current source and the previous release on the Github [Snapshots](https://github.com/HDFGroup/hdf5/releases/tag/snapshot-1.14) page. - - The compatibility reports are produced by the CI and are viewable in the Github [Releases/snapshot](https://github.com/HDFGroup/hdf5/releases/tag/snapshot) section. +4. Verify the interface compatibility reports between the current source and the previous release on the Github [Snapshots]u14] page. + - The compatibility reports are produced by the CI and are viewable in the Github [Releases/snapshot][u15] section. +5. Verify the interface compatibility reports between the current source and the previous release on the Github [Snapshots][u14] page. + - The compatibility reports are produced by the CI and are viewable in the Github [Releases/snapshot][u15] section. 6. Confirm the necessity of and approve of any interface-breaking changes. If any changes need to be reverted, task the developer who made the change to do so as soon as possible. If a change is reverted, return to the previous step and regenerate the compatibility report after the changes is made. Otherwise, continue to the next step. -7. Update the .so version numbers in the [config/lt_vers.am](https://github.com/HDFGroup/hdf5/blob/develop/config/lt_vers.am) file in the support branch according to [libtool's library interface version](https://www.gnu.org/software/libtool/manual/libtool.html#Versioning) scheme. +7. Update the .so version numbers in the [config/lt_vers.am][u9] file in the support branch according to [libtool's library interface version](https://www.gnu.org/software/libtool/manual/libtool.html#Versioning) scheme. - See [Updating version info (Libtool)](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info) for rules to help update library version numbers. 8. After the release branch has been created, run `./autogen.sh` to regenerate build system files on the release branch and commit the changes. @@ -83,21 +83,21 @@ For more information on the HDF5 versioning and backward and forward compatibili - or create the new branch in GitHub GUI. 4. Check that required CMake files point to the specific versions of the third-party software (szip, zlib and plugins) that they depend on. - Update as needed. -5. Change the **support** branch to X.Y.{Z+1}-1 using the [bin/h5vers](https://github.com/HDFGroup/hdf5/blob/develop/bin/h5vers) script: +5. Change the **support** branch to X.Y.{Z+1}-1 using the [bin/h5vers][u10] script: - `$ git checkout hdf5_X_Y` - `$ bin/h5vers -s X.Y.{Z+1}-1;` - `$ git commit -m "Updated support branch version number to X.Y.{Z+1}-1"` - `$ git push` -6. Change the **release preparation branch**'s version number to X.Y.Z-{SR+1} using the [bin/h5vers](https://github.com/HDFGroup/hdf5/blob/develop/bin/h5vers) script: +6. Change the **release preparation branch**'s version number to X.Y.Z-{SR+1} using the [bin/h5vers][u10]/bin/h5vers script: - `$ git checkout hdf5_X_Y_Z;` - `$ bin/h5vers -s X.Y.Z-{SR+1};` - `$ git commit -m "Updated release preparation branch version number to X.Y.Z-{SR+1}"` - `$ git push` 7. Update default configuration mode - `$ git checkout hdf5_X_Y_Z;` and `$ bin/switch_maint_mode -disable ./configure.ac` to disable `AM_MAINTAINER_MODE`. - - Need to set option `HDF5_GENERATE_HEADERS` to `OFF`, currently in line 996 of [src/CMakeLists.txt](https://github.com/HDFGroup/hdf5/blob/develop/src/CMakeLists.txt). - - Change the **release preparation branch**'s (i.e. hdf5_X_Y_Z) default configuration mode from development to production in [configure.ac](https://github.com/HDFGroup/hdf5/blob/develop/configure.ac). - - Find “Determine build mode” in [configure.ac](https://github.com/HDFGroup/hdf5/blob/develop/configure.ac). + - Need to set option `HDF5_GENERATE_HEADERS` to `OFF`, currently in line 996 of [src/CMakeLists.txt][11]. + - Change the **release preparation branch**'s (i.e. hdf5_X_Y_Z) default configuration mode from development to production in [configure.ac][u12]. + - Find “Determine build mode” in [configure.ac][u12]. - Change `default=debug` to `default=production` at the bottom of the `AS_HELP_STRING` for `--enable-build-mode`. - Under `if test "X-$BUILD_MODE" = X- ; then` change `BUILD_MODE=debug` to `BUILD_MODE=production`. - Run `sh ./autogen.sh` to regenerate the UNIX build system files and commit the changes. (use `git status --ignored` to see the changes and `git add -f` to add all files. First delete any new files not to be committed, notably `src/H5public.h~` and `autom4te.cache/`.) @@ -114,7 +114,7 @@ For more information on the HDF5 versioning and backward and forward compatibili 7. Choose the release branch 8. Change ‘Release version tag’ name to 'hdf5_X.Y.Z.P' - P is some pre-release number. -9. Send a message to the HDF forum indicating that a pre-release source package is available for testing at and that feedback from the user community on their test results is being accepted. +9. Send a message to the HDF forum indicating that a pre-release source package is available for testing at and that feedback from the user community on their test results is being accepted. 10. Contact paying clients who are interested in testing the pre-release source package and inform them that it is available for testing and that feedback on their test results of the pre-release is appreciated. 11. This should be automated and currently github binaries are not signed. - Follow the [How to sign binaries with digital certificates(this is missing)]() work instructions to sign each Windows and Mac binary package with a digital certificate. @@ -137,7 +137,7 @@ For more information on the HDF5 versioning and backward and forward compatibili ### 8. Finalize Release Notes (Release Manager) 1. Perform a final review of release notes and ensure that any new changes made to the source, any new known issues discovered, and any additional tests run since the code freeze have been reflected in RELEASE.txt and other appropriate in-source documentation files (INSTALL_*, etc.). (Refer to the sub-steps of step 3 for what to check). -2. Update the [RELEASE.txt](https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt) in the **support** branch (i.e. hdf5_X_Y) to remove entries in “Bugs fixed” and “New Features” sections and increment the version number for the following release (“Bug fixes since X.Y.Z” - occurs twice). +2. Update the [RELEASE.txt][u1] in the **support** branch (i.e. hdf5_X_Y) to remove entries in “Bugs fixed” and “New Features” sections and increment the version number for the following release (“Bug fixes since X.Y.Z” - occurs twice). - `$ git checkout hdf5_X_Y` - `$ vi RELEASE.txt # update RELEASE.txt to clear it out` - `$ git commit -m "Reset RELEASE.txt in preparation for the next release."` @@ -161,3 +161,19 @@ For more information on the HDF5 versioning and backward and forward compatibili ### 11. Conduct Release Retrospective (Release Manager) 1. Schedule time and solicit comments from retrospective 2. Identify issues and document them + +[u1]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/RELEASE.txt +[u2]: https://github.com/HDFGroup/hdf5/blob/develop/README.md +[u3]: https://github.com/HDFGroup/hdf5/blob/develop/COPYING +[u4]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs +[u5]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL +[u6]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_Auto.txt +[u7]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_CMake.txt +[u8]: https://github.com/HDFGroup/hdf5/blob/develop/.github/workflows/release.yml +[u9]: https://github.com/HDFGroup/hdf5/blob/develop/config/lt_vers.am +[u10]: https://github.com/HDFGroup/hdf5/blob/develop/bin/h5vers +[u11]: https://github.com/HDFGroup/hdf5/blob/develop/src/CMakeLists.txt +[u12]: https://github.com/HDFGroup/hdf5/blob/develop/configure.ac +[u13]: https://support.hdfgroup.org/documentation/HDF5/v1_14/v1_14_4/api-compat-macros.html +[u14]: https://github.com/HDFGroup/hdf5/releases/tag/snapshot-1.14 +[u15]: https://github.com/HDFGroup/hdf5/releases/tag/snapshot diff --git a/src/H5Amodule.h b/src/H5Amodule.h index 18fabe56f58..42715535367 100644 --- a/src/H5Amodule.h +++ b/src/H5Amodule.h @@ -59,7 +59,7 @@ * attached directly to that object * * \subsection subsec_error_H5A Attribute Function Summaries - * @see H5A reference manual + * see @ref H5A reference manual * * \subsection subsec_attribute_program Programming Model for Attributes * @@ -98,26 +98,6 @@ * \li Close the attribute * \li Close the primary data object (if appropriate) * - * - * - * - * - * - * - * - * - * - * - *
      CreateUpdate
      - * \snippet{lineno} H5A_examples.c create - * - * \snippet{lineno} H5A_examples.c update - *
      ReadDelete
      - * \snippet{lineno} H5A_examples.c read - * - * \snippet{lineno} H5A_examples.c delete - *
      - * * \subsection subsec_attribute_work Working with Attributes * * \subsubsection subsubsec_attribute_work_struct The Structure of an Attribute @@ -376,7 +356,7 @@ * An HDF5 attribute is a small metadata object describing the nature and/or intended usage of a primary data * object. A primary data object may be a dataset, group, or committed datatype. * - * @see sec_attribute + * @see \ref sec_attribute * */ diff --git a/src/H5Dmodule.h b/src/H5Dmodule.h index 26e748ce1a0..96c5b1a704e 100644 --- a/src/H5Dmodule.h +++ b/src/H5Dmodule.h @@ -887,7 +887,7 @@ filter. * It is clear that the internal HDF5 filter mechanism, while extensible, does not work well with third-party * filters. It would be a maintenance nightmare to keep adding and supporting new compression methods * in HDF5. For any set of HDF5 “internal” filters, there always will be data with which the “internal” -filters + * filters * will not achieve the optimal performance needed to address data I/O and storage problems. Thus the * internal HDF5 filter mechanism is enhanced to address the issues discussed above. * @@ -901,7 +901,7 @@ filters * * When an application reads data compressed with a third-party HDF5 filter, the HDF5 Library will search * for the required filter plugin, register the filter with the library (if the filter function is not -registered) and + * registered) and * apply it to the data on the read operation. * * For more information, @@ -1496,7 +1496,7 @@ allocated if necessary. * the size of the memory datatype and the number of elements in the memory selection. * * Variable-length data are organized in two or more areas of memory. For more information, - * \see \ref h4_vlen_datatype "Variable-length Datatypes". + * see \ref h4_vlen_datatype "Variable-length Datatypes". * * When writing data, the application creates an array of * vl_info_t which contains pointers to the elements. The elements might be, for example, strings. @@ -2735,7 +2735,7 @@ allocated if necessary. * See The HDF Group website for further information regarding the SZip filter. * * \subsubsection subsubsec_dataset_filters_dyn Using Dynamically-Loadable Filters - * \see \ref sec_filter_plugins for further information regarding the dynamically-loadable filters. + * see \ref sec_filter_plugins for further information regarding the dynamically-loadable filters. * * HDF has a filter plugin repository of useful third-party plugins that can used * diff --git a/src/H5Emodule.h b/src/H5Emodule.h index 307b5a7fac4..f46456a1369 100644 --- a/src/H5Emodule.h +++ b/src/H5Emodule.h @@ -58,7 +58,7 @@ * design for the Error Handling API. * * \subsection subsec_error_H5E Error Handling Function Summaries - * @see H5E reference manual + * see @ref H5E reference manual * * \subsection subsec_error_program Programming Model for Error Handling * This section is under construction. @@ -80,24 +80,21 @@ * an error stack ID is needed as a parameter, \ref H5E_DEFAULT can be used to indicate the library's default * stack. The first error record of the error stack, number #000, is produced by the API function itself and * is usually sufficient to indicate to the application what went wrong. - *
      - * - * - * - * - *
      Example: An Error Message
      - *

      If an application calls \ref H5Tclose on a - * predefined datatype then the following message is - * printed on the standard error stream. This is a - * simple error that has only one component, the API - * function; other errors may have many components. - *

      + *
      + * If an application calls \ref H5Tclose  on a
      + * predefined datatype then the following message is
      + * printed on the standard error stream.  This is a
      + * simple error that has only one component, the API
      + * function; other errors may have many components.
      + *
      + * An Error Message Example
      + * \code
        * HDF5-DIAG: Error detected in HDF5 (1.10.9) thread 0.
        *    #000: H5T.c line ### in H5Tclose(): predefined datatype
        *       major: Function argument
        *       minor: Bad value
      - *         
      - *
      + * \endcode + * * In the example above, we can see that an error record has a major message and a minor message. A major * message generally indicates where the error happens. The location can be a dataset or a dataspace, for * example. A minor message explains further details of the error. An example is “unable to open file”. @@ -158,15 +155,15 @@ * * Example: Turn off error messages while probing a function * \code - * *** Save old error handler *** + * // Save old error handler * H5E_auto2_t oldfunc; * void *old_client_data; * H5Eget_auto2(error_stack, &old_func, &old_client_data); - * *** Turn off error handling *** + * // Turn off error handling * H5Eset_auto2(error_stack, NULL, NULL); - * *** Probe. Likely to fail, but that's okay *** + * // Probe. Likely to fail, but that's okay * status = H5Fopen (......); - * *** Restore previous error handler *** + * // Restore previous error handler * H5Eset_auto2(error_stack, old_func, old_client_data); * \endcode * @@ -174,9 +171,9 @@ * * Example: Disable automatic printing and explicitly print error messages * \code - * *** Turn off error handling permanently *** + * // Turn off error handling permanently * H5Eset_auto2(error_stack, NULL, NULL); - * *** If failure, print error message *** + * // If failure, print error message * if (H5Fopen (....)<0) { * H5Eprint2(H5E_DEFAULT, stderr); * exit (1); @@ -243,9 +240,9 @@ * * The following example shows a user‐defined callback function. * - * Example: A user‐defined callback function + * A user‐defined callback function Example * \code - * \#define MSG_SIZE 64 + * #define MSG_SIZE 64 * herr_t * custom_print_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data) * { @@ -255,7 +252,7 @@ * char cls[MSG_SIZE]; * const int indent = 4; * - * *** Get descriptions for the major and minor error numbers *** + * // Get descriptions for the major and minor error numbers * if(H5Eget_class_name(err_desc->cls_id, cls, MSG_SIZE) < 0) * TEST_ERROR; * if(H5Eget_msg(err_desc->maj_num, NULL, maj, MSG_SIZE) < 0) @@ -296,13 +293,11 @@ * to push its own error records onto the error stack once it declares an error class of its own through the * HDF5 Error API. * - * - * - * - * - * - *
      Example: An Error Report
      - *

      An error report shows both the library's error record and the application's error records. - * See the example below. - *

      + * An error report shows both the library's error record and the application's error records.
      + * See the example below.
      + *
      + * An Error Report Example
      + * \code
        * Error Test-DIAG: Error detected in Error Program (1.0)
        *         thread 8192:
        *     #000: ../../hdf5/test/error_test.c line ### in main():
      @@ -318,10 +313,8 @@
        *         not a dataset
        *       major: Invalid arguments to routine
        *       minor: Inappropriate type
      - *       
      - *
      + *\endcode + * * In the line above error record #002 in the example above, the starting phrase is HDF5. This is the error * class name of the HDF5 Library. All of the library's error messages (major and minor) are in this default * error class. The Error Test in the beginning of the line above error record #000 is the name of the @@ -334,7 +327,7 @@ * * Example: The user‐defined error handler * \code - * \#define MSG_SIZE 64 + * #define MSG_SIZE 64 * herr_t * custom_print_cb(unsigned n, const H5E_error2_t *err_desc, * void* client_data) @@ -345,7 +338,7 @@ * char cls[MSG_SIZE]; * const int indent = 4; * - * *** Get descriptions for the major and minor error numbers *** + * // Get descriptions for the major and minor error numbers * if(H5Eget_class_name(err_desc->cls_id, cls, MSG_SIZE) < 0) * TEST_ERROR; * if(H5Eget_msg(err_desc->maj_num, NULL, maj, MSG_SIZE) < 0) @@ -411,13 +404,13 @@ * * Example: Create an error class and error messages * \code - * *** Create an error class *** + * // Create an error class * class_id = H5Eregister_class(ERR_CLS_NAME, PROG_NAME, PROG_VERS); - * *** Retrieve class name *** + * // Retrieve class name * H5Eget_class_name(class_id, cls_name, cls_size); - * *** Create a major error message in the class *** + * // Create a major error message in the class * maj_id = H5Ecreate_msg(class_id, H5E_MAJOR, “... ...”); - * *** Create a minor error message in the class *** + * // Create a minor error message in the class * min_id = H5Ecreate_msg(class_id, H5E_MINOR, “... ...”); * \endcode * @@ -486,14 +479,14 @@ * * Example: Pushing an error message to an error stack * \code - * *** Make call to HDF5 I/O routine *** + * // Make call to HDF5 I/O routine * if((dset_id=H5Dopen(file_id, dset_name, access_plist)) < 0) * { - * *** Push client error onto error stack *** + * // Push client error onto error stack * H5Epush(H5E_DEFAULT,__FILE__,FUNC,__LINE__,cls_id, * CLIENT_ERR_MAJ_IO,CLIENT_ERR_MINOR_OPEN, “H5Dopen failed”); * } - * *** Indicate error occurred in function *** + * // Indicate error occurred in function * return 0; * \endcode * @@ -504,15 +497,15 @@ * \code * if (H5Dwrite(dset_id, mem_type_id, mem_space_id, file_space_id, dset_xfer_plist_id, buf) < 0) * { - * *** Push client error onto error stack *** + * // Push client error onto error stack * H5Epush2(H5E_DEFAULT,__FILE__,FUNC,__LINE__,cls_id, * CLIENT_ERR_MAJ_IO,CLIENT_ERR_MINOR_HDF5, * “H5Dwrite failed”); - * *** Preserve the error stack by assigning an object handle to it *** + * // Preserve the error stack by assigning an object handle to it * error_stack = H5Eget_current_stack(); - * *** Close dataset *** + * // Close dataset * H5Dclose(dset_id); - * *** Replace the current error stack with the preserved one *** + * // Replace the current error stack with the preserved one * H5Eset_current_stack(error_stack); * } * return 0; @@ -545,7 +538,7 @@ * error stack. The error stack is statically allocated to reduce the * complexity of handling errors within the \ref H5E package. * - * @see sec_error + * @see \ref sec_error * */ diff --git a/src/H5Fmodule.h b/src/H5Fmodule.h index 5cb4a05dd7f..c9f1b31ceac 100644 --- a/src/H5Fmodule.h +++ b/src/H5Fmodule.h @@ -43,7 +43,7 @@ * \li The use of low-level file drivers * * This chapter assumes an understanding of the material presented in the data model chapter. For - * more information, @see @ref sec_data_model. + * more information, see \ref sec_data_model. * * \subsection subsec_file_access_modes File Access Modes * There are two issues regarding file access: @@ -101,7 +101,7 @@ * a user-definable data block; the size of data address parameters; properties of the B-trees that are * used to manage the data in the file; and certain HDF5 Library versioning information. * - * For more information, @see @ref subsubsec_file_property_lists_props. + * For more information, see \ref subsubsec_file_property_lists_props. * * This section has a more detailed discussion of file creation properties. If you have no special * requirements for these file characteristics, you can simply specify #H5P_DEFAULT for the default @@ -112,7 +112,7 @@ * settings, and parallel I/O. Data alignment, metadata block and cache sizes, and data sieve buffer * size are factors in improving I/O performance. * - * For more information, @see @ref subsubsec_file_property_lists_access. + * For more information, see \ref subsubsec_file_property_lists_access. * * This section has a more detailed discussion of file access properties. If you have no special * requirements for these file access characteristics, you can simply specify #H5P_DEFAULT for the @@ -466,8 +466,9 @@ * remain valid. Each of these file identifiers must be released by calling #H5Fclose when it is no * longer needed. * - * For more information, @see @ref subsubsec_file_property_lists_access. - * For more information, @see @ref subsec_file_property_lists. + * For more information, see \ref subsubsec_file_property_lists_access. + * + * For more information, see \ref subsec_file_property_lists. * * \subsection subsec_file_closes Closing an HDF5 File * #H5Fclose both closes a file and releases the file identifier returned by #H5Fopen or #H5Fcreate. @@ -512,7 +513,7 @@ * information for every property list function is provided in the \ref H5P * section of the HDF5 Reference Manual. * - * For more information, @see @ref sec_plist. + * For more information, @see \ref sec_plist. * * \subsubsection subsubsec_file_property_lists_create Creating a Property List * If you do not wish to rely on the default file creation and access properties, you must first create @@ -594,7 +595,7 @@ * \subsubsection subsubsec_file_property_lists_access File Access Properties * This section discusses file access properties that are not related to the low-level file drivers. File * drivers are discussed separately later in this chapter. - * For more information, @see @ref subsec_file_alternate_drivers. + * For more information, @see \ref subsec_file_alternate_drivers. * * File access property lists control various aspects of file I/O and structure. * @@ -657,7 +658,7 @@ * * HDF5 employs an extremely flexible mechanism called the virtual file layer, or VFL, for file * I/O. A full understanding of the VFL is only necessary if you plan to write your own drivers - * @see \ref VFL in the HDF5 Technical Notes. + * see \ref VFL in the HDF5 Technical Notes. * * For our * purposes here, it is sufficient to know that the low-level drivers used for file I/O reside in the @@ -690,7 +691,7 @@ * * If an application requires a special-purpose low-level driver, the VFL provides a public API for * creating one. For more information on how to create a driver, - * @see @ref VFL in the HDF5 Technical Notes. + * see \ref VFL in the HDF5 Technical Notes. * * \subsubsection subsubsec_file_alternate_drivers_id Identifying the Previously‐used File Driver * When creating a new HDF5 file, no history exists, so the file driver must be specified if it is to be @@ -888,11 +889,11 @@ * * Additional parameters may be added to these functions in the future. * - * @see + * see * HDF5 File Image Operations * section for information on more advanced usage of the Memory file driver, and - * @see + * see * Modified Region Writes * section for information on how to set write operations so that only modified regions are written * to storage. @@ -1070,7 +1071,7 @@ * name is FILE. If the function does not find an existing file, it will create one. If it does find an * existing file, it will empty the file in preparation for a new set of data. The identifier for the * "new" file will be passed back to the application program. - * For more information, @see @ref subsec_file_access_modes. + * For more information, @see \ref subsec_file_access_modes. * * Creating a file with default creation and access properties * \code @@ -1182,7 +1183,7 @@ * Note: In the code example above, loc_id is the file identifier for File1, /B is the link path to the * group where File2 is mounted, child_id is the file identifier for File2, and plist_id is a property * list identifier. - * For more information, @see @ref sec_group. + * For more information, @see \ref sec_group. * * See the entries for #H5Fmount, #H5Funmount, and #H5Lcreate_external in the HDF5 Reference Manual. * diff --git a/src/H5Gmodule.h b/src/H5Gmodule.h index a06d44cea75..49fc9ed9472 100644 --- a/src/H5Gmodule.h +++ b/src/H5Gmodule.h @@ -722,7 +722,7 @@ * *

      Mounting a File

      * An external link is a permanent connection between two files. A temporary connection can be set - * up with the #H5Fmount function. For more information, @see sec_file. + * up with the #H5Fmount function. For more information, @see \ref sec_file. * For more information, see the #H5Fmount function in the \ref RM. * * \subsubsection subsubsec_group_program_info Discovering Information about Objects diff --git a/src/H5PLmodule.h b/src/H5PLmodule.h index f034e7c6631..1aedc2783fe 100644 --- a/src/H5PLmodule.h +++ b/src/H5PLmodule.h @@ -276,10 +276,12 @@ * \endcode * * See the documentation at - * hdf5_plugins/docs folder. In + * hdf5_plugins/docs folder. In * particular: - * INSTALL_With_CMake - * USING_HDF5_AND_CMake + * INSTALL_With_CMake + * USING_HDF5_AND_CMake */ /** diff --git a/src/H5Pmodule.h b/src/H5Pmodule.h index ef300f9312a..8ac6f86eed9 100644 --- a/src/H5Pmodule.h +++ b/src/H5Pmodule.h @@ -979,7 +979,7 @@ *
      * \snippet{doc} tables/propertyLists.dox lcpl_table *
      - * @see STRCPL + * @see @ref STRCPL * * \defgroup ACPL Attribute Creation Properties * \ingroup STRCPL @@ -988,7 +988,7 @@ * \snippet{doc} tables/propertyLists.dox acpl_table *

    J!}n{wtAh@vmD*4_AW9 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 z%0D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π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

    * - * @see STRCPL + * @see @ref STRCPL * * \defgroup LAPL Link Access Properties * \ingroup H5P diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 320f55d9368..4d376c2b6be 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -5205,7 +5205,7 @@ H5_DLL herr_t H5Pset_mdc_config(hid_t plist_id, H5AC_cache_config_t *config_ptr) * current state of the logging flags. * * The log format is described in [Metadata Cache Logging] - * (https://\DSPURL/Fine-tuning+the+Metadata+Cache). + * (https://\DOCURL/advanced_topics/Fine-tuning+the+Metadata+Cache). * * \since 1.10.0 * diff --git a/src/H5Smodule.h b/src/H5Smodule.h index 2dc8fe127d6..b9897485405 100644 --- a/src/H5Smodule.h +++ b/src/H5Smodule.h @@ -53,7 +53,7 @@ * sub‐sampling, and scatter‐gather access to datasets. * * \subsection subsec_dataspace_function Dataspace Function Summaries - * @see H5S reference manual provides a reference list of dataspace functions, the H5S APIs. + * see \ref H5S reference manual provides a reference list of dataspace functions, the H5S APIs. * * \subsection subsec_dataspace_program Definition of Dataspace Objects and the Dataspace Programming Model * @@ -977,9 +977,9 @@ * \subsection subsec_dataspace_refer References * * Another use of selections is to store a reference to a region of a dataset in the file or an external file. - An HDF5 object reference + * An HDF5 object reference * object is a pointer to an object (attribute, dataset, group, or committed datatype) in the file or an - external file. A selection can + * external file. A selection can * be used to create a pointer to a set of selected elements of a dataset, called a region reference. The * selection can be either a point selection or a hyperslab selection. * @@ -990,13 +990,179 @@ * To discover the elements and/or read the data, the region reference can be dereferenced to obtain the * identifiers for the dataset and dataspace. * - * For more information, \see subsubsec_datatype_other_refs. + * For more information, \see \ref subsubsec_datatype_other_refs. * * \subsubsection subsubsec_dataspace_refer_use Example Uses for Region References + * Region references are used to implement stored pointers to data within a dataset. For example, features + * in a large dataset might be indexed by a table. See the figure below. This table could be stored as an + * HDF5 dataset with a compound datatype, for example, with a field for the name of the feature and a region + * reference to point to the feature in the dataset. See the second figure below. + * + * + * + * + * + *
    + * \image html Dspace_features.gif " Features indexed by a table" + *
    + * + * + * + * + * + *
    + * \image html Dspace_features_cmpd.gif "Storing the table with a compound datatype" + *
    * * \subsubsection subsubsec_dataspace_refer_create Creating References to Regions + * To create a region reference: + * \li 1. Create or open the dataset that contains the region + * \li 2. Get the dataspace for the dataset + * \li 3. Define a selection that specifies the region + * \li 4. Create a region reference using the dataset and dataspace with selection + * \li 5. Write the region reference(s) to the desired dataset or attribute + * \li 6. Release the region reference(s) + * + * The figure below shows a diagram of a file with three datasets. Dataset D1 and D2 are two dimensional + * arrays of integers. Dataset R1 is a one dimensional array of references to regions in D1 and D2. The + * regions can be any valid selection of the dataspace of the target dataset. + * + * + * + * + *
    + * \image html Dspace_three_datasets.gif "A file with three datasets" + *
    + * Note: In the figure above, R1 is a 1 D array of region pointers; each pointer refers to a selection + * in one dataset. + * + * The example below shows code to create the array of region references. The references are created in an + * array of type #H5R_ref_t. Each region is defined as a selection on the dataspace of the dataset, + * and a reference is created using \ref H5Rcreate_region(). The call to \ref H5Rcreate_region() specifies the + file, + * dataset, and the dataspace with selection. + * + * Create an array of region references + * \code + * // create an array of 4 region references + * H5R_ref_t ref[4]; + * + * // Create a reference to the first hyperslab in the first Dataset. + * offset[0] = 1; offset[1] = 1; + * count[0] = 3; count[1] = 2; + * status = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, offset, NULL, count, NULL); + * status = H5Rcreate_region(file_id, "D1", space_id, H5P_DEFAULT, &ref[0]); + * + * // The second reference is to a union of hyperslabs in the first Dataset + * offset[0] = 5; offset[1] = 3; + * count[0] = 1; count[1] = 4; + * status = H5Sselect_none(space_id); + * status = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, offset, NULL, count, NULL); + * offset[0] = 6; offset[1] = 5; + * count[0] = 1; count[1] = 2; + * status = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, offset, NULL, count, NULL); + * status = H5Rcreate_region(file_id, "D1", space_id, H5P_DEFAULT, &ref[1]); + * + * // the fourth reference is to a selection of points in the first Dataset + * status = H5Sselect_none(space_id); + * coord[0][0] = 4; coord[0][1] = 4; + * coord[1][0] = 2; coord[1][1] = 6; + * coord[2][0] = 3; coord[2][1] = 7; + * coord[3][0] = 1; coord[3][1] = 5; + * coord[4][0] = 5; coord[4][1] = 8; + * + * status = H5Sselect_elements(space_id, H5S_SELECT_SET, num_points, (const hssize_t **)coord); + * status = H5Rcreate_region(file_id, "D1", space_id, H5P_DEFAULT, &ref[3]); + * + * // the third reference is to a hyperslab in the second Dataset + * offset[0] = 0; offset[1] = 0; + * count[0] = 4; count[1] = 6; + * status = H5Sselect_hyperslab(space_id2, H5S_SELECT_SET, offset, NULL, count, NULL); + * status = H5Rcreate_region(file_id, "D2", space_id2, H5P_DEFAULT, &ref[2]); + * \endcode + * + * When all the references are created, the array of references is written to the dataset R1. The + * dataset is declared to have datatype #H5T_STD_REF. See the example below. Also, note the release + * of the references afterwards. + * + * Write the array of references to a dataset + * \code + * Hsize_t dimsr[1]; + * dimsr[0] = 4; + * + * // Dataset with references. + * spacer_id = H5Screate_simple(1, dimsr, NULL); + * dsetr_id = H5Dcreate(file_id, "R1", H5T_STD_REF_DSETREG, spacer_id, H5P_DEFAULT, H5P_DEFAULT, + * H5P_DEFAULT); + * + * // Write dataset with the references. + * status = H5Dwrite(dsetr_id, H5T_STD_REF_DSETREG, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref); + * + * status = H5Rdestroy(&ref[0]); + * status = H5Rdestroy(&ref[1]); + * status = H5Rdestroy(&ref[0]); + * status = H5Rdestroy(&ref[1]); + * \endcode + * + * When creating region references, the following rules are enforced. + * \li The selection must be a valid selection for the target dataset, just as when transferring data + * \li The dataset must exist in the file when the reference is created; #H5Rcreate_region + * \li The target dataset must be in the same file as the stored reference * * \subsubsection subsubsec_dataspace_refer_read Reading References to Regions + * To retrieve data from a region reference, the reference must be read from the file, and then the data can + * be retrieved. The steps are: + * \li 1. Open the dataset or attribute containing the reference objects + * \li 2. Read the reference object(s) + * \li 3. For each region reference, get the dataset (#H5Ropen_object) and dataspace (#H5Ropen_region) + * \li 4. Use the dataspace and datatype to discover what space is needed to store the data, allocate the + * correct storage and create a dataspace and datatype to define the memory data layout + * \li 5. Release the region reference(s) + * + * The example below shows code to read an array of region references from a dataset, and then read the + * data from the first selected region. Note that the region reference has information that records the + * dataset (within the file) and the selection on the dataspace of the dataset. After dereferencing the + * regions reference, the datatype, number of points, and some aspects of the selection can be discovered. + * (For a union of hyperslabs, it may not be possible to determine the exact set of hyperslabs that has been + * combined.) + * The table below the code example shows the inquiry functions. + * + * When reading data from a region reference, the following rules are enforced: + * \li The target dataset must be present and accessible in the file + * \li The selection must be a valid selection for the dataset + * + * Read an array of region references; read from the first selection + * \code + * dsetr_id = H5Dopen (file_id, "R1", H5P_DEFAULT); + * status = H5Dread(dsetr_id, H5T_STD, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref_out); + * + * // Dereference the first reference. + * // 1) get the dataset (H5Ropen_object) + * // 2) get the selected dataspace (H5Ropen_region) + * + * dsetv_id = H5Ropen_object(&ref_out[0], H5P_DEFAULT, H5P_DEFAULT); + * space_id = H5Ropen_region(&ref_out[0], H5P_DEFAULT, H5P_DEFAULT); + * + * // Discover how many points and shape of the data + * ndims = H5Sget_simple_extent_ndims(space_id); + * H5Sget_simple_extent_dims(space_id,dimsx,NULL); + * + * // Read and display hyperslab selection from the dataset. + * dimsy[0] = H5Sget_select_npoints(space_id); + * spacex_id = H5Screate_simple(1, dimsy, NULL); + * + * status = H5Dread(dsetv_id, H5T_NATIVE_INT, H5S_ALL, space_id, H5P_DEFAULT, data_out); + * printf("Selected hyperslab: "); + * for (i = 0; i < 8; i++) { + * printf("\n"); + * for (j = 0; j < 10; j++) + * printf("%d ", data_out[i][j]); + * } + * printf("\n"); + * + * status = H5Rdestroy(&ref_out[0]); + * \endcode + * * * \subsection subsec_dataspace_deprecated_refer Deprecated References to Dataset Regions * The API described in this section was deprecated since HDF5 1.12.0. Shown are @@ -1016,34 +1182,7 @@ * retrieved with a call to #H5Rget_region(). The selected dataspace can be used to read the selected data * elements. * - * For more information, \see subsubsec_datatype_other_refs. - * - * \subsubsection subsubsec_dataspace_deprecated_refer_use Deprecated Example Uses for Region References - * - * Region references are used to implement stored pointers to data within a dataset. For example, features - * in a large dataset might be indexed by a table. See the figure below. This table could be stored as an - * HDF5 dataset with a compound datatype, for example, with a field for the name of the feature and a region - * reference to point to the feature in the dataset. See the second figure below. - * - * - * - * - * - *
    - * \image html Dspace_features.gif " Features indexed by a table" - *
    - * - * - * - * - * - *
    - * \image html Dspace_features_cmpd.gif "Storing the table with a compound datatype" - *
    - * - * * \subsubsection subsubsec_dataspace_deprecated_refer_create Deprecated Creating References to Regions - * * To create a region reference: * \li 1. Create or open the dataset that contains the region * \li 2. Get the dataspace for the dataset @@ -1183,6 +1322,7 @@ * printf("\n"); * \endcode * + * \subsection subsec_dataspace_funcs Functions * * * @@ -1243,7 +1383,6 @@ * *
    The inquiry functions
    * - * * \subsection subsec_dataspace_sample Sample Programs * * This section contains the full programs from which several of the code examples in this chapter were diff --git a/src/H5Tmodule.h b/src/H5Tmodule.h index 636679e8380..3e121469108 100644 --- a/src/H5Tmodule.h +++ b/src/H5Tmodule.h @@ -304,7 +304,7 @@ * * * - * @see H5R + * @see @ref H5R * * * @@ -971,7 +971,7 @@ * translated to and from standard types of the same class, as described above. * * \subsection subsec_datatype_function Datatype Function Summaries - * @see H5T reference manual provides a reference list of datatype functions, the H5T APIs. + * see \ref H5T reference manual provides a reference list of datatype functions, the H5T APIs. * * \subsection subsec_datatype_program Programming Model for Datatypes * The HDF5 Library implements an object-oriented model of datatypes. HDF5 datatypes are @@ -2164,6 +2164,7 @@ filled according to the value of this property. The padding can be: * \endcode * * The example below shows the content of the file written on a little-endian machine. + * * Create and write a little-endian dataset with a compound datatype in C * \code * HDF5 “SDScompound.h5” { @@ -2248,6 +2249,7 @@ filled according to the value of this property. The padding can be: * * The figure below shows the content of the file written on a little-endian machine. Only float and * double fields are written. The default fill value is used to initialize the unwritten integer field. + * * Writing floats and doubles to a dataset on a little-endian system * \code * HDF5 “SDScompound.h5” { @@ -2285,6 +2287,7 @@ filled according to the value of this property. The padding can be: * compound datatype. As this example illustrates, writing and reading compound datatypes in * Fortran is always done by fields. The content of the written file is the same as shown in the * example above. + * * Create and write a dataset with a compound datatype in Fortran * \code * ! One cannot write an array of a derived datatype in @@ -2921,6 +2924,7 @@ filled according to the value of this property. The padding can be: * declaration of a datatype of type #H5T_C_S1 which is set to #H5T_VARIABLE. The HDF5 * Library automatically translates between this and the vl_t structure. Note: the #H5T_VARIABLE * size can only be used with string datatypes. + * * Set the string datatype size to H5T_VARIABLE * \code * tid1 = H5Tcopy (H5T_C_S1); @@ -2929,6 +2933,7 @@ filled according to the value of this property. The padding can be: * * Variable-length strings can be read into C strings (in other words, pointers to zero terminated * arrays of char). See the example below. + * * Read variable-length strings into C strings * \code * char *rdata[SPACE1_DIM1]; @@ -3053,6 +3058,7 @@ filled according to the value of this property. The padding can be: * would be as an array of integers. The example below shows an example of how to create an * enumeration with five elements. The elements map symbolic names to 2-byte integers. See the * table below. + * * Create an enumeration with five elements * \code * hid_t hdf_en_colors; @@ -3582,6 +3588,7 @@ filled according to the value of this property. The padding can be: * * To create two or more datasets that share a common datatype, first commit the datatype, and then * use that datatype to create the datasets. See the example below. + * * Create a shareable datatype * \code * hid_t t1 = ...some transient type...; @@ -3697,6 +3704,7 @@ filled according to the value of this property. The padding can be: * memory. The destination datatype must be specified in the #H5Dread call. The example below * shows an example of reading a dataset of 32-bit integers. The figure below the example shows * the data transformation that is performed. + * * Specify the destination datatype with H5Dread * \code * // Stored as H5T_STD_BE32 @@ -3797,6 +3805,7 @@ filled according to the value of this property. The padding can be: * The currently supported text format used by #H5LTtext_to_dtype and #H5LTdtype_to_text is the * data description language (DDL) and conforms to the \ref DDLBNF114. The portion of the * \ref DDLBNF114 that defines HDF5 datatypes appears below. + * * The definition of HDF5 datatypes from the HDF5 DDL * \code * ::= | | | diff --git a/src/H5module.h b/src/H5module.h index a7aa05a0644..083f40005c7 100644 --- a/src/H5module.h +++ b/src/H5module.h @@ -28,6 +28,7 @@ /** \page H5DM_UG HDF5 Data Model and File Structure * * \section sec_data_model The HDF5 Data Model and File Structure + * * \subsection subsec_data_model_intro Introduction * The Hierarchical Data Format (HDF) implements a model for managing and storing data. The * model includes an abstract data model and an abstract storage model (the data format), and @@ -100,8 +101,11 @@ * model, and stored in a storage medium. The stored objects include header blocks, free lists, data * blocks, B-trees, and other objects. Each group or dataset is stored as one or more header and data * blocks. - * @see HDF5 File Format Specification - * for more information on how these objects are organized. The HDF5 library can also use other + * + * For more information on how these objects are organized; + * see HDF5 File Format Specification + * + * The HDF5 library can also use other * libraries and modules such as compression. * * diff --git a/tools/src/h5dump/h5dump.c b/tools/src/h5dump/h5dump.c index dc86e526294..bb916d9fb1f 100644 --- a/tools/src/h5dump/h5dump.c +++ b/tools/src/h5dump/h5dump.c @@ -336,7 +336,7 @@ usage(const char *prog) PRINTVALSTREAM( rawoutstream, " " - "https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html.\n"); + "https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html.\n"); PRINTVALSTREAM(rawoutstream, " Without the file driver flag, the file will be opened with each driver in\n"); PRINTVALSTREAM(rawoutstream, " turn and in the order specified above until one driver succeeds\n"); diff --git a/tools/test/h5dump/expected/h5dump-help.txt b/tools/test/h5dump/expected/h5dump-help.txt index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/h5dump-help.txt +++ b/tools/test/h5dump/expected/h5dump-help.txt @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl b/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl +++ b/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl b/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl b/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl b/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl b/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl b/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl b/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl index a78d8d820ec..694bc6ae975 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://portal.hdfgroup.org/documentation/hdf5-docs/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. From 0a9c1e69d8f2a064fede7a2e9f41ec19be06fd36 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Fri, 30 Aug 2024 11:06:52 -0500 Subject: [PATCH 52/94] Fix grammar and simplify comment in H5Fint.c (#4790) --- src/H5Fint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Fint.c b/src/H5Fint.c index 190d1b25486..f653e0b71f0 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -1985,7 +1985,7 @@ H5F_open(bool try, H5F_t **_file, const char *name, unsigned flags, hid_t fcpl_i if ((ci_load || ci_write) && (flags & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE))) HGOTO_ERROR(H5E_FILE, H5E_UNSUPPORTED, FAIL, "can't have both SWMR and cache image"); - /* Retain the name the file was opened with */ + /* Retain the original filename. */ file->open_name = H5MM_xstrdup(name); /* Short cuts */ From e66ec4f5eebdba86679b3994271e71187592ea02 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 30 Aug 2024 14:11:01 -0500 Subject: [PATCH 53/94] Resolve race around single counter by using two counters (#4792) --- test/ttsafe_semaphore.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/ttsafe_semaphore.c b/test/ttsafe_semaphore.c index 37c8ed29941..b8a3dece723 100644 --- a/test/ttsafe_semaphore.c +++ b/test/ttsafe_semaphore.c @@ -20,14 +20,15 @@ #if defined(H5_HAVE_THREADS) -#define NUM_PINGPONG (500 * 1000) +#define NUM_PINGPONG (250 * 1000) #define NUM_CLIENTSERVER (50 * 1000) #define NUM_THREADS 16 typedef struct { H5TS_semaphore_t ping_sem, pong_sem; - H5TS_atomic_uint_t counter; + H5TS_atomic_uint_t ping_counter; + H5TS_atomic_uint_t pong_counter; } pingpong_t; typedef struct { @@ -47,11 +48,11 @@ ping(void *_test_info) result = H5TS_semaphore_wait(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_wait"); - H5TS_atomic_fetch_add_uint(&test_info->counter, (unsigned)1); + H5TS_atomic_fetch_add_uint(&test_info->ping_counter, (unsigned)1); result = H5TS_semaphore_signal(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (H5TS_atomic_load_uint(&test_info->counter) < NUM_PINGPONG); + } while (H5TS_atomic_load_uint(&test_info->ping_counter) < NUM_PINGPONG); return ret_value; } @@ -67,11 +68,11 @@ pong(void *_test_info) result = H5TS_semaphore_wait(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_wait"); - H5TS_atomic_fetch_add_uint(&test_info->counter, (unsigned)1); + H5TS_atomic_fetch_add_uint(&test_info->pong_counter, (unsigned)1); result = H5TS_semaphore_signal(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (H5TS_atomic_load_uint(&test_info->counter) < NUM_PINGPONG); + } while (H5TS_atomic_load_uint(&test_info->pong_counter) < NUM_PINGPONG); return ret_value; } @@ -93,7 +94,8 @@ tts_semaphore_pingpong(void) CHECK_I(result, "H5TS_semaphore_init"); result = H5TS_semaphore_init(&test_info.pong_sem, 0); CHECK_I(result, "H5TS_semaphore_init"); - H5TS_atomic_init_uint(&test_info.counter, (unsigned)0); + H5TS_atomic_init_uint(&test_info.ping_counter, (unsigned)0); + H5TS_atomic_init_uint(&test_info.pong_counter, (unsigned)0); /* Start ping & pong threads */ result = H5TS_thread_create(&ping_thread, ping, &test_info); @@ -111,7 +113,8 @@ tts_semaphore_pingpong(void) result = H5TS_thread_join(pong_thread, NULL); CHECK_I(result, "H5TS_thread_join"); - VERIFY(H5TS_atomic_load_uint(&test_info.counter), (NUM_PINGPONG + 1), "ping pong"); + VERIFY(H5TS_atomic_load_uint(&test_info.ping_counter), NUM_PINGPONG, "ping counter"); + VERIFY(H5TS_atomic_load_uint(&test_info.pong_counter), NUM_PINGPONG, "pong counter"); /* Destroy semaphores, etc. */ result = H5TS_semaphore_destroy(&test_info.ping_sem); @@ -119,7 +122,8 @@ tts_semaphore_pingpong(void) result = H5TS_semaphore_destroy(&test_info.pong_sem); CHECK_I(result, "H5TS_semaphore_destroy"); - H5TS_atomic_destroy_uint(&test_info.counter); + H5TS_atomic_destroy_uint(&test_info.ping_counter); + H5TS_atomic_destroy_uint(&test_info.pong_counter); } /* end tts_semaphore_pingpong() */ static H5TS_THREAD_RETURN_TYPE From 008b7ba708e4e9faa55e15e11d95c42b124e74e2 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Fri, 30 Aug 2024 14:13:06 -0500 Subject: [PATCH 54/94] Fix char-subscripts warnings in H5private.h (#4793) --- src/H5private.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/H5private.h b/src/H5private.h index ab005067668..9950d0ccadc 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1129,34 +1129,34 @@ H5_DLL herr_t H5_trace_args(struct H5RS_str_t *rs, const char *type, va_list ap) * Handles H5XY_. */ #define H5_IS_API(S) \ - ('_' != ((const char *)S)[2] /* underscore at position 2 */ \ - && '_' != ((const char *)S)[3] /* underscore at position 3 */ \ - && !( /* NOT */ \ - ((const char *)S)[4] /* pos 4 exists */ \ - && (isupper(S[3]) || isdigit(S[3])) /* pos 3 dig | uc */ \ - && '_' == ((const char *)S)[4] /* pos 4 underscore */ \ + ('_' != ((const char *)S)[2] /* underscore at position 2 */ \ + && '_' != ((const char *)S)[3] /* underscore at position 3 */ \ + && !( /* NOT */ \ + ((const char *)S)[4] /* pos 4 exists */ \ + && (isupper((int)S[3]) || isdigit((int)S[3])) /* pos 3 dig | uc */ \ + && '_' == ((const char *)S)[4] /* pos 4 underscore */ \ )) /* `S' is the name of a function which is being tested to check if it's */ /* a public API function */ #define H5_IS_PUB(S) \ - (((isdigit(S[1]) || isupper(S[1])) && islower(S[2])) || \ - ((isdigit(S[2]) || isupper(S[2])) && islower(S[3])) || \ - (!S[4] || ((isdigit(S[3]) || isupper(S[3])) && islower(S[4])))) + (((isdigit((int)S[1]) || isupper((int)S[1])) && islower((int)S[2])) || \ + ((isdigit((int)S[2]) || isupper((int)S[2])) && islower((int)S[3])) || \ + (!S[4] || ((isdigit((int)S[3]) || isupper((int)S[3])) && islower((int)S[4])))) /* `S' is the name of a function which is being tested to check if it's */ /* a private library function */ #define H5_IS_PRIV(S) \ - (((isdigit(S[1]) || isupper(S[1])) && '_' == S[2] && islower(S[3])) || \ - ((isdigit(S[2]) || isupper(S[2])) && '_' == S[3] && islower(S[4])) || \ - ((isdigit(S[3]) || isupper(S[3])) && '_' == S[4] && islower(S[5]))) + (((isdigit((int)S[1]) || isupper((int)S[1])) && '_' == S[2] && islower((int)S[3])) || \ + ((isdigit((int)S[2]) || isupper((int)S[2])) && '_' == S[3] && islower((int)S[4])) || \ + ((isdigit((int)S[3]) || isupper((int)S[3])) && '_' == S[4] && islower((int)S[5]))) /* `S' is the name of a function which is being tested to check if it's */ /* a package private function */ #define H5_IS_PKG(S) \ - (((isdigit(S[1]) || isupper(S[1])) && '_' == S[2] && '_' == S[3] && islower(S[4])) || \ - ((isdigit(S[2]) || isupper(S[2])) && '_' == S[3] && '_' == S[4] && islower(S[5])) || \ - ((isdigit(S[3]) || isupper(S[3])) && '_' == S[4] && '_' == S[5] && islower(S[6]))) + (((isdigit((int)S[1]) || isupper((int)S[1])) && '_' == S[2] && '_' == S[3] && islower((int)S[4])) || \ + ((isdigit((int)S[2]) || isupper((int)S[2])) && '_' == S[3] && '_' == S[4] && islower((int)S[5])) || \ + ((isdigit((int)S[3]) || isupper((int)S[3])) && '_' == S[4] && '_' == S[5] && islower((int)S[6]))) /* global library version information string */ extern char H5_lib_vers_info_g[]; From 2fdf713de6f33b77b6a4a69fb434c2f17839d2da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 07:48:37 -0500 Subject: [PATCH 55/94] Bump the github-actions group with 3 updates (#4798) Bumps the github-actions group with 3 updates: [actions/checkout](https://github.com/actions/checkout), [DoozyX/clang-format-lint-action](https://github.com/doozyx/clang-format-lint-action) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 4.1.1 to 4.1.7 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4.1.1...v4.1.7) Updates `DoozyX/clang-format-lint-action` from 0.17 to 0.18 - [Release notes](https://github.com/doozyx/clang-format-lint-action/releases) - [Commits](https://github.com/doozyx/clang-format-lint-action/compare/v0.17...v0.18) Updates `github/codeql-action` from 3.25.15 to 3.26.6 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/afb54ba388a7dca6ecae48f608c4ff05ff4cc77a...4dd16135b69a43b6c8efb853346f8437d92d3c93) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: DoozyX/clang-format-lint-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/clang-format-check.yml | 2 +- .github/workflows/clang-format-fix.yml | 4 ++-- .github/workflows/julia-auto.yml | 4 ++-- .github/workflows/julia-cmake.yml | 4 ++-- .github/workflows/publish-branch.yml | 2 +- .github/workflows/publish-release.yml | 2 +- .github/workflows/release-files.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index c4d68a8f004..78146ed932b 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v4.1.7 - name: Run clang-format style check for C and Java code - uses: DoozyX/clang-format-lint-action@v0.17 + uses: DoozyX/clang-format-lint-action@v0.18 with: source: '.' extensions: 'c,h,cpp,hpp,java' diff --git a/.github/workflows/clang-format-fix.yml b/.github/workflows/clang-format-fix.yml index 2ce9f6e9dad..75789e0f4e0 100644 --- a/.github/workflows/clang-format-fix.yml +++ b/.github/workflows/clang-format-fix.yml @@ -21,9 +21,9 @@ jobs: permissions: contents: write # In order to allow EndBug/add-and-commit to commit changes steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 - name: Fix C and Java formatting issues detected by clang-format - uses: DoozyX/clang-format-lint-action@d3c7f85989e3b6416265a0d12f8b4a8aa8b0c4ff # v0.13 + uses: DoozyX/clang-format-lint-action@caa179272c6ee7f1d25dfb503ee0c410c26ebd98 # v0.13 with: source: '.' extensions: 'c,h,cpp,hpp,java' diff --git a/.github/workflows/julia-auto.yml b/.github/workflows/julia-auto.yml index a7dd2ab15b9..f21fd659413 100644 --- a/.github/workflows/julia-auto.yml +++ b/.github/workflows/julia-auto.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Get Sources - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.7 - name: Install Dependencies shell: bash @@ -60,7 +60,7 @@ jobs: arch: 'x64' - name: Get julia hdf5 source - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.7 with: repository: JuliaIO/HDF5.jl path: . diff --git a/.github/workflows/julia-cmake.yml b/.github/workflows/julia-cmake.yml index c1306d6a381..113b81bd70c 100644 --- a/.github/workflows/julia-cmake.yml +++ b/.github/workflows/julia-cmake.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Get Sources - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.7 - name: Install Dependencies shell: bash @@ -63,7 +63,7 @@ jobs: arch: 'x64' - name: Get julia hdf5 source - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.7 with: repository: JuliaIO/HDF5.jl path: . diff --git a/.github/workflows/publish-branch.yml b/.github/workflows/publish-branch.yml index 1e5b99bd0b0..6c52c75308a 100644 --- a/.github/workflows/publish-branch.yml +++ b/.github/workflows/publish-branch.yml @@ -22,7 +22,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Get Sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 with: fetch-depth: 0 ref: '${{ github.head_ref || github.ref_name }}' diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index c153d217d87..dd7f4bfbc86 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -26,7 +26,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Get Sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 with: fetch-depth: 0 ref: '${{ github.head_ref || github.ref_name }}' diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index b2d6234a3bb..d2cde576a50 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -40,7 +40,7 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Get Sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 with: fetch-depth: 0 ref: '${{ github.head_ref || github.ref_name }}' diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index e67627fd885..d59f8c9bc6b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -32,7 +32,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 with: persist-credentials: false @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 with: sarif_file: results.sarif From 23be95fdd5f6b620e440bb2eee53a8d637495518 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Tue, 3 Sep 2024 07:51:57 -0500 Subject: [PATCH 56/94] Fix typo argueably in H5Cprivate.h (#4795) --- src/H5Cprivate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index 9f123123bc6..d7065799a67 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -903,7 +903,7 @@ typedef herr_t (*H5C_log_flush_func_t)(H5C_t *cache_ptr, haddr_t addr, bool was_ * * Note that flush dependencies are used to order flushes within rings. * - * Note also that at the conceptual level, rings are argueably superfluous, + * Note also that at the conceptual level, rings are arguably superfluous, * as a similar effect could be obtained via the flush dependency mechanism. * However, this would require all entries in the cache to participate in a * flush dependency -- with the implied setup and takedown overhead and From 33469a664cba7de87e71dc7f5db5804586595941 Mon Sep 17 00:00:00 2001 From: "H. Joe Lee" Date: Tue, 3 Sep 2024 08:00:10 -0500 Subject: [PATCH 57/94] Fix typos in H5Cpkg.h (#4796) --- src/H5Cpkg.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/H5Cpkg.h b/src/H5Cpkg.h index 208944e1053..6a636aee76c 100644 --- a/src/H5Cpkg.h +++ b/src/H5Cpkg.h @@ -1912,7 +1912,7 @@ typedef struct H5C_tag_info_t { * the hash table. Note that the index_size field (above) * is also the sum of the sizes of all entries in the cache. * Thus we should have the invariant that clean_index_size + - * dirty_index_size == index_size. + * dirty_index_size = index_size. * * WARNING: * The value of the clean_index_size must not be mistaken for @@ -1929,7 +1929,7 @@ typedef struct H5C_tag_info_t { * the hash table. Note that the index_size field (above) * is also the sum of the sizes of all entries in the cache. * Thus we should have the invariant that clean_index_size + - * dirty_index_size == index_size. + * dirty_index_size = index_size. * * dirty_index_ring_size: Array of size_t of length H5C_RING_NTYPES used to * maintain the sum of the sizes of all dirty entries in the @@ -2025,12 +2025,12 @@ typedef struct H5C_tag_info_t { * The cost of maintaining the skip list is significant. As it is only used * on flush and close, it is maintained only when needed. * - * To do this, we add a flag to control maintenanace of the skip list. + * To do this, we add a flag to control maintenance of the skip list. * This flag is initially set to false, which disables all operations * on the skip list. * * At the beginning of either flush or close, we scan the index list, - * insert all dirtly entries in the skip list, and enable operations + * insert all dirty entries in the skip list, and enable operations * on skip list by setting above control flag to true. * * In the case of a partial flush (i.e. flush tagged entries), we only From 0a7f89d5ad984d49ca64be9c773143eceaf49b77 Mon Sep 17 00:00:00 2001 From: abushwang <31229623+wswsmao@users.noreply.github.com> Date: Wed, 4 Sep 2024 00:11:07 +0800 Subject: [PATCH 58/94] Add bounds checking to avoid Out-of-bounds Write for gif2h5 (#4786) --- hl/tools/gif2h5/decompress.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hl/tools/gif2h5/decompress.c b/hl/tools/gif2h5/decompress.c index e87a60cf7af..62a22922ff4 100644 --- a/hl/tools/gif2h5/decompress.c +++ b/hl/tools/gif2h5/decompress.c @@ -296,6 +296,10 @@ Decompress(GIFIMAGEDESC *GifImageDesc, GIFHEAD *GifHead) * Build the hash table on-the-fly. No table is stored in the * file. */ + if (FreeCode >= 4096) { + printf("Error: FreeCode out of bounds\n"); + exit(EXIT_FAILURE); + } Prefix[FreeCode] = OldCode; Suffix[FreeCode] = FinChar; OldCode = InCode; From 902131faf2c11ff971d5c1ae85f1e4921d605150 Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:46:34 -0400 Subject: [PATCH 59/94] Replace non-VOL calls with VOL calls - part 5 (#4788) This PR switches H5I_object() and H5I_object_verify() to H5VL_vol_object() and H5VL_vol_object_verify(), respectively, in the H5M APIs and H5Gdeprec (was left out by mistake). This completes the fixes of issue GH-4730. --- src/H5Gdeprec.c | 26 +++++++++++++------------- src/H5M.c | 27 +++++++++++++-------------- src/H5Mpublic.h | 22 ++++++++++++++++++++-- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index 72b328c730e..6871283ed03 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -204,7 +204,7 @@ H5Gcreate1(hid_t loc_id, const char *name, size_t size_hint) loc_params.obj_type = H5I_get_type(loc_id); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Create the group */ @@ -262,7 +262,7 @@ H5Gopen1(hid_t loc_id, const char *name) loc_params.obj_type = H5I_get_type(loc_id); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Open the group */ @@ -320,7 +320,7 @@ H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name, const char *new new_loc_params.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(cur_loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(cur_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Construct a temporary VOL object */ @@ -351,7 +351,7 @@ H5Glink(hid_t cur_loc_id, H5G_link_t type, const char *cur_name, const char *new loc_params.obj_type = H5I_get_type(cur_loc_id); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(cur_loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(cur_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -409,9 +409,9 @@ H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type, hid_t new_loc_ new_loc_params.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; /* Get the location objects */ - if (NULL == (vol_obj1 = (H5VL_object_t *)H5I_object(cur_loc_id))) + if (NULL == (vol_obj1 = H5VL_vol_object(cur_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); - if (NULL == (vol_obj2 = (H5VL_object_t *)H5I_object(new_loc_id))) + if (NULL == (vol_obj2 = H5VL_vol_object(new_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -443,7 +443,7 @@ H5Glink2(hid_t cur_loc_id, const char *cur_name, H5G_link_t type, hid_t new_loc_ loc_params.obj_type = H5I_get_type(new_loc_id); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(new_loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(new_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -493,7 +493,7 @@ H5Gmove(hid_t src_loc_id, const char *src_name, const char *dst_name) loc_params2.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(src_loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(src_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Move the link */ @@ -541,11 +541,11 @@ H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *d if (H5L_SAME_LOC != src_loc_id) /* get the location object */ - if (NULL == (vol_obj1 = (H5VL_object_t *)H5I_object(src_loc_id))) + if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); if (H5L_SAME_LOC != dst_loc_id) /* get the location object */ - if (NULL == (vol_obj2 = (H5VL_object_t *)H5I_object(dst_loc_id))) + if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Move the link */ @@ -588,7 +588,7 @@ H5Gunlink(hid_t loc_id, const char *name) loc_params.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -635,7 +635,7 @@ H5Gget_linkval(hid_t loc_id, const char *name, size_t size, char *buf /*out*/) loc_params.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Set up VOL callback arguments */ @@ -1167,7 +1167,7 @@ H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char *name /*out*/, size_t size loc_params.obj_type = H5I_get_type(loc_id); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "invalid location identifier"); /* Set up VOL callback arguments */ diff --git a/src/H5M.c b/src/H5M.c index b196f0930b8..bb8b4d9882b 100644 --- a/src/H5M.c +++ b/src/H5M.c @@ -359,8 +359,7 @@ H5Mcreate_async(const char *app_file, const char *app_func, unsigned app_line, h * the in-file datatype for values is defined by VAL_TYPE_ID. * LOC_ID specifies the file to create the map object, but no * link to the object is created. Other options can be - * specified through the property lists LCPL_ID, MCPL_ID, and - * MAPL_ID. + * specified through the property lists MCPL_ID and MAPL_ID. * * The resulting ID should be linked into the file with * H5Olink or it will be deleted when closed. @@ -397,7 +396,7 @@ H5Mcreate_anon(hid_t loc_id, hid_t key_type_id, hid_t val_type_id, hid_t mcpl_id HGOTO_ERROR(H5E_MAP, H5E_CANTSET, H5I_INVALID_HID, "can't set access property list info"); /* get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid location identifier"); /* Set location parameters */ @@ -693,7 +692,7 @@ H5Mget_key_type(hid_t map_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid map identifier"); /* Set up VOL callback arguments */ @@ -737,7 +736,7 @@ H5Mget_val_type(hid_t map_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid map identifier"); /* Set up VOL callback arguments */ @@ -781,7 +780,7 @@ H5Mget_create_plist(hid_t map_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid map identifier"); /* Set up VOL callback arguments */ @@ -828,7 +827,7 @@ H5Mget_access_plist(hid_t map_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid map identifier"); /* Set up VOL callback arguments */ @@ -871,7 +870,7 @@ H5Mget_count(hid_t map_id, hsize_t *count /*out*/, hid_t dxpl_id) FUNC_ENTER_API(H5I_INVALID_HID) /* Check args */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "invalid map identifier"); /* Get the default dataset transfer property list if the user didn't provide one */ @@ -927,7 +926,7 @@ H5M__put_api_common(hid_t map_id, hid_t key_mem_type_id, const void *key, hid_t HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid value memory datatype ID"); /* Get map pointer */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "map_id is not a map ID"); /* Get the default dataset transfer property list if the user didn't provide one */ @@ -1056,7 +1055,7 @@ H5M__get_api_common(hid_t map_id, hid_t key_mem_type_id, const void *key, hid_t HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid value memory datatype ID"); /* Get map pointer */ - if (NULL == (*vol_obj_ptr = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (*vol_obj_ptr = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "map_id is not a map ID"); /* Get the default dataset transfer property list if the user didn't provide one */ @@ -1187,7 +1186,7 @@ H5Mexists(hid_t map_id, hid_t key_mem_type_id, const void *key, hbool_t *exists, HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid key memory datatype ID"); /* Get map pointer */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "map_id is not a map ID"); /* Get the default dataset transfer property list if the user didn't provide one */ @@ -1263,7 +1262,7 @@ H5Miterate(hid_t map_id, hsize_t *idx, hid_t key_mem_type_id, H5M_iterate_t op, HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified"); /* Get map pointer */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "map_id is not a map ID"); /* Get the default dataset transfer property list if the user didn't provide one */ @@ -1348,7 +1347,7 @@ H5Miterate_by_name(hid_t loc_id, const char *map_name, hsize_t *idx, hid_t key_m HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no operator specified"); /* Get the location object */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object(loc_id))) + if (NULL == (vol_obj = H5VL_vol_object(loc_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Get the default dataset transfer property list if the user didn't provide one */ @@ -1412,7 +1411,7 @@ H5Mdelete(hid_t map_id, hid_t key_mem_type_id, const void *key, hid_t dxpl_id) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid key memory datatype ID"); /* Get map pointer */ - if (NULL == (vol_obj = (H5VL_object_t *)H5I_object_verify(map_id, H5I_MAP))) + if (NULL == (vol_obj = H5VL_vol_object_verify(map_id, H5I_MAP))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "map_id is not a map ID"); /* Get the default dataset transfer property list if the user didn't provide one */ diff --git a/src/H5Mpublic.h b/src/H5Mpublic.h index 44c78fe064f..3d8a8c7f7c8 100644 --- a/src/H5Mpublic.h +++ b/src/H5Mpublic.h @@ -245,9 +245,27 @@ H5_DLL hid_t H5Mcreate_async(hid_t loc_id, const char *name, hid_t key_type_id, /** * \ingroup H5M * - * \brief + * \brief Creates a map object without linking it into a file * - * \details + * \fgdta_loc_id + * \type_id{key_type_id} + * \type_id{val_type_id} + * \mcpl_id + * \mapl_id + * \return \hid_t{map object} + * The resulting ID should be linked into the file with H5Olink or it + * will be deleted when closed. + * + * \details H5Mcreate_anon() creates a new map object for storing key-value + * pairs. The in-file datatype for keys is defined by \p key_type_id + * and the in-file datatype for values is defined by \p val_type_id. \p + * loc_id specifies the file to create the map object, but no link to + * the object is created. Other options can be specified through the + * property lists \p mcpl_id and \p mapl_id. + * + * The new map should be linked into the group hierarchy before being + * closed or it will be deleted. The map should be closed when the + * caller no longer requires it. * * \since 1.12.0 * From 4ffeb77fdb72f50407c0c6e5d2503e6f7763e8d3 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 4 Sep 2024 07:32:42 -0500 Subject: [PATCH 60/94] Correct the URL paths (#4802) --- HDF5Examples/README.md | 2 +- README.md | 2 +- doc/parallel-compression.md | 6 +++--- release_docs/RELEASE_PROCESS.md | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/HDF5Examples/README.md b/HDF5Examples/README.md index e70a1a792d0..c1a27d5fb12 100644 --- a/HDF5Examples/README.md +++ b/HDF5Examples/README.md @@ -48,7 +48,7 @@ HDF5 SNAPSHOTS, PREVIOUS RELEASES AND SOURCE CODE -------------------------------------------- Full Documentation and Programming Resources for this HDF5 can be found at - https://support.hdfgroup.org/documentation/HDF5/index.html + https://support.hdfgroup.org/documentation/hdf5/index.html Periodically development code snapshots are provided at the following URL: diff --git a/README.md b/README.md index 1be794abcb1..e54d02c9587 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ Periodically development code snapshots are provided at the following URL: Source packages for current and previous releases are located at: - https://support.hdfgroup.org/downloads/HDF5 + https://support.hdfgroup.org/downloads/hdf5 Development code is available at our Github location: diff --git a/doc/parallel-compression.md b/doc/parallel-compression.md index 77126d6acf6..0d16c448e65 100644 --- a/doc/parallel-compression.md +++ b/doc/parallel-compression.md @@ -340,9 +340,9 @@ hid_t file_id = H5Fcreate("file.h5", H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); [u5]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga85faefca58387bba409b65c470d7d851 [u6]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga4335bb45b35386daa837b4ff1b9cd4a4 [u7]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga6bd822266b31f86551a9a1d79601b6a2 -[u8]: https://support.hdfgroup.org/documentation/HDF5/parallel-compression-improvements-in-hdf5-1-13-1 -[u9]: https://support.hdfgroup.org/documentation/HDF5/chunking_in_hdf5.html -[u10]: https://support.hdfgroup.org/documentation/HDF5/technotes/TechNote-HDF5-ImprovingIOPerformanceCompressedDatasets.pdf +[u8]: https://support.hdfgroup.org/documentation/hdf5/parallel-compression-improvements-in-hdf5-1-13-1 +[u9]: https://support.hdfgroup.org/documentation/hdf5/chunking_in_hdf5.html +[u10]: https://support.hdfgroup.org/documentation/hdf5/technotes/TechNote-HDF5-ImprovingIOPerformanceCompressedDatasets.pdf [u11]: https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a [u12]: https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#ga167ff65f392ca3b7f1933b1cee1b9f70 [u13]: https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#gad012d7f3c2f1e1999eb1770aae3a4963 diff --git a/release_docs/RELEASE_PROCESS.md b/release_docs/RELEASE_PROCESS.md index 3e876d34369..b3d6f651bc8 100644 --- a/release_docs/RELEASE_PROCESS.md +++ b/release_docs/RELEASE_PROCESS.md @@ -114,7 +114,7 @@ For more information on the HDF5 versioning and backward and forward compatibili 7. Choose the release branch 8. Change ‘Release version tag’ name to 'hdf5_X.Y.Z.P' - P is some pre-release number. -9. Send a message to the HDF forum indicating that a pre-release source package is available for testing at and that feedback from the user community on their test results is being accepted. +9. Send a message to the HDF forum indicating that a pre-release source package is available for testing at /{hdf5-X.Y.Z-P}> and that feedback from the user community on their test results is being accepted. 10. Contact paying clients who are interested in testing the pre-release source package and inform them that it is available for testing and that feedback on their test results of the pre-release is appreciated. 11. This should be automated and currently github binaries are not signed. - Follow the [How to sign binaries with digital certificates(this is missing)]() work instructions to sign each Windows and Mac binary package with a digital certificate. @@ -167,13 +167,13 @@ For more information on the HDF5 versioning and backward and forward compatibili [u3]: https://github.com/HDFGroup/hdf5/blob/develop/COPYING [u4]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs [u5]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL -[u6]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_Auto.txt +[u6]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_Autotools.txt [u7]: https://github.com/HDFGroup/hdf5/blob/develop/release_docs/INSTALL_CMake.txt [u8]: https://github.com/HDFGroup/hdf5/blob/develop/.github/workflows/release.yml [u9]: https://github.com/HDFGroup/hdf5/blob/develop/config/lt_vers.am [u10]: https://github.com/HDFGroup/hdf5/blob/develop/bin/h5vers [u11]: https://github.com/HDFGroup/hdf5/blob/develop/src/CMakeLists.txt [u12]: https://github.com/HDFGroup/hdf5/blob/develop/configure.ac -[u13]: https://support.hdfgroup.org/documentation/HDF5/v1_14/v1_14_4/api-compat-macros.html +[u13]: https://support.hdfgroup.org/documentation/hdf5/v1_14/v1_14_4/api-compat-macros.html [u14]: https://github.com/HDFGroup/hdf5/releases/tag/snapshot-1.14 [u15]: https://github.com/HDFGroup/hdf5/releases/tag/snapshot From 308fc972f7462cd001adb8a64753890b2d1414d2 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Wed, 4 Sep 2024 13:14:22 -0500 Subject: [PATCH 61/94] Fix a few issues with error reporting during sec2 reads/writes (#4794) --- src/H5FDsec2.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/H5FDsec2.c b/src/H5FDsec2.c index 0a623e9cb36..99ff8df6cfe 100644 --- a/src/H5FDsec2.c +++ b/src/H5FDsec2.c @@ -700,15 +700,16 @@ H5FD__sec2_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNU int myerrno = errno; time_t mytime = time(NULL); +#ifndef H5_HAVE_PREADWRITE offset = HDlseek(file->fd, 0, SEEK_CUR); +#endif HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file read failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, " - "error message = '%s', buf = %p, total read size = %llu, bytes this sub-read = %llu, " - "bytes actually read = %llu, offset = %llu", - ctime(&mytime), file->filename, file->fd, myerrno, strerror(myerrno), buf, - (unsigned long long)size, (unsigned long long)bytes_in, - (unsigned long long)bytes_read, (unsigned long long)offset); + "error message = '%s', buf = %p, total read size = %zu, bytes this sub-read = %llu, " + "offset = %llu", + ctime(&mytime), file->filename, file->fd, myerrno, strerror(myerrno), buf, size, + (unsigned long long)bytes_in, (unsigned long long)offset); } /* end if */ if (0 == bytes_read) { @@ -810,15 +811,16 @@ H5FD__sec2_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UN int myerrno = errno; time_t mytime = time(NULL); +#ifndef H5_HAVE_PREADWRITE offset = HDlseek(file->fd, 0, SEEK_CUR); +#endif HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed: time = %s, filename = '%s', file descriptor = %d, errno = %d, " - "error message = '%s', buf = %p, total write size = %llu, bytes this sub-write = " - "%llu, bytes actually written = %llu, offset = %llu", - ctime(&mytime), file->filename, file->fd, myerrno, strerror(myerrno), buf, - (unsigned long long)size, (unsigned long long)bytes_in, - (unsigned long long)bytes_wrote, (unsigned long long)offset); + "error message = '%s', buf = %p, total write size = %zu, bytes this sub-write = " + "%llu, offset = %llu", + ctime(&mytime), file->filename, file->fd, myerrno, strerror(myerrno), buf, size, + (unsigned long long)bytes_in, (unsigned long long)offset); } /* end if */ assert(bytes_wrote > 0); From 39361bd24efbb22e1626824f7281ecf85f7801d4 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:15:12 -0500 Subject: [PATCH 62/94] Update windows and apple signing process (#4806) --- .github/workflows/cmake-ctest.yml | 157 +++++++++++++++++++-- .github/workflows/daily-build.yml | 3 + .github/workflows/release-files.yml | 6 +- .github/workflows/release.yml | 3 + CMakeInstallation.cmake | 5 + CMakePresets.json | 84 +++++++++-- config/cmake-presets/hidden-presets.json | 170 +++++++++++++++++++---- config/cmake/CPack.Info.plist.in | 11 +- config/cmake/SignPackageFiles.cmake | 43 ++++++ config/cmake/distribution.entitlements | 16 +++ config/cmake/examples/CTestScript.cmake | 2 +- config/cmake/scripts/CTestScript.cmake | 20 +-- config/toolchain/mingw64.cmake | 2 +- release_docs/USING_CMake_Examples.txt | 2 +- 14 files changed, 456 insertions(+), 68 deletions(-) create mode 100644 config/cmake/SignPackageFiles.cmake create mode 100644 config/cmake/distribution.entitlements diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index a588614e673..64bae44d511 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -23,6 +23,12 @@ on: required: true default: snapshots secrets: + APPLE_CERTS_BASE64: + required: true + APPLE_CERTS_BASE64_PASSWD: + required: true + KEYCHAIN_PASSWD: + required: true AZURE_TENANT_ID: required: true AZURE_CLIENT_ID: @@ -53,13 +59,15 @@ jobs: run: | if [[ '${{ env.signing_secret }}' == '' ]] then - SIGN_VAL=$(echo "false") + SIGN_VAL=$(echo 'notexists') else - SIGN_VAL=$(echo "true") + SIGN_VAL=$(echo 'exists') fi echo "BINSIGN=$SIGN_VAL" >> $GITHUB_OUTPUT shell: bash + - run: echo "signing is ${{ steps.set-signing-state.outputs.BINSIGN }}." + build_and_test_win: # Windows w/ MSVC + CMake # @@ -114,7 +122,27 @@ jobs: run: 7z x ${{ steps.set-file-base.outputs.FILE_BASE }}.zip shell: bash + - name: Install TrustedSigning (Windows) + run: | + Invoke-WebRequest -Uri https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\nuget.exe + .\nuget.exe install Microsoft.Windows.SDK.BuildTools -Version 10.0.22621.3233 -x + .\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.53 -x + shell: pwsh + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + + - name: create-json + id: create-json + uses: jsdaniell/create-json@v1.2.3 + with: + name: "credentials.json" + dir: 'hdfsrc' + json: '{"Endpoint": "${{ secrets.AZURE_ENDPOINT }}","CodeSigningAccountName": "${{ secrets.AZURE_CODE_SIGNING_NAME }}","CertificateProfileName": "${{ secrets.AZURE_CERT_PROFILE_NAME }}"}' + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + - name: Run ctest (Windows) + env: + BINSIGN: ${{ needs.check-secret.outputs.sign-state }} + SIGNTOOLDIR: ${{ github.workspace }}/Microsoft.Windows.SDK.BuildTools/bin/10.0.22621.0/x64 run: | cd "${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}" cmake --workflow --preset=${{ inputs.preset_name }}-MSVC --fresh @@ -134,7 +162,7 @@ jobs: file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 - if: ${{ needs.check-secret.outputs.sign-state == 'true' }} + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} - name: Publish binary (Windows) id: publish-ctest-binary @@ -323,6 +351,28 @@ jobs: with: version: "1.9.7" + - name: Install the Apple certificate and provisioning profile + shell: bash + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.APPLE_CERTS_BASE64 }} + P12_PASSWORD: ${{ secrets.APPLE_CERTS_BASE64_PASSWD }} + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} + run: | + # create variables + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_FILE=${{ vars.KEYCHAIN_NAME }}.keychain + # import certificate from secrets + echo $BUILD_CERTIFICATE_BASE64 | base64 --decode > $CERTIFICATE_PATH + security -v create-keychain -p $KEYCHAIN_PASSWD $KEYCHAIN_FILE + security -v list-keychain -d user -s $KEYCHAIN_FILE + security -v list-keychains + security -v set-keychain-settings -lut 21600 $KEYCHAIN_FILE + security -v unlock-keychain -p $KEYCHAIN_PASSWD $KEYCHAIN_FILE + # import certificate to keychain + security -v import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_FILE + security -v set-key-partition-list -S apple-tool:,codesign:,apple: -k $KEYCHAIN_PASSWD $KEYCHAIN_FILE + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + - name: Set up JDK 19 uses: actions/setup-java@v4 with: @@ -367,10 +417,99 @@ jobs: - name: Run ctest (MacOS_latest) id: run-ctest + env: + BINSIGN: ${{ needs.check-secret.outputs.sign-state }} + SIGNER: ${{ vars.SIGNER }} run: | cd "${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}" - cmake --workflow --preset=${{ inputs.preset_name }}-MACOS-Clang --fresh + cmake --workflow --preset=${{ inputs.preset_name }}-macos-Clang --fresh + shell: bash + + - name: Sign dmg (MacOS_latest) + id: sign-dmg + env: + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} + KEYCHAIN_NAME: ${{ vars.KEYCHAIN_NAME }} + SIGNER: ${{ vars.SIGNER }} + NOTARY_USER: ${{ vars.NOTARY_USER }} + NOTARY_KEY: ${{ vars.NOTARY_KEY }} + run: | + /usr/bin/codesign --force --timestamp --options runtime --entitlements ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/config/cmake/distribution.entitlements --verbose=4 --strict --sign ${{ env.SIGNER }} --deep ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: Check dmg timestamp (MacOS_latest) + run: | + /usr/bin/codesign -dvv ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: Verify dmg (MacOS_latest) + run: | + /usr/bin/hdiutil verify ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: Notarize dmg (MacOS_latest) + id: notarize-dmg + env: + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} + KEYCHAIN_NAME: ${{ vars.KEYCHAIN_NAME }} + SIGNER: ${{ vars.SIGNER }} + NOTARY_USER: ${{ vars.NOTARY_USER }} + NOTARY_KEY: ${{ vars.NOTARY_KEY }} + run: | + jsonout=$(/usr/bin/xcrun notarytool submit --wait --output-format json --apple-id ${{ env.NOTARY_USER }} --password ${{ env.NOTARY_KEY }} --team-id ${{ env.SIGNER }} ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg) + echo "JSONOUT=$jsonout" >> $GITHUB_OUTPUT + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: Get ID token (MacOS_latest) + id: get-id-token + run: | + echo "notary result is ${{ fromJson(steps.notarize-dmg.outputs.JSONOUT) }}" + token=${{ fromJson(steps.notarize-dmg.outputs.JSONOUT).id }} + echo "ID_TOKEN=$token" >> "$GITHUB_OUTPUT" + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: post notary check (MacOS_latest) + id: post-notary + env: + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} + KEYCHAIN_NAME: ${{ vars.KEYCHAIN_NAME }} + SIGNER: ${{ vars.SIGNER }} + NOTARY_USER: ${{ vars.NOTARY_USER }} + NOTARY_KEY: ${{ vars.NOTARY_KEY }} + run: | + { + echo 'NOTARYOUT<> $GITHUB_OUTPUT + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: Get notary info (MacOS_latest) + id: get-notary-info + run: | + echo "notary info is ${{ steps.post-notary.outputs.NOTARYOUT }}." + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + shell: bash + + - name: Staple dmg (MacOS_latest) + id: staple-dmg + env: + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} + KEYCHAIN_NAME: ${{ vars.KEYCHAIN_NAME }} + SIGNER: ${{ vars.SIGNER }} + NOTARY_USER: ${{ vars.NOTARY_USER }} + NOTARY_KEY: ${{ vars.NOTARY_KEY }} + run: | + /usr/bin/xcrun stapler staple ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} shell: bash + continue-on-error: true - name: Publish binary (MacOS_latest) id: publish-ctest-binary @@ -379,8 +518,8 @@ jobs: mkdir "${{ runner.workspace }}/build/hdf5" cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING ${{ runner.workspace }}/build/hdf5 cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 ${{ runner.workspace }}/build/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/README.md ${{ runner.workspace }}/build/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/*.tar.gz ${{ runner.workspace }}/build/hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/README.md ${{ runner.workspace }}/build/hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.tar.gz ${{ runner.workspace }}/build/hdf5 cd "${{ runner.workspace }}/build" tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz hdf5 shell: bash @@ -392,8 +531,8 @@ jobs: mkdir "${{ runner.workspace }}/builddmg/hdf5" cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING ${{ runner.workspace }}/builddmg/hdf5 cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 ${{ runner.workspace }}/builddmg/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/README.md ${{ runner.workspace }}/builddmg/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Clang/*.dmg ${{ runner.workspace }}/builddmg/hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/README.md ${{ runner.workspace }}/builddmg/hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg ${{ runner.workspace }}/builddmg/hdf5 cd "${{ runner.workspace }}/builddmg" tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz hdf5 shell: bash @@ -568,7 +707,7 @@ jobs: file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 - if: ${{ needs.check-secret.outputs.sign-state == 'true' }} + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} - name: Publish binary (Windows_intel) id: publish-ctest-binary diff --git a/.github/workflows/daily-build.yml b/.github/workflows/daily-build.yml index 3375dec6f31..2b7d6aef3bf 100644 --- a/.github/workflows/daily-build.yml +++ b/.github/workflows/daily-build.yml @@ -45,6 +45,9 @@ jobs: # use_tag: snapshot use_environ: snapshots secrets: + APPLE_CERTS_BASE64: ${{ secrets.APPLE_CERTS_BASE64 }} + APPLE_CERTS_BASE64_PASSWD: ${{ secrets.APPLE_CERTS_BASE64_PASSWD }} + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index d2cde576a50..c51c9754697 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -186,7 +186,7 @@ jobs: sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt @@ -232,7 +232,7 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz @@ -261,7 +261,7 @@ jobs: hdf5.tar.gz hdf5.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b0a90ff61e..e41b30c4d37 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,6 +41,9 @@ jobs: snap_name: hdf5-${{ needs.call-workflow-tarball.outputs.source_base }} use_environ: release secrets: + APPLE_CERTS_BASE64: ${{ secrets.APPLE_CERTS_BASE64 }} + APPLE_CERTS_BASE64_PASSWD: ${{ secrets.APPLE_CERTS_BASE64_PASSWD }} + KEYCHAIN_PASSWD: ${{ secrets.KEYCHAIN_PASSWD }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} diff --git a/CMakeInstallation.cmake b/CMakeInstallation.cmake index 313dbb2e8e3..a2564e68ad5 100644 --- a/CMakeInstallation.cmake +++ b/CMakeInstallation.cmake @@ -268,6 +268,11 @@ if (NOT HDF5_EXTERNALLY_CONFIGURED AND NOT HDF5_NO_PACKAGES) endif () set (CPACK_PACKAGE_ICON "${HDF_RESOURCES_DIR}/hdf.bmp") + set (CPACK_ORIG_SOURCE_DIR ${CMAKE_SOURCE_DIR}) + if ("$ENV{BINSIGN}" STREQUAL "exists") + set (CPACK_PRE_BUILD_SCRIPTS ${CMAKE_SOURCE_DIR}/config/cmake/SignPackageFiles.cmake) + endif () + set (CPACK_GENERATOR "TGZ") if (WIN32) set (CPACK_GENERATOR "ZIP") diff --git a/CMakePresets.json b/CMakePresets.json index 31849736320..472a33df0b6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -155,6 +155,26 @@ "ci-StdShar" ] }, + { + "name": "ci-StdShar-macos-Clang", + "description": "Clang Standard Config for macos (Release)", + "inherits": [ + "ci-macos-Release-Clang", + "ci-CPP", + "ci-Java", + "ci-StdShar" + ] + }, + { + "name": "ci-StdShar-macos-GNUC", + "description": "GNUC Standard Config for macos (Release)", + "inherits": [ + "ci-macos-Release-GNUC", + "ci-CPP", + "ci-Java", + "ci-StdShar" + ] + }, { "name": "ci-StdShar-GNUC", "description": "GNUC Standard Config for x64 (Release)", @@ -203,6 +223,23 @@ "ci-x64-Release-Clang" ] }, + { + "name": "ci-StdShar-macos-Clang", + "description": "Clang Standard Build for macos (Release)", + "configurePreset": "ci-StdShar-macos-Clang", + "inherits": [ + "ci-macos-Release-Clang" + ] + }, + { + "name": "ci-StdShar-macos-GNUC", + "description": "GNUC Standard Build for macos (Release)", + "configurePreset": "ci-StdShar-macos-GNUC", + "verbose": true, + "inherits": [ + "ci-macos-Release-GNUC" + ] + }, { "name": "ci-StdShar-GNUC", "description": "GNUC Standard Build for x64 (Release)", @@ -252,22 +289,24 @@ ] }, { - "name": "ci-StdShar-MACOS-Clang", - "configurePreset": "ci-StdShar-Clang", + "name": "ci-StdShar-macos-Clang", + "configurePreset": "ci-StdShar-macos-Clang", "inherits": [ - "ci-x64-Release-Clang" + "ci-macos-Release-Clang" ], "execution": { "noTestsAction": "error", "timeout": 180, "jobs": 2 - }, - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Darwin" } }, + { + "name": "ci-StdShar-macos-GNUC", + "configurePreset": "ci-StdShar-macos-GNUC", + "inherits": [ + "ci-macos-Release-GNUC" + ] + }, { "name": "ci-StdShar-GNUC", "configurePreset": "ci-StdShar-GNUC", @@ -318,6 +357,16 @@ "configurePreset": "ci-StdShar-Clang", "inherits": "ci-x64-Release-Clang" }, + { + "name": "ci-StdShar-macos-Clang", + "configurePreset": "ci-StdShar-macos-Clang", + "inherits": "ci-macos-Release-Clang" + }, + { + "name": "ci-StdShar-macos-GNUC", + "configurePreset": "ci-StdShar-macos-GNUC", + "inherits": "ci-macos-Release-GNUC" + }, { "name": "ci-StdShar-GNUC", "configurePreset": "ci-StdShar-GNUC", @@ -354,12 +403,12 @@ ] }, { - "name": "ci-StdShar-MACOS-Clang", + "name": "ci-StdShar-macos-Clang", "steps": [ - {"type": "configure", "name": "ci-StdShar-Clang"}, - {"type": "build", "name": "ci-StdShar-Clang"}, - {"type": "test", "name": "ci-StdShar-MACOS-Clang"}, - {"type": "package", "name": "ci-StdShar-Clang"} + {"type": "configure", "name": "ci-StdShar-macos-Clang"}, + {"type": "build", "name": "ci-StdShar-macos-Clang"}, + {"type": "test", "name": "ci-StdShar-macos-Clang"}, + {"type": "package", "name": "ci-StdShar-macos-Clang"} ] }, { @@ -371,6 +420,15 @@ {"type": "package", "name": "ci-StdShar-GNUC"} ] }, + { + "name": "ci-StdShar-macos-GNUC", + "steps": [ + {"type": "configure", "name": "ci-StdShar-macos-GNUC"}, + {"type": "build", "name": "ci-StdShar-macos-GNUC"}, + {"type": "test", "name": "ci-StdShar-macos-GNUC"}, + {"type": "package", "name": "ci-StdShar-macos-GNUC"} + ] + }, { "name": "ci-StdShar-GNUC-S3", "steps": [ diff --git a/config/cmake-presets/hidden-presets.json b/config/cmake-presets/hidden-presets.json index d4e52cab752..8051eb66be0 100644 --- a/config/cmake-presets/hidden-presets.json +++ b/config/cmake-presets/hidden-presets.json @@ -10,7 +10,7 @@ "binaryDir": "${sourceParentDir}/build/${presetName}", "installDir": "${sourceParentDir}/install/${presetName}" }, - { + { "name": "ci-x64", "architecture": { "value": "x64", @@ -21,7 +21,15 @@ { "name": "ci-x86", "architecture": { - "value": "x86", + "value": "Win32", + "strategy": "external" + }, + "hidden": true + }, + { + "name": "ci-arm64", + "architecture": { + "value": "ARM64", "strategy": "external" }, "hidden": true @@ -48,25 +56,29 @@ "CMAKE_C_COMPILER": "cl", "CMAKE_CXX_COMPILER": "cl" }, - "toolset": { - "value": "host=x64", - "strategy": "external" - }, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" } }, + { + "name": "ci-macos", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64;x86_64" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, { "name": "ci-Clang", "hidden": true, "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "config/toolchain/clang.cmake" - }, - "toolset": { - "value": "host=x64", - "strategy": "external" } }, { @@ -79,29 +91,17 @@ "type": "equals", "lhs": "${hostSystemName}", "rhs": "Linux" - }, - "toolset": { - "value": "host=x64", - "strategy": "external" } }, { "name": "ci-Intel", - "hidden": true, - "toolset": { - "value": "host=x64", - "strategy": "external" - } + "hidden": true }, { "name": "ci-Fortran", "hidden": true, "cacheVariables": { "HDF5_BUILD_FORTRAN": "ON" - }, - "toolset": { - "value": "host=x64", - "strategy": "external" } }, { @@ -129,10 +129,6 @@ "hidden": true, "cacheVariables": { "HDF5_BUILD_JAVA": "ON" - }, - "toolset": { - "value": "host=x64", - "strategy": "external" } }, { @@ -201,6 +197,50 @@ "ci-GNUC" ] }, + { + "name": "ci-macos-Debug-Clang", + "description": "Clang/LLVM for x64 (Debug)", + "hidden": true, + "inherits": [ + "ci-base", + "ci-macos", + "ci-Debug", + "ci-Clang" + ] + }, + { + "name": "ci-macos-Release-Clang", + "description": "Clang/LLVM for x64 (Release)", + "hidden": true, + "inherits": [ + "ci-base", + "ci-macos", + "ci-Release", + "ci-Clang" + ] + }, + { + "name": "ci-macos-Debug-GNUC", + "description": "GNUC for x64 (Debug)", + "hidden": true, + "inherits": [ + "ci-base", + "ci-macos", + "ci-Debug", + "ci-GNUC" + ] + }, + { + "name": "ci-macos-Release-GNUC", + "description": "GNUC for x64 (Release)", + "hidden": true, + "inherits": [ + "ci-base", + "ci-macos", + "ci-Release", + "ci-GNUC" + ] + }, { "name": "ci-x64-Debug-Intel", "description": "Intel for x64 (Debug)", @@ -328,6 +368,38 @@ "ci-base" ] }, + { + "name": "ci-macos-Debug-Clang", + "configurePreset": "ci-macos-Debug-Clang", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, + { + "name": "ci-macos-Release-Clang", + "configurePreset": "ci-macos-Release-Clang", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, + { + "name": "ci-macos-Debug-GNUC", + "configurePreset": "ci-macos-Debug-GNUC", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, + { + "name": "ci-macos-Release-GNUC", + "configurePreset": "ci-macos-Release-GNUC", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, { "name": "ci-x64-Debug-Intel", "configurePreset": "ci-x64-Debug-Intel", @@ -453,6 +525,38 @@ "ci-base" ] }, + { + "name": "ci-macos-Debug-Clang", + "configurePreset": "ci-macos-Debug-Clang", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, + { + "name": "ci-macos-Release-Clang", + "configurePreset": "ci-macos-Release-Clang", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, + { + "name": "ci-macos-Debug-GNUC", + "configurePreset": "ci-macos-Debug-GNUC", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, + { + "name": "ci-macos-Release-GNUC", + "configurePreset": "ci-macos-Release-GNUC", + "hidden": true, + "inherits": [ + "ci-base" + ] + }, { "name": "ci-x64-Debug-Intel", "configurePreset": "ci-x64-Debug-Intel", @@ -536,6 +640,18 @@ "hidden": true, "inherits": "ci-base" }, + { + "name": "ci-macos-Release-Clang", + "configurePreset": "ci-macos-Release-Clang", + "hidden": true, + "inherits": "ci-base" + }, + { + "name": "ci-macos-Release-GNUC", + "configurePreset": "ci-macos-Release-GNUC", + "hidden": true, + "inherits": "ci-base" + }, { "name": "ci-x64-Release-Intel", "configurePreset": "ci-x64-Release-Intel", diff --git a/config/cmake/CPack.Info.plist.in b/config/cmake/CPack.Info.plist.in index b936470fc29..a518f559cc9 100644 --- a/config/cmake/CPack.Info.plist.in +++ b/config/cmake/CPack.Info.plist.in @@ -1,5 +1,5 @@ - - + + CFBundleDevelopmentRegion @@ -16,11 +16,16 @@ FMWK CFBundleSignature ???? + + LSApplicationCategoryType + public.app-category.utilities CFBundleVersion @CPACK_PACKAGE_VERSION@ CFBundleShortVersionString @CPACK_SHORT_VERSION_STRING@ + NSHumanReadableCopyright + Copyright 2006 by The HDF Group CSResourcesFileMapped - + true diff --git a/config/cmake/SignPackageFiles.cmake b/config/cmake/SignPackageFiles.cmake new file mode 100644 index 00000000000..da5084917fe --- /dev/null +++ b/config/cmake/SignPackageFiles.cmake @@ -0,0 +1,43 @@ +# This script signs the targets for the package +message(STATUS "Signing script in ${CPACK_TEMPORARY_INSTALL_DIRECTORY} and ${CPACK_PACKAGE_INSTALL_DIRECTORY}") + +# RPM needs ALL_COMPONENTS_IN_ONE added to path between ${CPACK_TEMPORARY_INSTALL_DIRECTORY} and ${CPACK_PACKAGE_INSTALL_DIRECTORY} +if (CPACK_GENERATOR MATCHES "RPM") + set (CPACK_TARGET_FILE_DIRECTORY "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_COMPONENTS_IN_ONE/${CPACK_PACKAGE_INSTALL_DIRECTORY}") +elseif (CPACK_GENERATOR MATCHES "WIX" OR CPACK_GENERATOR MATCHES "NSIS") + set (CPACK_TARGET_FILE_DIRECTORY "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/libraries") +elseif (CPACK_GENERATOR MATCHES "ZIP") + set (CPACK_TARGET_FILE_DIRECTORY "${CPACK_TEMPORARY_INSTALL_DIRECTORY}") +elseif (CPACK_GENERATOR MATCHES "DragNDrop") + set (CPACK_TARGET_FILE_DIRECTORY "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/${CPACK_PACKAGE_INSTALL_DIRECTORY}") +else () + set (CPACK_TARGET_FILE_DIRECTORY "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/${CPACK_PACKAGE_INSTALL_DIRECTORY}") +endif () +file (GLOB target_list LIST_DIRECTORIES false "${CPACK_TARGET_FILE_DIRECTORY}/lib/*" "${CPACK_TARGET_FILE_DIRECTORY}/bin/*") +foreach (targetfile IN LISTS target_list) + if (WIN32) + # Sign the targets + execute_process (COMMAND $ENV{SIGNTOOLDIR}/signtool + sign /v /debug /fd SHA256 /tr http://timestamp.acs.microsoft.com /td SHA256 + /dlib "Microsoft.Trusted.Signing.Client/bin/x64/Azure.CodeSigning.Dlib.dll" /dmdf ${CPACK_ORIG_SOURCE_DIR}/credentials.json + ${targetfile} + ) + execute_process ( + COMMAND ${CMAKE_COMMAND} -E echo "Signing the target ${targetfile}" + ) + elseif (APPLE) + # Sign the targets + execute_process (COMMAND codesign + --force --timestamp --options runtime --entitlements ${CPACK_ORIG_SOURCE_DIR}/config/cmake/distribution.entitlements + --verbose=4 --strict --sign "$ENV{SIGNER}" + ${targetfile} + ) + execute_process ( + COMMAND ${CMAKE_COMMAND} -E echo "Signing the target ${targetfile}" + ) + else () + execute_process ( + COMMAND ${CMAKE_COMMAND} -E echo "Signing the target ${targetfile}" + ) + endif () +endforeach () diff --git a/config/cmake/distribution.entitlements b/config/cmake/distribution.entitlements new file mode 100644 index 00000000000..0e0df6c7627 --- /dev/null +++ b/config/cmake/distribution.entitlements @@ -0,0 +1,16 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-dyld-environment-variables + + + diff --git a/config/cmake/examples/CTestScript.cmake b/config/cmake/examples/CTestScript.cmake index 657806ce3c2..b1bfa8a9fc1 100644 --- a/config/cmake/examples/CTestScript.cmake +++ b/config/cmake/examples/CTestScript.cmake @@ -137,7 +137,7 @@ set (CTEST_CONFIGURE_COMMAND #----------------------------------------------------------------------------- ## -- set output to english -set ($ENV{LC_MESSAGES} "en_EN") +set (ENV{LC_MESSAGES} "en_EN") #----------------------------------------------------------------------------- configure_file(${CTEST_SOURCE_DIRECTORY}/config/cmake/CTestCustom.cmake ${CTEST_BINARY_DIRECTORY}/CTestCustom.cmake) diff --git a/config/cmake/scripts/CTestScript.cmake b/config/cmake/scripts/CTestScript.cmake index ad6cd44014b..46037f573b1 100644 --- a/config/cmake/scripts/CTestScript.cmake +++ b/config/cmake/scripts/CTestScript.cmake @@ -51,15 +51,15 @@ endif () set (BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DSITE:STRING=${CTEST_SITE} -DBUILDNAME:STRING=${CTEST_BUILD_NAME}") # Launchers work only with Makefile and Ninja generators. -if(NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make|Ninja" OR LOCAL_SKIP_TEST) - set(CTEST_USE_LAUNCHERS 0) - set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} 0) - set(BUILD_OPTIONS "${BUILD_OPTIONS} -DCTEST_USE_LAUNCHERS:BOOL=OFF") -else() - set(CTEST_USE_LAUNCHERS 1) - set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} 1) - set(BUILD_OPTIONS "${BUILD_OPTIONS} -DCTEST_USE_LAUNCHERS:BOOL=ON") -endif() +if (NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make|Ninja" OR LOCAL_SKIP_TEST) + set (CTEST_USE_LAUNCHERS 0) + set (ENV{CTEST_USE_LAUNCHERS_DEFAULT} 0) + set (BUILD_OPTIONS "${BUILD_OPTIONS} -DCTEST_USE_LAUNCHERS:BOOL=OFF") +else () + set (CTEST_USE_LAUNCHERS 1) + set (ENV{CTEST_USE_LAUNCHERS_DEFAULT} 1) + set (BUILD_OPTIONS "${BUILD_OPTIONS} -DCTEST_USE_LAUNCHERS:BOOL=ON") +endif () #----------------------------------------------------------------------------- # MAC machines need special option @@ -206,7 +206,7 @@ endif () #----------------------------------------------------------------------------- ## -- set output to english -set ($ENV{LC_MESSAGES} "en_EN") +set (ENV{LC_MESSAGES} "en_EN") # Print summary information. foreach (v diff --git a/config/toolchain/mingw64.cmake b/config/toolchain/mingw64.cmake index 1b138919087..d4d2e4e0532 100644 --- a/config/toolchain/mingw64.cmake +++ b/config/toolchain/mingw64.cmake @@ -1,4 +1,4 @@ -set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) +set (TOOLCHAIN_PREFIX x86_64-w64-mingw32) set (CMAKE_SYSTEM_NAME Windows) set (CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) set (CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) diff --git a/release_docs/USING_CMake_Examples.txt b/release_docs/USING_CMake_Examples.txt index f31a922804d..2769fda3395 100644 --- a/release_docs/USING_CMake_Examples.txt +++ b/release_docs/USING_CMake_Examples.txt @@ -22,7 +22,7 @@ I. Preconditions 1. We suggest you obtain the latest CMake for your platform from the Kitware web site. The HDF5 1.15.x product requires a minimum CMake version - of 3.18. If you are using VS2022, the minimum version is 3.21. + of 3.18. If you are using VS2022, the minimum CMake version is 3.21. 2. You have installed the HDF5 library built with CMake, by executing the HDF Install Utility (the *.msi file in the binary package for From dae1cc05157cbccfdfdc0b20fb1b24c93ab00fb7 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:21:38 -0500 Subject: [PATCH 63/94] Use latest clang format action (#4807) --- .github/workflows/clang-format-check.yml | 5 ++++- .github/workflows/clang-format-fix.yml | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 78146ed932b..8fd5b5fb8f7 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -1,8 +1,10 @@ name: clang-format Check on: pull_request: + permissions: contents: read + jobs: formatting-check: name: Formatting Check @@ -10,8 +12,9 @@ jobs: if: "!contains(github.event.head_commit.message, 'skip-ci')" steps: - uses: actions/checkout@v4.1.7 + - name: Run clang-format style check for C and Java code - uses: DoozyX/clang-format-lint-action@v0.18 + uses: DoozyX/clang-format-lint-action@v0.18.2 with: source: '.' extensions: 'c,h,cpp,hpp,java' diff --git a/.github/workflows/clang-format-fix.yml b/.github/workflows/clang-format-fix.yml index 75789e0f4e0..a99d32d38ad 100644 --- a/.github/workflows/clang-format-fix.yml +++ b/.github/workflows/clang-format-fix.yml @@ -11,8 +11,10 @@ name: clang-format Commit Changes on: workflow_dispatch: push: + permissions: contents: read + jobs: formatting-check: name: Commit Format Changes @@ -21,9 +23,10 @@ jobs: permissions: contents: write # In order to allow EndBug/add-and-commit to commit changes steps: - - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 + - uses: actions/checkout@v4.1.7 + - name: Fix C and Java formatting issues detected by clang-format - uses: DoozyX/clang-format-lint-action@caa179272c6ee7f1d25dfb503ee0c410c26ebd98 # v0.13 + uses: DoozyX/clang-format-lint-action@v0.18.2 with: source: '.' extensions: 'c,h,cpp,hpp,java' @@ -31,6 +34,7 @@ jobs: inplace: True style: file exclude: './config ./hl/src/H5LTanalyze.c ./hl/src/H5LTparse.c ./hl/src/H5LTparse.h ./src/H5Epubgen.h ./src/H5Einit.h ./src/H5Eterm.h ./src/H5Edefin.h ./src/H5version.h ./src/H5overflow.h' + - uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4 with: author_name: github-actions From 2eaa01690a521a4e2b18f6474f70d7a38ab4341e Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:30:13 -0500 Subject: [PATCH 64/94] Correct path to document (#4808) --- doxygen/dox/Specifications.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen/dox/Specifications.dox b/doxygen/dox/Specifications.dox index 7807fa3ba11..f2ba467d7bb 100644 --- a/doxygen/dox/Specifications.dox +++ b/doxygen/dox/Specifications.dox @@ -17,7 +17,7 @@ \li \ref IMG \li \ref TBL -\li +\li HDF5 Dimension Scale Specification */ From a75542b3e77664f5f4be39dac24e9e3c791456da Mon Sep 17 00:00:00 2001 From: bmribler <39579120+bmribler@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:50:10 -0400 Subject: [PATCH 65/94] Detect invalid ID to H5Gmove2 (#4765) User's application segfaulted because the returned value H5I_BADID wasn't detected when H5I_get_type() was called. This PR adds checks for invalid file/group identifiers passed into H5Gmove2. This defect occurs in many other places, hence, issue GH-4764. Fixes #4737 --- src/H5Gdeprec.c | 43 ++++++++++++++++++++------- src/H5L.c | 74 +++++++++++++++++++++++++++++++--------------- src/H5VLcallback.c | 4 +++ test/links.c | 53 +++++++++++++++++++++++++++++---- 4 files changed, 135 insertions(+), 39 deletions(-) diff --git a/src/H5Gdeprec.c b/src/H5Gdeprec.c index 6871283ed03..5f9ad63756e 100644 --- a/src/H5Gdeprec.c +++ b/src/H5Gdeprec.c @@ -519,10 +519,35 @@ H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *d H5VL_loc_params_t loc_params1; H5VL_object_t *vol_obj2 = NULL; /* Object of dst_id */ H5VL_loc_params_t loc_params2; + H5I_type_t src_id_type = H5I_BADID, dst_id_type = H5I_BADID; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) + /* Check arguments */ + if (!src_name || !*src_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified"); + if (!dst_name || !*dst_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified"); + + /* src and dst location IDs cannot both have the value of H5L_SAME_LOC */ + if (src_loc_id == H5L_SAME_LOC && dst_loc_id == H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "current and destination should not both be H5L_SAME_LOC"); + + /* reset an ID in the case of H5L_SAME_LOC */ + if (src_loc_id == H5L_SAME_LOC) + src_loc_id = dst_loc_id; + else if (dst_loc_id == H5L_SAME_LOC) + dst_loc_id = src_loc_id; + + src_id_type = H5I_get_type(src_loc_id); + if (!(H5I_GROUP == src_id_type || H5I_FILE == src_id_type)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group (or file) ID, src_loc_id"); + + dst_id_type = H5I_get_type(dst_loc_id); + if (!(H5I_GROUP == dst_id_type || H5I_FILE == dst_id_type)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group (or file) ID, dst_loc_id"); + /* Set up collective metadata if appropriate */ if (H5CX_set_loc(dst_loc_id) < 0) HGOTO_ERROR(H5E_SYM, H5E_CANTSET, FAIL, "can't set collective metadata read info"); @@ -531,22 +556,20 @@ H5Gmove2(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *d loc_params1.type = H5VL_OBJECT_BY_NAME; loc_params1.loc_data.loc_by_name.name = src_name; loc_params1.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; - loc_params1.obj_type = H5I_get_type(src_loc_id); + loc_params1.obj_type = src_id_type; /* Set location parameter for destination object */ loc_params2.type = H5VL_OBJECT_BY_NAME; loc_params2.loc_data.loc_by_name.name = dst_name; loc_params2.loc_data.loc_by_name.lapl_id = H5P_LINK_ACCESS_DEFAULT; - loc_params2.obj_type = H5I_get_type(dst_loc_id); + loc_params2.obj_type = dst_id_type; - if (H5L_SAME_LOC != src_loc_id) - /* get the location object */ - if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); - if (H5L_SAME_LOC != dst_loc_id) - /* get the location object */ - if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); + /* get the location object */ + if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); + /* get the location object */ + if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Move the link */ if (H5VL_link_move(vol_obj1, &loc_params1, vol_obj2, &loc_params2, H5P_LINK_CREATE_DEFAULT, diff --git a/src/H5L.c b/src/H5L.c index cbc584f6b44..3616cb75a59 100644 --- a/src/H5L.c +++ b/src/H5L.c @@ -94,7 +94,8 @@ H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds H5VL_object_t *vol_obj2 = NULL; /* Object of dst_id */ H5VL_loc_params_t loc_params1; H5VL_loc_params_t loc_params2; - H5VL_object_t tmp_vol_obj; /* Temporary object */ + H5VL_object_t tmp_vol_obj; /* Temporary object */ + H5I_type_t src_id_type = H5I_BADID, dst_id_type = H5I_BADID; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) @@ -106,6 +107,21 @@ H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no current name specified"); if (!dst_name || !*dst_name) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination name specified"); + + /* reset an ID in the case of H5L_SAME_LOC */ + if (src_loc_id == H5L_SAME_LOC) + src_loc_id = dst_loc_id; + else if (dst_loc_id == H5L_SAME_LOC) + dst_loc_id = src_loc_id; + + /* verify that src and dst IDs are either a file or a group ID */ + src_id_type = H5I_get_type(src_loc_id); + if (!(H5I_GROUP == src_id_type || H5I_FILE == src_id_type)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group (or file) ID, src_loc_id"); + dst_id_type = H5I_get_type(dst_loc_id); + if (!(H5I_GROUP == dst_id_type || H5I_FILE == dst_id_type)) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group (or file) ID, dst_loc_id"); + if (lcpl_id != H5P_DEFAULT && (true != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list"); @@ -117,30 +133,27 @@ H5Lmove(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds H5CX_set_lcpl(lcpl_id); /* Verify access property list and set up collective metadata if appropriate */ - if (H5CX_set_apl(&lapl_id, H5P_CLS_LACC, ((src_loc_id != H5L_SAME_LOC) ? src_loc_id : dst_loc_id), true) < - 0) + if (H5CX_set_apl(&lapl_id, H5P_CLS_LACC, dst_loc_id, true) < 0) HGOTO_ERROR(H5E_LINK, H5E_CANTSET, FAIL, "can't set access property list info"); /* Set location parameter for source object */ loc_params1.type = H5VL_OBJECT_BY_NAME; loc_params1.loc_data.loc_by_name.name = src_name; loc_params1.loc_data.loc_by_name.lapl_id = lapl_id; - loc_params1.obj_type = H5I_get_type(src_loc_id); + loc_params1.obj_type = src_id_type; /* Set location parameter for destination object */ loc_params2.type = H5VL_OBJECT_BY_NAME; loc_params2.loc_data.loc_by_name.name = dst_name; loc_params2.loc_data.loc_by_name.lapl_id = lapl_id; - loc_params2.obj_type = H5I_get_type(dst_loc_id); + loc_params2.obj_type = dst_id_type; - if (H5L_SAME_LOC != src_loc_id) - /* Get the location object */ - if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); - if (H5L_SAME_LOC != dst_loc_id) - /* Get the location object */ - if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); + /* Get the location object */ + if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); + /* Get the location object */ + if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL connectors are the same */ if (vol_obj1 && vol_obj2) { @@ -195,7 +208,8 @@ H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds H5VL_loc_params_t loc_params1; H5VL_object_t *vol_obj2 = NULL; /* Object of dst_id */ H5VL_loc_params_t loc_params2; - H5VL_object_t tmp_vol_obj; /* Temporary object */ + H5VL_object_t tmp_vol_obj; /* Temporary object */ + H5I_type_t src_id_type = H5I_BADID, dst_id_type = H5I_BADID; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) @@ -210,6 +224,20 @@ H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds if (lcpl_id != H5P_DEFAULT && (true != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list"); + /* reset an ID in the case of H5L_SAME_LOC */ + if (src_loc_id == H5L_SAME_LOC) + src_loc_id = dst_loc_id; + else if (dst_loc_id == H5L_SAME_LOC) + dst_loc_id = src_loc_id; + + /* verify that src and dst IDs are either a file or a group ID */ + src_id_type = H5I_get_type(src_loc_id); + if (!(H5I_GROUP == src_id_type || H5I_FILE == src_id_type) && src_loc_id != H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group (or file) ID, src_loc_id"); + dst_id_type = H5I_get_type(dst_loc_id); + if (!(H5I_GROUP == dst_id_type || H5I_FILE == dst_id_type) && dst_loc_id != H5L_SAME_LOC) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group (or file) ID, dst_loc_id"); + /* Check the link create property list */ if (H5P_DEFAULT == lcpl_id) lcpl_id = H5P_LINK_CREATE_DEFAULT; @@ -226,22 +254,20 @@ H5Lcopy(hid_t src_loc_id, const char *src_name, hid_t dst_loc_id, const char *ds loc_params1.type = H5VL_OBJECT_BY_NAME; loc_params1.loc_data.loc_by_name.name = src_name; loc_params1.loc_data.loc_by_name.lapl_id = lapl_id; - loc_params1.obj_type = H5I_get_type(src_loc_id); + loc_params1.obj_type = src_id_type; /* Set location parameter for destination object */ loc_params2.type = H5VL_OBJECT_BY_NAME; loc_params2.loc_data.loc_by_name.name = dst_name; loc_params2.loc_data.loc_by_name.lapl_id = lapl_id; - loc_params2.obj_type = H5I_get_type(dst_loc_id); + loc_params2.obj_type = dst_id_type; - if (H5L_SAME_LOC != src_loc_id) - /* Get the location object */ - if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); - if (H5L_SAME_LOC != dst_loc_id) - /* Get the location object */ - if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); + /* Get the location object */ + if (NULL == (vol_obj1 = H5VL_vol_object(src_loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); + /* Get the location object */ + if (NULL == (vol_obj2 = H5VL_vol_object(dst_loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier"); /* Make sure that the VOL connectors are the same */ if (vol_obj1 && vol_obj2) { diff --git a/src/H5VLcallback.c b/src/H5VLcallback.c index 58e839c9985..0e696088ebf 100644 --- a/src/H5VLcallback.c +++ b/src/H5VLcallback.c @@ -5100,6 +5100,10 @@ H5VL_link_move(const H5VL_object_t *src_vol_obj, const H5VL_loc_params_t *loc_pa FUNC_ENTER_NOAPI(FAIL) + /* Sanity check */ + assert(src_vol_obj); + assert(src_vol_obj->data); + /* Set wrapper info in API context */ vol_obj = (src_vol_obj->data ? src_vol_obj : dst_vol_obj); if (H5VL_set_vol_wrapper(vol_obj) < 0) diff --git a/test/links.c b/test/links.c index 6612f56e363..ad9948af04d 100644 --- a/test/links.c +++ b/test/links.c @@ -1938,12 +1938,14 @@ test_move_preserves(hid_t fapl_id, bool new_format) *------------------------------------------------------------------------- */ #ifndef H5_NO_DEPRECATED_SYMBOLS +#define NUM_OBJS 3 /* number of groups in FILENAME[0] file */ static int test_deprec(hid_t fapl, bool new_format) { hid_t file_id = H5I_INVALID_HID; hid_t group1_id = H5I_INVALID_HID; hid_t group2_id = H5I_INVALID_HID; + hid_t group3_id = H5I_INVALID_HID; H5G_stat_t sb_hard1, sb_hard2, sb_soft1, sb_soft2; H5G_obj_t obj_type; /* Object type */ hsize_t num_objs; /* Number of objects in a group */ @@ -1967,6 +1969,8 @@ test_deprec(hid_t fapl, bool new_format) FAIL_STACK_ERROR; if ((group2_id = H5Gcreate2(file_id, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) FAIL_STACK_ERROR; + if ((group3_id = H5Gcreate2(file_id, "group3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + FAIL_STACK_ERROR; /* Test H5Gset and get comment */ @@ -2022,7 +2026,7 @@ test_deprec(hid_t fapl, bool new_format) /* Test getting the number of objects in a group */ if (H5Gget_num_objs(file_id, &num_objs) < 0) FAIL_STACK_ERROR; - if (num_objs != 2) + if (num_objs != NUM_OBJS) TEST_ERROR; if (H5Gget_num_objs(group1_id, &num_objs) < 0) FAIL_STACK_ERROR; @@ -2113,9 +2117,43 @@ test_deprec(hid_t fapl, bool new_format) /* Test H5Gmove and H5Gmove2 */ if (H5Gmove(file_id, "group1", "moved_group1") < 0) - FAIL_STACK_ERROR; + TEST_ERROR; if (H5Gmove2(file_id, "group2", group1_id, "moved_group2") < 0) - FAIL_STACK_ERROR; + TEST_ERROR; + if (H5Gmove2(file_id, "group3", H5L_SAME_LOC, "moved_group3") < 0) + TEST_ERROR; + if (H5Gmove2(file_id, "moved_group3", group2_id, "moved_group3_to_group2") < 0) + TEST_ERROR; + + /* Test H5Gmove2 with H5L_SAME_LOC */ + if (H5Gmove2(group2_id, "moved_group3_to_group2", H5L_SAME_LOC, "group3_same_loc") < 0) + TEST_ERROR; + + /* Test H5Gmove2 with H5L_SAME_LOC */ + if (H5Gmove2(H5L_SAME_LOC, "moved_group1/moved_group2", file_id, "moved_group2_again") < 0) + TEST_ERROR; + + /* Put back moved_group2 for subsequent tests */ + if (H5Gmove2(file_id, "moved_group2_again", file_id, "moved_group1/moved_group2") < 0) + TEST_ERROR; + + /* Test passing in invalid ID */ + H5E_BEGIN_TRY + { + hid_t bad_id = H5I_BADID; + if (H5Gmove2(bad_id, "group2", group1_id, "moved_group2") >= 0) + TEST_ERROR; + } + H5E_END_TRY + + /* Test passing in invalid ID */ + H5E_BEGIN_TRY + { + hid_t bad_id = H5I_BADID; + if (H5Gmove2(file_id, "group2", bad_id, "moved_group2") >= 0) + TEST_ERROR; + } + H5E_END_TRY /* Ensure that both groups can be opened */ if (H5Gclose(group2_id) < 0) @@ -2129,6 +2167,8 @@ test_deprec(hid_t fapl, bool new_format) FAIL_STACK_ERROR; /* Close open IDs */ + if (H5Gclose(group3_id) < 0) + FAIL_STACK_ERROR; if (H5Gclose(group2_id) < 0) FAIL_STACK_ERROR; if (H5Gclose(group1_id) < 0) @@ -2154,6 +2194,7 @@ test_deprec(hid_t fapl, bool new_format) error: H5E_BEGIN_TRY { + H5Gclose(group3_id); H5Gclose(group2_id); H5Gclose(group1_id); H5Fclose(file_id); @@ -3293,7 +3334,8 @@ external_link_closing_deprec(hid_t fapl, bool new_format) /* Test copy (as of this test, it uses the same code as move) */ if (H5Lcopy(fid1, "elink/elink/elink", fid1, "elink/elink/elink_copied", H5P_DEFAULT, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; - if (H5Lcopy(fid1, "elink/elink/elink", fid1, "elink/elink/elink/elink_copied2", H5P_DEFAULT, + /* Also exercise H5L_SAME_LOC */ + if (H5Lcopy(H5L_SAME_LOC, "elink/elink/elink", fid1, "elink/elink/elink/elink_copied2", H5P_DEFAULT, H5P_DEFAULT) < 0) FAIL_STACK_ERROR; @@ -4325,7 +4367,8 @@ lapl_nlinks_deprec(hid_t fapl, bool new_format) */ if (H5Lcopy(fid, "soft17", fid, "soft17/newer_soft", H5P_DEFAULT, plist) < 0) TEST_ERROR; - if (H5Lmove(fid, "soft17/newer_soft", fid, "soft17/newest_soft", H5P_DEFAULT, plist) < 0) + /* Also exercise H5L_SAME_LOC */ + if (H5Lmove(fid, "soft17/newer_soft", H5L_SAME_LOC, "soft17/newest_soft", H5P_DEFAULT, plist) < 0) TEST_ERROR; /* H5Olink */ From f3ca753979be4fc0ecde7238c1341494c5f010f2 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 6 Sep 2024 10:53:32 -0500 Subject: [PATCH 66/94] Fix use of public API calls (#4809) Switch public API calls to private ones. Root cause of #4672, which it fixes. Also minor code cleanups --- src/H5FDfamily.c | 91 +++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/src/H5FDfamily.c b/src/H5FDfamily.c index 642da8d0b66..335c63a94f1 100644 --- a/src/H5FDfamily.c +++ b/src/H5FDfamily.c @@ -30,14 +30,14 @@ #include "H5FDdrvr_module.h" /* This source code file is part of the H5FD driver module */ -#include "H5private.h" /* Generic Functions */ -#include "H5Eprivate.h" /* Error handling */ -#include "H5Fprivate.h" /* File access */ -#include "H5FDprivate.h" /* File drivers */ -#include "H5FDfamily.h" /* Family file driver */ -#include "H5Iprivate.h" /* IDs */ -#include "H5MMprivate.h" /* Memory management */ -#include "H5Pprivate.h" /* Property lists */ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5Fprivate.h" /* File access */ +#include "H5FDprivate.h" /* File drivers */ +#include "H5FDfamily.h" /* Family file driver */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ /* The size of the member name buffers */ #define H5FD_FAM_MEMB_NAME_BUF_SIZE 4096 @@ -187,10 +187,9 @@ H5FD__family_get_default_config(H5FD_family_fapl_t *fa_out) HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "can't set default driver on member FAPL"); done: - if (ret_value < 0 && fa_out->memb_fapl_id >= 0) { + if (ret_value < 0 && fa_out->memb_fapl_id >= 0) if (H5I_dec_ref(fa_out->memb_fapl_id) < 0) HDONE_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't decrement ref. count on member FAPL ID"); - } FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__family_get_default_config() */ @@ -237,6 +236,7 @@ H5FD__family_get_default_printf_filename(const char *old_filename) if (file_extension) { /* Insert the printf format between the filename and ".h5" extension. */ intptr_t beginningLength = file_extension - old_filename; + snprintf(tmp_buffer, new_filename_len, "%.*s%s%s", (int)beginningLength, old_filename, suffix, ".h5"); } else { @@ -246,15 +246,15 @@ H5FD__family_get_default_printf_filename(const char *old_filename) file_extension = strrchr(old_filename, '.'); if (file_extension) { intptr_t beginningLength = file_extension - old_filename; + snprintf(tmp_buffer, new_filename_len, "%.*s%s%s", (int)beginningLength, old_filename, suffix, file_extension); } - else { + else /* If the filename doesn't contain an extension at all, just insert * the printf format at the end of the filename. */ snprintf(tmp_buffer, new_filename_len, "%s%s", old_filename, suffix); - } } ret_value = tmp_buffer; @@ -618,7 +618,7 @@ H5FD__family_sb_decode(H5FD_t *_file, const char H5_ATTR_UNUSED *name, const uns /* Check if member size from file access property is correct */ if (msize != file->pmem_size) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "Family member size should be %lu. But the size from file access property is %lu", (unsigned long)msize, (unsigned long)file->pmem_size); @@ -724,16 +724,16 @@ H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxad file->pmem_size = fa->memb_size; /* Member size passed in through property */ if (default_config && H5I_dec_ref(fa->memb_fapl_id) < 0) - HGOTO_ERROR(H5E_ID, H5E_CANTDEC, NULL, "can't decrement ref. count on member FAPL"); + HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, NULL, "can't decrement ref. count on member FAPL"); } /* end else */ file->name = H5MM_strdup(name); file->flags = flags; /* Allocate space for the string buffers */ if (NULL == (memb_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE))) - HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate member name"); + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate member name"); if (NULL == (temp = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE))) - HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "unable to allocate temporary member name"); + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, NULL, "unable to allocate temporary member name"); /* Check that names are unique */ snprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, name, 0); @@ -746,7 +746,7 @@ H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxad name = temp; } else - HGOTO_ERROR(H5E_FILE, H5E_FILEEXISTS, NULL, "file names not unique"); + HGOTO_ERROR(H5E_VFL, H5E_FILEEXISTS, NULL, "file names not unique"); } /* Open all the family members */ @@ -771,17 +771,14 @@ H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxad * Allow H5F_ACC_CREAT only on the first family member. */ if (0 == file->nmembs) { - if (NULL == (file->memb[file->nmembs] = H5FDopen(memb_name, (0 == file->nmembs ? flags : t_flags), - file->memb_fapl_id, HADDR_UNDEF))) + if (H5FD_open(false, &file->memb[file->nmembs], memb_name, (0 == file->nmembs ? flags : t_flags), + file->memb_fapl_id, HADDR_UNDEF) < 0) HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open member file"); } else { - H5E_PAUSE_ERRORS - { - file->memb[file->nmembs] = H5FDopen(memb_name, (0 == file->nmembs ? flags : t_flags), - file->memb_fapl_id, HADDR_UNDEF); - } - H5E_RESUME_ERRORS + if (H5FD_open(true, &file->memb[file->nmembs], memb_name, (0 == file->nmembs ? flags : t_flags), + file->memb_fapl_id, HADDR_UNDEF) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, NULL, "unable to open member file"); if (!file->memb[file->nmembs]) break; @@ -794,7 +791,7 @@ H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxad * smaller than the size specified through H5Pset_fapl_family(). Update the actual * member size. */ - if ((eof = H5FDget_eof(file->memb[0], H5FD_MEM_DEFAULT))) + if ((eof = H5FD_get_eof(file->memb[0], H5FD_MEM_DEFAULT))) file->memb_size = eof; ret_value = (H5FD_t *)file; @@ -818,7 +815,7 @@ H5FD__family_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxad if (H5FD_close(file->memb[u]) < 0) nerrors++; if (nerrors) - HGOTO_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "unable to close member files"); + HDONE_ERROR(H5E_FILE, H5E_CANTCLOSEFILE, NULL, "unable to close member files"); if (file->memb) H5MM_xfree(file->memb); @@ -906,7 +903,7 @@ H5FD__family_cmp(const H5FD_t *_f1, const H5FD_t *_f2) assert(f1->nmembs >= 1 && f1->memb[0]); assert(f2->nmembs >= 1 && f2->memb[0]); - ret_value = H5FDcmp(f1->memb[0], f2->memb[0]); + ret_value = H5FD_cmp(f1->memb[0], f2->memb[0]); FUNC_LEAVE_NOAPI(ret_value) } /* end H5FD__family_cmp() */ @@ -1000,7 +997,7 @@ H5FD__family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t abs_eoa) /* Allocate space for the member name buffer */ if (NULL == (memb_name = (char *)H5MM_malloc(H5FD_FAM_MEMB_NAME_BUF_SIZE))) - HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, FAIL, "unable to allocate member name"); + HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, FAIL, "unable to allocate member name"); for (u = 0; addr || u < file->nmembs; u++) { @@ -1021,9 +1018,9 @@ H5FD__family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t abs_eoa) file->nmembs = MAX(file->nmembs, u + 1); snprintf(memb_name, H5FD_FAM_MEMB_NAME_BUF_SIZE, file->name, u); H5_CHECK_OVERFLOW(file->memb_size, hsize_t, haddr_t); - if (NULL == (file->memb[u] = H5FDopen(memb_name, file->flags | H5F_ACC_CREAT, file->memb_fapl_id, - (haddr_t)file->memb_size))) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to open member file"); + if (H5FD_open(false, &file->memb[u], memb_name, file->flags | H5F_ACC_CREAT, file->memb_fapl_id, + (haddr_t)file->memb_size) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTOPENFILE, FAIL, "unable to open member file"); } /* end if */ /* Set the EOA marker for the member */ @@ -1031,12 +1028,12 @@ H5FD__family_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t abs_eoa) H5_CHECK_OVERFLOW(file->memb_size, hsize_t, haddr_t); if (addr > (haddr_t)file->memb_size) { if (H5FD_set_eoa(file->memb[u], type, ((haddr_t)file->memb_size - file->pub.base_addr)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set file eoa"); + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to set file eoa"); addr -= file->memb_size; } /* end if */ else { if (H5FD_set_eoa(file->memb[u], type, (addr - file->pub.base_addr)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "unable to set file eoa"); + HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to set file eoa"); addr = 0; } /* end else */ } /* end for */ @@ -1126,12 +1123,12 @@ H5FD__family_get_handle(H5FD_t *_file, hid_t fapl, void **file_handle) /* Get the plist structure and family offset */ if (NULL == (plist = H5P_object_verify(fapl, H5P_FILE_ACCESS))) - HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); + HGOTO_ERROR(H5E_VFL, H5E_BADID, FAIL, "can't find object for ID"); if (H5P_get(plist, H5F_ACS_FAMILY_OFFSET_NAME, &offset) < 0) - HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get offset for family driver"); + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't get offset for family driver"); if (offset > (file->memb_size * file->nmembs)) - HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "offset is bigger than file size"); + HGOTO_ERROR(H5E_VFL, H5E_BADID, FAIL, "offset is bigger than file size"); memb = (int)(offset / file->memb_size); ret_value = H5FD_get_vfd_handle(file->memb[memb], fapl, file_handle); @@ -1192,8 +1189,8 @@ H5FD__family_read(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, s assert(u < file->nmembs); - if (H5FDread(file->memb[u], type, dxpl_id, sub, req, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "member file read failed"); + if (H5FD_read(file->memb[u], type, sub, req, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_READERROR, FAIL, "member file read failed"); addr += req; buf += req; @@ -1254,8 +1251,8 @@ H5FD__family_write(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, assert(u < file->nmembs); - if (H5FDwrite(file->memb[u], type, dxpl_id, sub, req, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "member file write failed"); + if (H5FD_write(file->memb[u], type, sub, req, buf) < 0) + HGOTO_ERROR(H5E_VFL, H5E_WRITEERROR, FAIL, "member file write failed"); addr += req; buf += req; @@ -1290,7 +1287,7 @@ H5FD__family_flush(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool closing) nerrors++; if (nerrors) - HGOTO_ERROR(H5E_IO, H5E_BADVALUE, FAIL, "unable to flush member files"); + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to flush member files"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1321,7 +1318,7 @@ H5FD__family_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, bool closing) nerrors++; if (nerrors) - HGOTO_ERROR(H5E_IO, H5E_BADVALUE, FAIL, "unable to flush member files"); + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "unable to flush member files"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1360,12 +1357,12 @@ H5FD__family_lock(H5FD_t *_file, bool rw) if (u < file->nmembs) { unsigned v; /* Local index variable */ - for (v = 0; v < u; v++) { + for (v = 0; v < u; v++) if (H5FD_unlock(file->memb[v]) < 0) /* Push error, but keep going */ HDONE_ERROR(H5E_IO, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock member files"); - } /* end for */ - HGOTO_ERROR(H5E_IO, H5E_CANTLOCKFILE, FAIL, "unable to lock member files"); + + HGOTO_ERROR(H5E_VFL, H5E_CANTLOCKFILE, FAIL, "unable to lock member files"); } /* end if */ done: @@ -1394,7 +1391,7 @@ H5FD__family_unlock(H5FD_t *_file) for (u = 0; u < file->nmembs; u++) if (file->memb[u]) if (H5FD_unlock(file->memb[u]) < 0) - HGOTO_ERROR(H5E_IO, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock member files"); + HGOTO_ERROR(H5E_VFL, H5E_CANTUNLOCKFILE, FAIL, "unable to unlock member files"); done: FUNC_LEAVE_NOAPI(ret_value) From ec005fb2a2b66542044109c58a19dab4e0f69123 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 6 Sep 2024 10:56:14 -0500 Subject: [PATCH 67/94] Remove call to H5E_clear_stack() (#4810) Remove call to H5E_clear_stack() in H5G_node_debug() Add misc. minor cleanups --- src/H5Gnode.c | 96 +++++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/src/H5Gnode.c b/src/H5Gnode.c index cc45f39b1d6..c89417750e2 100644 --- a/src/H5Gnode.c +++ b/src/H5Gnode.c @@ -288,7 +288,7 @@ H5G__node_create(H5F_t *f, H5B_ins_t H5_ATTR_UNUSED op, void *_lt_key, void H5_A assert(H5B_INS_FIRST == op); if (NULL == (sym = H5FL_CALLOC(H5G_node_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed"); + HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, FAIL, "memory allocation failed"); sym->node_size = H5G_NODE_SIZE(f); if (HADDR_UNDEF == (*addr_p = H5MF_alloc(f, H5FD_MEM_BTREE, (hsize_t)sym->node_size))) HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "unable to allocate file space"); @@ -309,13 +309,12 @@ H5G__node_create(H5F_t *f, H5B_ins_t H5_ATTR_UNUSED op, void *_lt_key, void H5_A rt_key->offset = 0; done: - if (ret_value < 0) { + if (ret_value < 0) if (sym != NULL) { if (sym->entry != NULL) sym->entry = H5FL_SEQ_FREE(H5G_entry_t, sym->entry); sym = H5FL_FREE(H5G_node_t, sym); } /* end if */ - } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_create() */ @@ -472,7 +471,7 @@ H5G__node_found(H5F_t *f, haddr_t addr, const void H5_ATTR_UNUSED *_lt_key, bool * Load the symbol table node for exclusive access. */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to protect symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table node"); /* * Binary search. @@ -504,7 +503,7 @@ H5G__node_found(H5F_t *f, haddr_t addr, const void H5_ATTR_UNUSED *_lt_key, bool done: if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to release symbol table node"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to release symbol table node"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_found() */ @@ -569,7 +568,7 @@ H5G__node_insert(H5F_t *f, haddr_t addr, void H5_ATTR_UNUSED *_lt_key, bool H5_A * Load the symbol node. */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to protect symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect symbol table node"); /* * Where does the new symbol get inserted? We use a binary search. @@ -609,7 +608,7 @@ H5G__node_insert(H5F_t *f, haddr_t addr, void H5_ATTR_UNUSED *_lt_key, bool H5_A HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, H5B_INS_ERROR, "unable to split symbol table node"); if (NULL == (snrt = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, *new_node_p, f, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to split symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to split symbol table node"); H5MM_memcpy(snrt->entry, sn->entry + H5F_SYM_LEAF_K(f), H5F_SYM_LEAF_K(f) * sizeof(H5G_entry_t)); snrt->nsyms = H5F_SYM_LEAF_K(f); @@ -662,9 +661,9 @@ H5G__node_insert(H5F_t *f, haddr_t addr, void H5_ATTR_UNUSED *_lt_key, bool H5_A done: if (snrt && H5AC_unprotect(f, H5AC_SNODE, *new_node_p, snrt, snrt_flags) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to release symbol table node"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release symbol table node"); if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, sn_flags) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5B_INS_ERROR, "unable to release symbol table node"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5B_INS_ERROR, "unable to release symbol table node"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_insert() */ @@ -718,7 +717,7 @@ H5G__node_remove(H5F_t *f, haddr_t addr, void H5_ATTR_NDEBUG_UNUSED *_lt_key /*i /* Load the symbol table */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__NO_FLAGS_SET))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5B_INS_ERROR, "unable to protect symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5B_INS_ERROR, "unable to protect symbol table node"); /* "Normal" removal of a single entry from the symbol table node */ if (udata->common.name != NULL) { @@ -860,7 +859,7 @@ H5G__node_remove(H5F_t *f, haddr_t addr, void H5_ATTR_NDEBUG_UNUSED *_lt_key /*i tmp_oloc.file = f; /* Reduce the link count for all entries in this node */ - for (idx = 0; idx < sn->nsyms; idx++) { + for (idx = 0; idx < sn->nsyms; idx++) if (!(H5G_CACHED_SLINK == sn->entry[idx].type)) { /* Decrement the reference count */ assert(H5_addr_defined(sn->entry[idx].header)); @@ -870,7 +869,6 @@ H5G__node_remove(H5F_t *f, haddr_t addr, void H5_ATTR_NDEBUG_UNUSED *_lt_key /*i HGOTO_ERROR(H5E_SYM, H5E_CANTDELETE, H5B_INS_ERROR, "unable to decrement object link count"); } /* end if */ - } /* end for */ /* * We are about to remove all the symbols in this node. Free this @@ -919,7 +917,7 @@ H5G__node_iterate(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, /* Protect the symbol table node & local heap while we iterate over entries */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node"); /* * Iterate over the symbol table node entries. @@ -954,7 +952,7 @@ H5G__node_iterate(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, done: /* Release resources */ if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_iterate() */ @@ -988,13 +986,13 @@ H5G__node_sumup(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, /* Find the object node and add the number of symbol entries. */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node"); *num_objs += sn->nsyms; done: if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_sumup() */ @@ -1029,7 +1027,7 @@ H5G__node_by_idx(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, /* Get a pointer to the symbol table node */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node"); /* Find the node, locate the object symbol table entry and retrieve the name */ if (udata->idx >= udata->num_objs && udata->idx < (udata->num_objs + sn->nsyms)) { @@ -1051,7 +1049,7 @@ H5G__node_by_idx(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, done: if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_by_idx() */ @@ -1084,14 +1082,14 @@ H5G__node_init(H5F_t *f) /* Allocate & initialize global info for the shared structure */ if (NULL == (shared = H5B_shared_new(f, H5B_SNODE, sizeof_rkey))) - HGOTO_ERROR(H5E_BTREE, H5E_NOSPACE, FAIL, "memory allocation failed for shared B-tree info"); + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "memory allocation failed for shared B-tree info"); /* Set up the "local" information for this file's groups */ /* */ /* Make shared B-tree info reference counted */ if (H5F_SET_GRP_BTREE_SHARED(f, H5UC_create(shared, H5B_shared_free)) < 0) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't create ref-count wrapper for shared B-tree info"); + HGOTO_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create ref-count wrapper for shared B-tree info"); done: FUNC_LEAVE_NOAPI(ret_value) @@ -1155,7 +1153,7 @@ H5G__node_copy(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, const /* load the symbol table into memory from the source file */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node"); /* copy object in this node one by one */ for (i = 0; i < sn->nsyms; i++) { @@ -1223,7 +1221,7 @@ H5G__node_copy(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, const /* Copy the shared object from source to destination */ if (H5O_copy_header_map(&tmp_src_oloc, &new_dst_oloc, cpy_info, true, &obj_type, (void **)&cpy_udata) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy object"); + HGOTO_ERROR(H5E_SYM, H5E_CANTCOPY, H5_ITER_ERROR, "unable to copy object"); /* Set up object creation info for symbol table insertion. Only * case so far is for inserting old-style groups (for caching stab @@ -1247,7 +1245,7 @@ H5G__node_copy(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, const lnk.type = H5L_TYPE_SOFT; if ((lnk.u.soft.name = (char *)H5HL_offset_into(udata->src_heap, src_ent->cache.slink.lval_offset)) == NULL) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, H5_ITER_ERROR, "unable to get link name"); + HGOTO_ERROR(H5E_SYM, H5E_CANTGET, H5_ITER_ERROR, "unable to get link name"); /* Sanity check soft link name, to detect running off the end of the heap block */ max_link_len = udata->src_block_size - src_ent->cache.slink.lval_offset; @@ -1288,7 +1286,7 @@ H5G__node_copy(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr, const done: if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_copy() */ @@ -1325,7 +1323,7 @@ H5G__node_build_table(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr * because we're about to call an application function. */ if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, H5_ITER_ERROR, "unable to load symbol table node"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, H5_ITER_ERROR, "unable to load symbol table node"); /* Check if the link table needs to be extended */ if ((udata->ltable->nlinks + sn->nsyms) >= udata->alloc_nlinks) { @@ -1335,7 +1333,7 @@ H5G__node_build_table(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr /* Re-allocate the link table */ if (NULL == (x = (H5O_link_t *)H5MM_realloc(udata->ltable->lnks, sizeof(H5O_link_t) * na))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5_ITER_ERROR, "memory allocation failed"); + HGOTO_ERROR(H5E_SYM, H5E_CANTALLOC, H5_ITER_ERROR, "memory allocation failed"); udata->ltable->lnks = x; } /* end if */ @@ -1355,7 +1353,7 @@ H5G__node_build_table(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t addr done: /* Release the locked items */ if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, H5_ITER_ERROR, "unable to release object header"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, H5_ITER_ERROR, "unable to release object header"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__node_build_table() */ @@ -1400,9 +1398,8 @@ H5G__node_iterate_size(H5F_t *f, const void H5_ATTR_UNUSED *_lt_key, haddr_t H5_ herr_t H5G_node_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, haddr_t heap_addr) { - H5G_node_t *sn = NULL; - H5HL_t *heap = NULL; - unsigned u; /* Local index variable */ + H5G_node_t *sn = NULL; + H5HL_t *heap = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -1419,22 +1416,17 @@ H5G_node_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, had /* Pin the heap down in memory */ if (heap_addr > 0 && H5_addr_defined(heap_addr)) if (NULL == (heap = H5HL_protect(f, heap_addr, H5AC__READ_ONLY_FLAG))) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to protect symbol table heap"); + HGOTO_ERROR(H5E_SYM, H5E_CANTPROTECT, FAIL, "unable to protect symbol table heap"); - /* - * If we couldn't load the symbol table node, then try loading the - * B-tree node. - */ - if (NULL == (sn = (H5G_node_t *)H5AC_protect(f, H5AC_SNODE, addr, f, H5AC__READ_ONLY_FLAG))) { - H5G_bt_common_t udata; /*data to pass through B-tree */ + /* Try loading symbol table node */ + H5E_PAUSE_ERRORS + { + 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 */ - H5E_clear_stack(); /* discard that error */ - udata.heap = heap; - udata.block_size = H5HL_heap_get_size(heap); - if (H5B_debug(f, addr, stream, indent, fwidth, H5B_SNODE, &udata) < 0) - HGOTO_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL, "unable to debug B-tree node"); - } /* end if */ - else { fprintf(stream, "%*sSymbol Table Node...\n", indent, ""); fprintf(stream, "%*s%-*s %s\n", indent, "", fwidth, "Dirty:", sn->cache_info.is_dirty ? "Yes" : "No"); fprintf(stream, "%*s%-*s %u\n", indent, "", fwidth, @@ -1460,12 +1452,24 @@ H5G_node_debug(H5F_t *f, haddr_t addr, FILE *stream, int indent, int fwidth, had H5G__ent_debug(sn->entry + u, stream, indent, fwidth, heap); } /* end for */ } /* end if */ + /* + * If we couldn't load the symbol table node, then try loading the + * B-tree node. + */ + else { + H5G_bt_common_t udata; /*data to pass through B-tree */ + + udata.heap = heap; + udata.block_size = H5HL_heap_get_size(heap); + if (H5B_debug(f, addr, stream, indent, fwidth, H5B_SNODE, &udata) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to debug B-tree node"); + } /* end else */ done: if (sn && H5AC_unprotect(f, H5AC_SNODE, addr, sn, H5AC__NO_FLAGS_SET) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to release symbol table node"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to release symbol table node"); if (heap && H5HL_unprotect(heap) < 0) - HDONE_ERROR(H5E_SYM, H5E_PROTECT, FAIL, "unable to unprotect symbol table heap"); + HDONE_ERROR(H5E_SYM, H5E_CANTUNPROTECT, FAIL, "unable to unprotect symbol table heap"); FUNC_LEAVE_NOAPI(ret_value) } /* end H5G_node_debug() */ From 285cb76b6651e91aa9574eab35dc6d4653adf909 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:58:20 -0500 Subject: [PATCH 68/94] Enable win Intel signing (#4812) --- .github/workflows/cmake-ctest.yml | 23 +++++++++++++++++++++-- config/cmake/SignPackageFiles.cmake | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 64bae44d511..5f1be87cf3f 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -135,7 +135,7 @@ jobs: uses: jsdaniell/create-json@v1.2.3 with: name: "credentials.json" - dir: 'hdfsrc' + dir: '${{ steps.set-file-base.outputs.SOURCE_BASE }}' json: '{"Endpoint": "${{ secrets.AZURE_ENDPOINT }}","CodeSigningAccountName": "${{ secrets.AZURE_CODE_SIGNING_NAME }}","CertificateProfileName": "${{ secrets.AZURE_CERT_PROFILE_NAME }}"}' if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} @@ -554,7 +554,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: tgz-macos14_clang-dmg-binary - path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz + path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` build_and_test_S3_linux: @@ -683,11 +683,30 @@ jobs: run: 7z x ${{ steps.set-file-base.outputs.FILE_BASE }}.zip shell: bash + - name: Install TrustedSigning (Windows) + run: | + Invoke-WebRequest -Uri https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\nuget.exe + .\nuget.exe install Microsoft.Windows.SDK.BuildTools -Version 10.0.22621.3233 -x + .\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.53 -x + shell: pwsh + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + + - name: create-json + id: create-json + uses: jsdaniell/create-json@v1.2.3 + with: + name: "credentials.json" + dir: '${{ steps.set-file-base.outputs.SOURCE_BASE }}' + json: '{"Endpoint": "${{ secrets.AZURE_ENDPOINT }}","CodeSigningAccountName": "${{ secrets.AZURE_CODE_SIGNING_NAME }}","CertificateProfileName": "${{ secrets.AZURE_CERT_PROFILE_NAME }}"}' + if: ${{ needs.check-secret.outputs.sign-state == 'exists' }} + - name: Run ctest (Windows_intel) with oneapi 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: | cd "${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}" cmake --workflow --preset=${{ inputs.preset_name }}-win-Intel --fresh diff --git a/config/cmake/SignPackageFiles.cmake b/config/cmake/SignPackageFiles.cmake index da5084917fe..81cc5bfff21 100644 --- a/config/cmake/SignPackageFiles.cmake +++ b/config/cmake/SignPackageFiles.cmake @@ -13,7 +13,7 @@ elseif (CPACK_GENERATOR MATCHES "DragNDrop") else () set (CPACK_TARGET_FILE_DIRECTORY "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/${CPACK_PACKAGE_INSTALL_DIRECTORY}") endif () -file (GLOB target_list LIST_DIRECTORIES false "${CPACK_TARGET_FILE_DIRECTORY}/lib/*" "${CPACK_TARGET_FILE_DIRECTORY}/bin/*") +file (GLOB target_list LIST_DIRECTORIES false "${CPACK_TARGET_FILE_DIRECTORY}/lib/*" "${CPACK_TARGET_FILE_DIRECTORY}/bin/*" "${CPACK_TARGET_FILE_DIRECTORY}/lib/plugin/*") foreach (targetfile IN LISTS target_list) if (WIN32) # Sign the targets From 255bd4b0e0c35938636b630ebbe5bae129b8c67b Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Sat, 7 Sep 2024 12:26:11 -0500 Subject: [PATCH 69/94] Remove unneeded file name part (#4814) --- .github/workflows/cmake-ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 5f1be87cf3f..09f3dae35fe 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -534,7 +534,7 @@ jobs: cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/README.md ${{ runner.workspace }}/builddmg/hdf5 cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg ${{ runner.workspace }}/builddmg/hdf5 cd "${{ runner.workspace }}/builddmg" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.arm64.dmg.tar.gz hdf5 + tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz hdf5 shell: bash - name: List files in the space (MacOS_latest) From baa04393fbc09966893fc3a40ea74cec99cc3843 Mon Sep 17 00:00:00 2001 From: Larry Knox Date: Sat, 7 Sep 2024 12:27:33 -0500 Subject: [PATCH 70/94] Change name of libhdf5hl_fortran installed by autotools (#4811) * Change name of libhdf5hl_fortran installed by autotools to libhdf5_hl_fortran to be consistent with CMake install and with other hl lib files. Switched corresponding symlink to libhdf5hl_fortran. Fixes issue #4684. * Update h5fc.in to use renamed libhdf5_hl_fortran. Fix typo in code to create link to libhdf5_hl_fortran.a. * Removed code to create symlink for previous name of renamed lib libhdf5hl_fortran. Add RELEASE.txt entry about changeing name libhdf5hl_fortran to libhdf5_hl_fortran. --- config/commence.am | 2 +- fortran/src/h5fc.in | 2 +- hl/fortran/src/Makefile.am | 23 ++++------------------- release_docs/RELEASE.txt | 6 ++++++ 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/config/commence.am b/config/commence.am index 1f0dc2edda9..05e4b653d89 100644 --- a/config/commence.am +++ b/config/commence.am @@ -37,7 +37,7 @@ LIBH5CPP=$(top_builddir)/c++/src/libhdf5_cpp.la LIBH5JNI=$(top_builddir)/java/src/jni/libhdf5_java.la LIBH5TOOLS=$(top_builddir)/tools/lib/libh5tools.la LIBH5_HL=$(top_builddir)/hl/src/libhdf5_hl.la -LIBH5F_HL=$(top_builddir)/hl/fortran/src/libhdf5hl_fortran.la +LIBH5F_HL=$(top_builddir)/hl/fortran/src/libhdf5_hl_fortran.la LIBH5CPP_HL=$(top_builddir)/hl/c++/src/libhdf5_hl_cpp.la # Install directories that automake doesn't know about diff --git a/fortran/src/h5fc.in b/fortran/src/h5fc.in index 3c044257a49..51440781459 100644 --- a/fortran/src/h5fc.in +++ b/fortran/src/h5fc.in @@ -296,7 +296,7 @@ if test "x$do_link" = "xyes"; then shared_link="" # conditionally link with the hl library if test "X$HL" = "Xhl"; then - libraries=" $libraries -lhdf5hl_fortran -lhdf5_hl -lhdf5_fortran -lhdf5 " + libraries=" $libraries -lhdf5_hl_fortran -lhdf5_hl -lhdf5_fortran -lhdf5 " else libraries=" $libraries -lhdf5_fortran -lhdf5 " fi diff --git a/hl/fortran/src/Makefile.am b/hl/fortran/src/Makefile.am index 5834c9932d7..eef7e8b4dc1 100644 --- a/hl/fortran/src/Makefile.am +++ b/hl/fortran/src/Makefile.am @@ -24,10 +24,10 @@ AM_CPPFLAGS+=-I$(top_srcdir)/src -I$(top_srcdir)/hl/src -I$(top_builddir)/hl/src AM_FCFLAGS+=-I$(top_builddir)/fortran/src $(F9XMODFLAG)$(top_builddir)/fortran/src # Our main target, the high-level fortran library -lib_LTLIBRARIES=libhdf5hl_fortran.la +lib_LTLIBRARIES=libhdf5_hl_fortran.la # Add libtool numbers to the HDF5 HL Fortran library (from config/lt_vers.am) -libhdf5hl_fortran_la_LDFLAGS= -version-info $(LT_HL_F_VERS_INTERFACE):$(LT_HL_F_VERS_REVISION):$(LT_HL_F_VERS_AGE) $(AM_LDFLAGS) +libhdf5_hl_fortran_la_LDFLAGS= -version-info $(LT_HL_F_VERS_INTERFACE):$(LT_HL_F_VERS_REVISION):$(LT_HL_F_VERS_AGE) $(AM_LDFLAGS) # Some Fortran compilers can't build shared libraries, so sometimes we # want to build a shared C library and a static Fortran library. If so, @@ -43,26 +43,11 @@ endif #endif # List sources to include in the HDF5 HL Fortran library. -libhdf5hl_fortran_la_SOURCES=H5DSfc.c H5LTfc.c H5IMfc.c H5IMcc.c H5TBfc.c \ +libhdf5_hl_fortran_la_SOURCES=H5DSfc.c H5LTfc.c H5IMfc.c H5IMcc.c H5TBfc.c \ H5DSff.F90 H5LTff.F90 H5TBff.F90 H5IMff.F90 H5DOff.F90 H5LTff_gen.F90 H5TBff_gen.F90 # HDF5 HL Fortran library depends on HDF5 Library. -libhdf5hl_fortran_la_LIBADD=$(LIBH5_HL) $(LIBH5F) - -# The name of the lib file doesn't follow the same pattern as the other hl lib -# files, namely libhdf5_hl_*. Add a symlink with the compliant name to the -# actual lib file. -install-exec-hook: - cd $(DESTDIR)$(libdir) && \ - if test -f libhdf5hl_fortran.a -a \ - ! -f libhdf5_hl_fortran.a; then \ - $(LN_S) libhdf5hl_fortran.a libhdf5_hl_fortran.a; \ - fi; \ - if test -f libhdf5hl_fortran.so -a \ - ! -f libhdf5_hl_fortran.so; then \ - $(LN_S) libhdf5hl_fortran.so libhdf5_hl_fortran.so; \ - fi; - +libhdf5_hl_fortran_la_LIBADD=$(LIBH5_HL) $(LIBH5F) # Fortran module files can have different extensions and different names # (e.g., different capitalizations) on different platforms. Write rules diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 89ed27fa5dc..0686bd47739 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -1767,6 +1767,12 @@ Bug Fixes since HDF5-1.14.0 release Configuration ------------- + - Changed name of libhdf5hl_fortran installed by autotools to libhdf5_hl_fortran. The + new name is consistent with the name of the lib when installed by CMake and with the + other hl libs. + + Fixes GitHub issue #4811 + - Fixed usage issue with FindZLIB.cmake module When building HDF5 with CMake and relying on the FindZLIB.cmake module, From 92532bbec8d465636d14d81da1b689e41dce871b Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sat, 7 Sep 2024 12:38:46 -0500 Subject: [PATCH 71/94] Rename and add more locking infrastructure (#4729) Rename existing recursive R/W locks from H5TS_rw_lock_t to H5TS_rec_rwlock_t, so it's more obvious that they are recursive. Add non-recursive R/W lock, H5TS_rwlock_t Add spinlock, H5TS_spinlock_t Add an atomic void pointer, H5TS_atomic_voidp_t --- src/CMakeLists.txt | 1 + src/H5TSatomic.c | 61 +- src/H5TSatomic.h | 69 +- src/H5TSpkg.h | 81 +- src/H5TSprivate.h | 92 ++- src/H5TSrec_rwlock.c | 745 ++++++++++++++++++ src/H5TSrwlock.c | 650 ++------------- src/H5TSrwlock.h | 405 ++++++++++ src/Makefile.am | 2 +- test/CMakeLists.txt | 3 +- test/Makefile.am | 3 +- test/ttsafe.c | 9 +- test/ttsafe.h | 11 +- ...safe_rec_rw_lock.c => ttsafe_rec_rwlock.c} | 424 +++++----- test/ttsafe_rwlock.c | 317 ++++++++ test/ttsafe_semaphore.c | 27 +- 16 files changed, 2043 insertions(+), 857 deletions(-) create mode 100644 src/H5TSrec_rwlock.c create mode 100644 src/H5TSrwlock.h rename test/{ttsafe_rec_rw_lock.c => ttsafe_rec_rwlock.c} (77%) create mode 100644 test/ttsafe_rwlock.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2fadc0e039a..47fc1dcf751 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -650,6 +650,7 @@ set (H5TS_SOURCES ${HDF5_SRC_DIR}/H5TSonce.c ${HDF5_SRC_DIR}/H5TSpool.c ${HDF5_SRC_DIR}/H5TSpthread.c + ${HDF5_SRC_DIR}/H5TSrec_rwlock.c ${HDF5_SRC_DIR}/H5TSrwlock.c ${HDF5_SRC_DIR}/H5TSsemaphore.c ${HDF5_SRC_DIR}/H5TSthread.c diff --git a/src/H5TSatomic.c b/src/H5TSatomic.c index 1e3798cd026..e765a5f491a 100644 --- a/src/H5TSatomic.c +++ b/src/H5TSatomic.c @@ -77,8 +77,7 @@ H5TS_atomic_init_int(H5TS_atomic_int_t *obj, int desired) { FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Initialize mutex that protects the "atomic" value */ - (void) + /* Initialize mutex that protects the "atomic" value */ H5TS_mutex_init(&obj->mutex, H5TS_MUTEX_TYPE_PLAIN); /* Set the value */ @@ -104,8 +103,7 @@ H5TS_atomic_destroy_int(H5TS_atomic_int_t *obj) { FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Destroy mutex that protects the "atomic" value */ - (void) + /* Destroy mutex that protects the "atomic" value */ H5TS_mutex_destroy(&obj->mutex); FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY @@ -128,8 +126,7 @@ H5TS_atomic_init_uint(H5TS_atomic_uint_t *obj, unsigned desired) { FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Initialize mutex that protects the "atomic" value */ - (void) + /* Initialize mutex that protects the "atomic" value */ H5TS_mutex_init(&obj->mutex, H5TS_MUTEX_TYPE_PLAIN); /* Set the value */ @@ -155,13 +152,61 @@ H5TS_atomic_destroy_uint(H5TS_atomic_uint_t *obj) { FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Destroy mutex that protects the "atomic" value */ - (void) + /* Destroy mutex that protects the "atomic" value */ H5TS_mutex_destroy(&obj->mutex); FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY } /* end H5TS_atomic_destroy_uint() */ +/*-------------------------------------------------------------------------- + * Function: H5TS_atomic_init_voidp + * + * Purpose: Initializes an atomic 'void *' variable object with a value. + * + * Note: Per the C11 standard, this function is not atomic and + * concurrent execution from multiple threads is a data race. + * + * Return: None + * + *-------------------------------------------------------------------------- + */ +void +H5TS_atomic_init_voidp(H5TS_atomic_voidp_t *obj, void *desired) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Initialize mutex that protects the "atomic" value */ + H5TS_mutex_init(&obj->mutex, H5TS_MUTEX_TYPE_PLAIN); + + /* Set the value */ + obj->value = desired; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS_atomic_init_voidp() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_atomic_destroy_voidp + * + * Purpose: Destroys / releases resources for an atomic 'void *' variable + * + * Note: No equivalent in the C11 atomics, but needed here, to destroy + * the mutex used to protect the atomic value. + * + * Return: None + * + *-------------------------------------------------------------------------- + */ +void +H5TS_atomic_destroy_voidp(H5TS_atomic_voidp_t *obj) +{ + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + /* Destroy mutex that protects the "atomic" value */ + H5TS_mutex_destroy(&obj->mutex); + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS_atomic_destroy_voidp() */ + #endif /* H5_HAVE_STDATOMIC_H */ #endif /* H5_HAVE_THREADS */ diff --git a/src/H5TSatomic.h b/src/H5TSatomic.h index dc6e5e4ca0e..478760e8c4d 100644 --- a/src/H5TSatomic.h +++ b/src/H5TSatomic.h @@ -277,4 +277,71 @@ H5TS_atomic_fetch_sub_uint(H5TS_atomic_uint_t *obj, unsigned arg) return ret_value; } /* end H5TS_atomic_fetch_sub_uint() */ -#endif /* H5_HAVE_THREADS */ +/*-------------------------------------------------------------------------- + * Function: H5TS_atomic_exchange_voidp + * + * Purpose: Atomically replaces the value of an atomic 'void *' variable + * and returns the value held previously. + * + * Return: Returns the value of the atomic variable held previously + * + *-------------------------------------------------------------------------- + */ +static inline void * +H5TS_atomic_exchange_voidp(H5TS_atomic_voidp_t *obj, void *desired) +{ + void *ret_value; + + /* Lock mutex that protects the "atomic" value */ + H5TS_mutex_lock(&obj->mutex); + + /* Get the current value */ + ret_value = obj->value; + + /* Set the value */ + obj->value = desired; + + /* Release the object's mutex */ + H5TS_mutex_unlock(&obj->mutex); + + return ret_value; +} /* end H5TS_atomic_exchange_voidp() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS_atomic_compare_exchange_strong_voidp + * + * Purpose: Atomically compares the contents of 'obj' with 'expected', and + * if those are bitwise equal, replaces the former with 'desired' + * (performs read-modify-write operation). Otherwise, loads the + * actual contents of 'obj' into '*expected' (performs load + * operation). + * + * Return: The result of the comparison: true if 'obj' was equal to + * 'expected', false otherwise. + * + *-------------------------------------------------------------------------- + */ +static inline bool +H5TS_atomic_compare_exchange_strong_voidp(H5TS_atomic_voidp_t *obj, void **expected, void *desired) +{ + bool ret_value; + + /* Lock mutex that protects the "atomic" value */ + H5TS_mutex_lock(&obj->mutex); + + /* Compare 'obj' w/'expected' */ + if (obj->value == *expected) { + obj->value = desired; + ret_value = true; + } + else { + *expected = obj->value; + ret_value = false; + } + /* Release the object's mutex */ + H5TS_mutex_unlock(&obj->mutex); + + return ret_value; +} /* end H5TS_atomic_compare_exchange_strong_voidp() */ + +#endif /* H5_HAVE_STDATOMIC_H */ diff --git a/src/H5TSpkg.h b/src/H5TSpkg.h index c2ff919f2f3..b90f4110d6b 100644 --- a/src/H5TSpkg.h +++ b/src/H5TSpkg.h @@ -34,9 +34,9 @@ /* Enable statistics for recursive R/W lock when H5TS debugging is enabled */ #ifdef H5TS_DEBUG -#define H5TS_ENABLE_REC_RW_LOCK_STATS 1 +#define H5TS_ENABLE_REC_RWLOCK_STATS 1 #else -#define H5TS_ENABLE_REC_RW_LOCK_STATS 0 +#define H5TS_ENABLE_REC_RWLOCK_STATS 0 #endif /****************************/ @@ -57,10 +57,10 @@ typedef struct H5TS_api_info_t { } H5TS_api_info_t; #endif /* H5_HAVE_THREADSAFE */ -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /****************************************************************************** * - * Structure H5TS_rw_lock_stats_t + * Structure H5TS_rec_rwlock_stats_t * * Statistics for the recursive R/W lock. * @@ -118,7 +118,7 @@ typedef struct H5TS_api_info_t { * ******************************************************************************/ -typedef struct H5TS_rw_lock_stats_t { +typedef struct H5TS_rec_rwlock_stats_t { int64_t read_locks_granted; int64_t read_locks_released; int64_t real_read_locks_granted; @@ -134,36 +134,35 @@ typedef struct H5TS_rw_lock_stats_t { int64_t max_write_lock_recursion_depth; int64_t write_locks_delayed; int64_t max_write_locks_pending; -} H5TS_rw_lock_stats_t; +} H5TS_rec_rwlock_stats_t; #endif /****************************************************************************** * - * Structure H5TS_rw_lock_t + * Structure H5TS_rec_rwlock_t * * A recursive readers / writer (R/W) lock. * - * This structure holds the fields needed to implement a recursive R/W lock - * that allows recursive write locks, and for the associated statistics - * collection fields. + * This structure holds the fields needed to implement a recursive R/W lock that + * allows recursive write locks, and the associated statistics collection fields. * * Note that we can't use the pthreads or Win32 R/W locks: they permit * recursive read locks, but disallow recursive write locks. * * Individual fields are: * - * mutex: Mutex used to maintain mutual exclusion on the fields of - * of this structure. + * mutex: Mutex used to maintain mutual exclusion on the fields of this + * structure. * * lock_type: Whether the lock is unused, a reader, or a writer. * * writers_cv: Condition variable used for waiting writers. * - * write_thread: The thread that owns a write lock, which is recursive - * for that thread. + * write_thread: The thread that owns a write lock, which is recursive for + * that thread. * - * rec_write_lock_count: The # of recursive write locks outstanding - * for the thread that owns the write lock. + * rec_write_lock_count: The # of recursive write locks outstanding for the + * thread that owns the write lock. * * waiting_writers_count: The count of waiting writers. * @@ -171,28 +170,27 @@ typedef struct H5TS_rw_lock_stats_t { * * reader_thread_count: The # of threads holding a read lock. * - * rec_read_lock_count_key: Instance of thread-local key used to maintain - * a thread-specific recursive lock count for each thread - * holding a read lock. + * rec_read_lock_count_key: Instance of thread-local key used to maintain a + * recursive lock count for each thread holding a read lock. * - * is_key_registered: Flag to track if the rec_read_lock_count_key has been + * is_key_registered: Flag to track if the read_lock_count_key has been * registered yet for a lock. * - * stats: Instance of H5TS_rw_lock_stats_t used to track - * statistics on the recursive R/W lock. + * stats: Instance of H5TS_rec_rwlock_stats_t used to track statistics + * on the lock. * ******************************************************************************/ typedef enum { - H5TS_RW_LOCK_UNUSED = 0, /* Lock is currently unused */ - H5TS_RW_LOCK_WRITE, /* Lock is a recursive write lock */ - H5TS_RW_LOCK_READ /* Lock is a recursive read lock */ -} H5TS_rw_lock_type_t; + H5TS_REC_RWLOCK_UNUSED = 0, /* Lock is currently unused */ + H5TS_REC_RWLOCK_WRITE, /* Lock is a recursive write lock */ + H5TS_REC_RWLOCK_READ /* Lock is a recursive read lock */ +} H5TS_rec_rwlock_type_t; -typedef struct H5TS_rw_lock_t { +typedef struct H5TS_rec_rwlock_t { /* General fields */ - H5TS_mutex_t mutex; - H5TS_rw_lock_type_t lock_type; + H5TS_mutex_t mutex; + H5TS_rec_rwlock_type_t lock_type; /* Writer fields */ H5TS_cond_t writers_cv; @@ -206,11 +204,11 @@ typedef struct H5TS_rw_lock_t { H5TS_key_t rec_read_lock_count_key; bool is_key_registered; -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Stats */ - H5TS_rw_lock_stats_t stats; + H5TS_rec_rwlock_stats_t stats; #endif -} H5TS_rw_lock_t; +} H5TS_rec_rwlock_t; /*****************************/ /* Package Private Variables */ @@ -237,11 +235,12 @@ H5_DLL herr_t H5TS__tinfo_term(void); #endif /* H5_HAVE_THREADSAFE */ /* Recursive R/W lock related function declarations */ -H5_DLL herr_t H5TS__rw_lock_init(H5TS_rw_lock_t *rw_lock); -H5_DLL herr_t H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock); -H5_DLL herr_t H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock); -H5_DLL herr_t H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock); -H5_DLL herr_t H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock); +H5_DLL herr_t H5TS__rec_rwlock_init(H5TS_rec_rwlock_t *lock); +H5_DLL herr_t H5TS__rec_rwlock_rdlock(H5TS_rec_rwlock_t *lock); +H5_DLL herr_t H5TS__rec_rwlock_wrlock(H5TS_rec_rwlock_t *lock); +H5_DLL herr_t H5TS__rec_rwlock_rdunlock(H5TS_rec_rwlock_t *lock); +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 @@ -256,10 +255,10 @@ H5_DLL void H5TS__pthread_first_thread_init(void); #endif #endif /* H5_HAVE_THREADSAFE */ -#if H5TS_ENABLE_REC_RW_LOCK_STATS -H5_DLL herr_t H5TS__rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats); -H5_DLL herr_t H5TS__rw_lock_reset_stats(H5TS_rw_lock_t *rw_lock); -H5_DLL herr_t H5TS__rw_lock_print_stats(const char *header_str, H5TS_rw_lock_stats_t *stats); +#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); +H5_DLL herr_t H5TS__rec_rwlock_reset_stats(H5TS_rec_rwlock_t *lock); +H5_DLL herr_t H5TS__rec_rwlock_print_stats(const char *header_str, H5TS_rec_rwlock_stats_t *stats); #endif #endif /* H5_HAVE_THREADS */ diff --git a/src/H5TSprivate.h b/src/H5TSprivate.h index ccba5b8c390..d2be12414d6 100644 --- a/src/H5TSprivate.h +++ b/src/H5TSprivate.h @@ -99,7 +99,44 @@ #define H5TS_atomic_fetch_add_uint(obj, arg) atomic_fetch_add((obj), (arg)) #define H5TS_atomic_fetch_sub_uint(obj, arg) atomic_fetch_sub((obj), (arg)) #define H5TS_atomic_destroy_uint(obj) /* void */ -#endif /* H5_HAVE_STDATOMIC_H */ + +/* atomic_voidp */ +#define H5TS_atomic_init_voidp(obj, desired) atomic_init((obj), (desired)) +#define H5TS_atomic_exchange_voidp(obj, desired) atomic_exchange((obj), (desired)) +#define H5TS_atomic_compare_exchange_strong_voidp(obj, expected, desired) \ + atomic_compare_exchange_strong((obj), (expected), (desired)) +#define H5TS_atomic_destroy_voidp(obj) /* void */ +#endif /* H5_HAVE_STDATOMIC_H */ + +#if defined(H5_HAVE_STDATOMIC_H) +/* Spinlock operations, built from C11 atomics. Generally follows the example + * here: http://en.cppreference.com/w/cpp/atomic/atomic_flag with some memory + * order improvements. + * + * Note: Pass a pointer to a H5TS_spinlock_t to all the spinlock macros. + * + */ + +/* Initialize the lock */ +#define H5TS_SPINLOCK_INIT(lock) \ + do { \ + *(lock) = ATOMIC_FLAG_INIT; \ + } while (0) + +/* Acquire the lock */ +#define H5TS_SPINLOCK_LOCK(lock) \ + do { \ + while (atomic_flag_test_and_set_explicit(lock, memory_order_acquire)) \ + ; \ + } while (0) + +/* Release the lock */ +#define H5TS_SPINLOCK_UNLOCK(lock) \ + do { \ + atomic_flag_clear_explicit(lock, memory_order_release); \ + } while (0) + +#endif /****************************/ /* Library Private Typedefs */ @@ -113,6 +150,14 @@ typedef struct H5TS_pool_t H5TS_pool_t; /* Portability aliases */ #ifdef H5_HAVE_C11_THREADS + +/* Non-recursive readers/writer lock */ +typedef struct H5TS_rwlock_t { + mtx_t mutex; + cnd_t read_cv, write_cv; + unsigned readers, writers, read_waiters, write_waiters; +} H5TS_rwlock_t; + typedef thrd_t H5TS_thread_t; typedef int (*H5TS_thread_start_func_t)(void *); typedef int H5TS_thread_ret_t; @@ -128,17 +173,19 @@ typedef LPTHREAD_START_ROUTINE H5TS_thread_start_func_t; typedef DWORD H5TS_thread_ret_t; typedef DWORD H5TS_key_t; typedef CRITICAL_SECTION H5TS_CAPABILITY("mutex") H5TS_mutex_t; +typedef SRWLOCK H5TS_rwlock_t; typedef CONDITION_VARIABLE H5TS_cond_t; typedef INIT_ONCE H5TS_once_t; typedef PINIT_ONCE_FN H5TS_once_init_func_t; #else typedef pthread_t H5TS_thread_t; typedef void *(*H5TS_thread_start_func_t)(void *); -typedef 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_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_once_init_func_t)(void); #endif #endif @@ -147,6 +194,12 @@ typedef void (*H5TS_once_init_func_t)(void); #if defined(H5_HAVE_STDATOMIC_H) && !defined(__cplusplus) typedef atomic_int H5TS_atomic_int_t; typedef atomic_uint H5TS_atomic_uint_t; +/* Suppress warning about _Atomic keyword not supported in C99 */ +H5_GCC_DIAG_OFF("c99-c11-compat") +H5_CLANG_DIAG_OFF("c11-extensions") +typedef void *_Atomic H5TS_atomic_voidp_t; +H5_GCC_DIAG_ON("c99-c11-compat") +H5_CLANG_DIAG_ON("c11-extensions") #else typedef struct { H5TS_mutex_t mutex; @@ -156,6 +209,10 @@ typedef struct { H5TS_mutex_t mutex; unsigned value; } H5TS_atomic_uint_t; +typedef struct { + H5TS_mutex_t mutex; + void *value; +} H5TS_atomic_voidp_t; #endif /* Thread Barrier */ @@ -203,6 +260,11 @@ typedef struct H5TS_semaphore_t { } H5TS_semaphore_t; #endif +#if defined(H5_HAVE_STDATOMIC_H) && !defined(__cplusplus) +/* Spinlock, built from C11 atomic_flag */ +typedef atomic_flag H5TS_spinlock_t; +#endif + /*****************************/ /* Library-private Variables */ /*****************************/ @@ -234,6 +296,15 @@ H5_DLL herr_t H5TS_mutex_init(H5TS_mutex_t *mutex, int type); H5_DLL herr_t H5TS_mutex_trylock(H5TS_mutex_t *mutex, bool *acquired) H5TS_TRY_ACQUIRE(SUCCEED, *mutex); H5_DLL herr_t H5TS_mutex_destroy(H5TS_mutex_t *mutex); +/* R/W locks */ +H5_DLL herr_t H5TS_rwlock_init(H5TS_rwlock_t *lock); +/* R/W lock & unlock calls are defined in H5TSrwlock.h */ +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_wrunlock(H5TS_rwlock_t *lock); +H5_DLL herr_t H5TS_rwlock_destroy(H5TS_rwlock_t *lock); + /* Condition variable operations */ H5_DLL herr_t H5TS_cond_init(H5TS_cond_t *cond); /* Condition variable wait, signal, broadcast calls are defined in H5TScond.h */ @@ -275,6 +346,14 @@ static inline void H5TS_atomic_store_uint(H5TS_atomic_uint_t *obj, unsigned static inline unsigned H5TS_atomic_fetch_add_uint(H5TS_atomic_uint_t *obj, unsigned arg); static inline unsigned H5TS_atomic_fetch_sub_uint(H5TS_atomic_uint_t *obj, unsigned arg); H5_DLL void H5TS_atomic_destroy_uint(H5TS_atomic_uint_t *obj); + +/* void * _Atomic (atomic void pointer) */ +H5_DLL void H5TS_atomic_init_voidp(H5TS_atomic_voidp_t *obj, void *desired); +/* Atomic 'void *' load, store, etc. calls are defined in H5TSatomic.h */ +static inline void *H5TS_atomic_exchange_voidp(H5TS_atomic_voidp_t *obj, void *desired); +static inline bool H5TS_atomic_compare_exchange_strong_voidp(H5TS_atomic_voidp_t *obj, void **expected, + void *desired); +H5_DLL void H5TS_atomic_destroy_voidp(H5TS_atomic_voidp_t *obj); #endif /* H5_HAVE_STDATOMIC_H */ /* Barrier related function declarations */ @@ -297,6 +376,7 @@ H5_DLL herr_t H5TS_semaphore_destroy(H5TS_semaphore_t *sem); #include "H5TSatomic.h" #endif /* H5_HAVE_STDATOMIC_H */ #include "H5TSbarrier.h" +#include "H5TSrwlock.h" #include "H5TSsemaphore.h" #include "H5TSpool.h" diff --git a/src/H5TSrec_rwlock.c b/src/H5TSrec_rwlock.c new file mode 100644 index 00000000000..e191aa3a290 --- /dev/null +++ b/src/H5TSrec_rwlock.c @@ -0,0 +1,745 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: This file contains support for recursive R/W locks, equivalent to + * the pthread 'pthread_rwlock_t' type and capabilities, except that + * threads that hold write access for the lock are allowed to acquire + * write access again (and must match each lock with an unlock operation). + * + * Note: Because this threadsafety framework operates outside the library, + * it does not use the error stack (although it does use error macros + * that don't push errors on a stack) and only uses the "namecheck only" + * FUNC_ENTER_* / FUNC_LEAVE_* macros. + */ + +/****************/ +/* Module Setup */ +/****************/ + +#include "H5TSmodule.h" /* This source code file is part of the H5TS module */ + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5TSpkg.h" /* Threadsafety */ + +#ifdef H5_HAVE_THREADS + +/****************/ +/* Local Macros */ +/****************/ + +/******************/ +/* Local Typedefs */ +/******************/ + +/* + * Count of the number of active [recursive] read lock calls for a given thread. + * The # of readers for the lock in question is decremented when the recursive + * read lock count drops to zero. + */ +typedef int64_t H5TS_rec_entry_count_t; + +/********************/ +/* Local Prototypes */ +/********************/ + +/*********************/ +/* Package Variables */ +/*********************/ + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + +/*******************/ +/* Local Variables */ +/*******************/ + +#if H5TS_ENABLE_REC_RWLOCK_STATS +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_rdlock + * + * Purpose: Update stats for acquiring a read lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_rdlock(H5TS_rec_rwlock_t *lock, const H5TS_rec_entry_count_t *count) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(lock); + assert(H5TS_REC_RWLOCK_READ == lock->lock_type); + assert(count); + assert(*count >= 1); + + lock->stats.read_locks_granted++; + + if (*count == 1) { + lock->stats.real_read_locks_granted++; + if (lock->reader_thread_count > lock->stats.max_read_locks) + lock->stats.max_read_locks = lock->reader_thread_count; + } + + if (*count > lock->stats.max_read_lock_recursion_depth) + lock->stats.max_read_lock_recursion_depth = *count; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_rdlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_rd_lock_delay + * + * Purpose: Update stats for delay in acquiring a read lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_rd_lock_delay(H5TS_rec_rwlock_t *lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(lock); + + lock->stats.read_locks_delayed++; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_rd_lock_delay() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_rd_unlock + * + * Purpose: Update stats for releasing a read lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_rd_unlock(H5TS_rec_rwlock_t *lock, const H5TS_rec_entry_count_t *count) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(lock); + assert(H5TS_REC_RWLOCK_READ == lock->lock_type); + assert(count); + assert(*count >= 0); + + lock->stats.read_locks_released++; + + if (*count == 0) + lock->stats.real_read_locks_released++; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_rd_unlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_wr_lock + * + * Purpose: Update stats for acquiring a write lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_wr_lock(H5TS_rec_rwlock_t *lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(lock); + assert(H5TS_REC_RWLOCK_WRITE == lock->lock_type); + assert(lock->rec_write_lock_count >= 1); + + lock->stats.write_locks_granted++; + + if (lock->rec_write_lock_count == 1) { + lock->stats.real_write_locks_granted++; + if (lock->rec_write_lock_count > lock->stats.max_write_locks) + lock->stats.max_write_locks = lock->rec_write_lock_count; + } + + if (lock->rec_write_lock_count > lock->stats.max_write_lock_recursion_depth) + lock->stats.max_write_lock_recursion_depth = lock->rec_write_lock_count; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_wr_lock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_wr_lock_delay + * + * Purpose: Update stats for delay in acquiring a write lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_wr_lock_delay(H5TS_rec_rwlock_t *lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(lock); + + lock->stats.write_locks_delayed++; + + if (lock->stats.max_write_locks_pending <= lock->waiting_writers_count) + lock->stats.max_write_locks_pending = lock->waiting_writers_count + 1; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_wr_lock_delay() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__update_stats_wr_unlock + * + * Purpose: Update stats for releasing a write lock + * + * Return: none + * + *-------------------------------------------------------------------------- + */ +static void +H5TS__update_stats_wr_unlock(H5TS_rec_rwlock_t *lock) +{ + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + assert(lock); + assert(H5TS_REC_RWLOCK_WRITE == lock->lock_type); + assert(lock->rec_write_lock_count >= 0); + + lock->stats.write_locks_released++; + + if (lock->rec_write_lock_count == 0) + lock->stats.real_write_locks_released++; + + FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY +} /* end H5TS__update_stats_wr_unlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_get_stats + * + * Purpose: Obtain a copy of the current statistics for a recursive + * read / write lock. + * + * Note: To obtain a consistent set of statistics, the function must + * obtain the lock mutex. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_get_stats(H5TS_rec_rwlock_t *lock, H5TS_rec_rwlock_stats_t *stats) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock || NULL == stats)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex))) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Copy R/W lock stats */ + *stats = lock->stats; + +done: + if (H5_LIKELY(have_mutex)) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex) < 0)) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_get_stats() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_reset_stats + * + * Purpose: Reset the statistics for the supplied recursive read / write + * lock. + * + * Note: To obtain a consistent set of statistics, the function must + * obtain the lock mutex. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_reset_stats(H5TS_rec_rwlock_t *lock) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex) < 0)) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Reset stats */ + memset(&lock->stats, 0, sizeof(lock->stats)); + +done: + if (H5_LIKELY(have_mutex)) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex) < 0)) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_reset_stats() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_print_stats + * + * Purpose: Print statistics for the supplied recursive R/W lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_print_stats(const char *header_str, H5TS_rec_rwlock_stats_t *stats) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == header_str || NULL == stats)) + HGOTO_DONE(FAIL); + + fprintf(stdout, "\n\n%s\n\n", header_str); + fprintf(stdout, " read_locks_granted = %" PRId64 "\n", stats->read_locks_granted); + fprintf(stdout, " read_locks_released = %" PRId64 "\n", stats->read_locks_released); + fprintf(stdout, " real_read_locks_granted = %" PRId64 "\n", stats->real_read_locks_granted); + fprintf(stdout, " real_read_locks_released = %" PRId64 "\n", stats->real_read_locks_released); + fprintf(stdout, " max_read_locks = %" PRId64 "\n", stats->max_read_locks); + fprintf(stdout, " max_read_lock_recursion_depth = %" PRId64 "\n", stats->max_read_lock_recursion_depth); + fprintf(stdout, " read_locks_delayed = %" PRId64 "\n", stats->read_locks_delayed); + fprintf(stdout, " write_locks_granted = %" PRId64 "\n", stats->write_locks_granted); + fprintf(stdout, " write_locks_released = %" PRId64 "\n", stats->write_locks_released); + fprintf(stdout, " real_write_locks_granted = %" PRId64 "\n", stats->real_write_locks_granted); + fprintf(stdout, " real_write_locks_released = %" PRId64 "\n", stats->real_write_locks_released); + fprintf(stdout, " max_write_locks = %" PRId64 "\n", stats->max_write_locks); + fprintf(stdout, " max_write_lock_recursion_depth = %" PRId64 "\n", + stats->max_write_lock_recursion_depth); + fprintf(stdout, " write_locks_delayed = %" PRId64 "\n", stats->write_locks_delayed); + fprintf(stdout, " max_write_locks_pending = %" PRId64 "\n\n", stats->max_write_locks_pending); + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_print_stats() */ +#endif /* H5TS_ENABLE_REC_RWLOCK_STATS */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_init + * + * Purpose: Initialize the supplied instance of H5TS_rec_rwlock_t. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_init(H5TS_rec_rwlock_t *lock) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + +#ifdef H5_HAVE_WIN_THREADS + /* The current H5TS_rec_rwlock_t implementation uses H5TS_key_create() with a + * key destructor callback, which is not [currently] supported by Windows. + */ + HGOTO_DONE(FAIL); +#else + /* Initialize the lock */ + memset(lock, 0, sizeof(*lock)); + HDcompile_assert(H5TS_REC_RWLOCK_UNUSED == 0); + if (H5_UNLIKELY(H5TS_mutex_init(&lock->mutex, H5TS_MUTEX_TYPE_PLAIN) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_cond_init(&lock->writers_cv) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_cond_init(&lock->readers_cv) < 0)) + HGOTO_DONE(FAIL); +#endif + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_init() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_destroy + * + * Purpose: Take down an instance of H5TS_rec_rwlock_t. All mutex, condition + * variables, and keys are destroyed. However, the instance of + * H5TS_rec_rwlock_t is not freed. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_destroy(H5TS_rec_rwlock_t *lock) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Call the appropriate destroy routines. We are committed + * to the destroy at this point, so call them all, even if one fails + * along the way. + */ + if (H5_UNLIKELY(H5TS_mutex_destroy(&lock->mutex) < 0)) + ret_value = FAIL; + if (H5_UNLIKELY(H5TS_cond_destroy(&lock->readers_cv) < 0)) + ret_value = FAIL; + if (H5_UNLIKELY(H5TS_cond_destroy(&lock->writers_cv) < 0)) + ret_value = FAIL; + if (lock->is_key_registered) + if (H5_UNLIKELY(H5TS_key_delete(lock->rec_read_lock_count_key) < 0)) + ret_value = FAIL; + +done: + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_destroy() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_rdlock + * + * Purpose: Attempt to obtain a read lock on the associated recursive + * read / write lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_rdlock(H5TS_rec_rwlock_t *lock) +{ + H5TS_rec_entry_count_t *count; + H5TS_thread_t my_thread = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex) < 0)) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Fail if attempting to acquire a read lock on a thread that holds + * a write lock + */ + if (H5_UNLIKELY(H5TS_REC_RWLOCK_WRITE == lock->lock_type && + H5TS_thread_equal(my_thread, lock->write_thread))) + HGOTO_DONE(FAIL); + + /* If there is no thread-specific data for this thread, set it up */ + if (!lock->is_key_registered) { + if (H5_UNLIKELY(H5TS_key_create(&lock->rec_read_lock_count_key, free) < 0)) + HGOTO_DONE(FAIL); + lock->is_key_registered = true; + count = NULL; + } + else if (H5_UNLIKELY(H5TS_key_get_value(lock->rec_read_lock_count_key, (void **)&count) < 0)) + HGOTO_DONE(FAIL); + if (NULL == count) { + if (H5_UNLIKELY(NULL == (count = calloc(1, sizeof(*count))))) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(H5TS_key_set_value(lock->rec_read_lock_count_key, (void *)count) < 0)) + HGOTO_DONE(FAIL); + } + + if (*count > 0) { /* This is a recursive lock */ + assert(H5TS_REC_RWLOCK_READ == lock->lock_type); + assert(lock->reader_thread_count > 0 && lock->rec_write_lock_count == 0); + } + else { /* This is an initial read lock request, on this thread */ + /* Readers defer to current or pending writers */ + if (H5TS_REC_RWLOCK_WRITE == lock->lock_type) { +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS__update_stats_rd_lock_delay(lock); +#endif + + do { + if (H5_UNLIKELY(H5TS_cond_wait(&lock->readers_cv, &lock->mutex) < 0)) + HGOTO_DONE(FAIL); + } while (H5TS_REC_RWLOCK_WRITE == lock->lock_type); + } + + /* Set counter's lock type (which might already be set) & increment + * number of reader threads + */ + lock->lock_type = H5TS_REC_RWLOCK_READ; + lock->reader_thread_count++; + } + + /* Increment read lock count for this thread */ + (*count)++; +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS__update_stats_rdlock(lock, count); +#endif + +done: + if (H5_LIKELY(have_mutex)) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex) < 0)) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_rdlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_wrlock + * + * Purpose: Attempt to obtain a write lock on the associated recursive + * read / write lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_wrlock(H5TS_rec_rwlock_t *lock) +{ + H5TS_thread_t my_thread = H5TS_thread_self(); + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex) < 0)) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Check for initial write lock request on this thread */ + if (H5TS_REC_RWLOCK_WRITE != lock->lock_type || !H5TS_thread_equal(my_thread, lock->write_thread)) { + /* Fail if attempting to acquire a write lock on a thread that holds + * a read lock + */ + if (H5TS_REC_RWLOCK_READ == lock->lock_type) { + H5TS_rec_entry_count_t *count; + + /* Sanity check */ + assert(lock->is_key_registered); + + /* Fail if read lock count for this thread is > 0 */ + if (H5_UNLIKELY(H5TS_key_get_value(lock->rec_read_lock_count_key, (void **)&count) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(NULL != count && *count > 0)) + HGOTO_DONE(FAIL); + } + + /* If lock is already held, wait to acquire it */ + if (H5TS_REC_RWLOCK_UNUSED != lock->lock_type) { +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS__update_stats_wr_lock_delay(lock); +#endif + + do { + int result; + + lock->waiting_writers_count++; + result = H5TS_cond_wait(&lock->writers_cv, &lock->mutex); + lock->waiting_writers_count--; + if (H5_UNLIKELY(result != 0)) + HGOTO_DONE(FAIL); + } while (H5TS_REC_RWLOCK_UNUSED != lock->lock_type); + } + + /* Set lock type & owner thread */ + lock->lock_type = H5TS_REC_RWLOCK_WRITE; + lock->write_thread = my_thread; + } + + /* Increment write lock count for this thread */ + lock->rec_write_lock_count++; +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS__update_stats_wr_lock(lock); +#endif + +done: + if (H5_LIKELY(have_mutex)) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex) < 0)) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_wrlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_rdunlock + * + * Purpose: Attempt to unlock a read lock. + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_rdunlock(H5TS_rec_rwlock_t *lock) +{ + H5TS_rec_entry_count_t *count; + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex) < 0)) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Error check */ + if (H5_UNLIKELY(H5TS_REC_RWLOCK_READ != lock->lock_type)) + HGOTO_DONE(FAIL); + + /* Sanity and error checks */ + assert(lock->is_key_registered); + assert(lock->reader_thread_count > 0); + assert(0 == lock->rec_write_lock_count); + if (H5_UNLIKELY(H5TS_key_get_value(lock->rec_read_lock_count_key, (void **)&count) < 0)) + HGOTO_DONE(FAIL); + if (H5_UNLIKELY(NULL == count)) + HGOTO_DONE(FAIL); + assert(*count > 0); + + /* Decrement recursive lock count for this thread */ + (*count)--; +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS__update_stats_rd_unlock(lock, count); +#endif + + /* Check if this thread is releasing its last read lock */ + if (0 == *count) { + /* Decrement the # of threads with a read lock */ + lock->reader_thread_count--; + + /* Check if lock is unused now */ + if (0 == lock->reader_thread_count) { + lock->lock_type = H5TS_REC_RWLOCK_UNUSED; + + /* Indicate that lock is unused now */ + /* Prioritize pending writers if there are any */ + if (lock->waiting_writers_count > 0) { + if (H5_UNLIKELY(H5TS_cond_signal(&lock->writers_cv) < 0)) + HGOTO_DONE(FAIL); + } + else { + if (H5_UNLIKELY(H5TS_cond_broadcast(&lock->readers_cv) < 0)) + HGOTO_DONE(FAIL); + } + } + } + +done: + if (H5_LIKELY(have_mutex)) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex) < 0)) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_rdunlock() */ + +/*-------------------------------------------------------------------------- + * Function: H5TS__rec_rwlock_wrunlock + * + * Purpose: Attempt to unlock a write lock + * + * Return: Non-negative on success / Negative on failure + * + *-------------------------------------------------------------------------- + */ +herr_t +H5TS__rec_rwlock_wrunlock(H5TS_rec_rwlock_t *lock) +{ + bool have_mutex = false; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI_NAMECHECK_ONLY + + if (H5_UNLIKELY(NULL == lock)) + HGOTO_DONE(FAIL); + + /* Acquire the mutex */ + if (H5_UNLIKELY(H5TS_mutex_lock(&lock->mutex) < 0)) + HGOTO_DONE(FAIL); + have_mutex = true; + + /* Error check */ + if (H5_UNLIKELY(H5TS_REC_RWLOCK_WRITE != lock->lock_type)) + HGOTO_DONE(FAIL); + + /* Sanity checks */ + assert(0 == lock->reader_thread_count); + assert(lock->rec_write_lock_count > 0); + + /* Decrement recursive lock count */ + lock->rec_write_lock_count--; +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS__update_stats_wr_unlock(lock); +#endif + + /* Check if lock is unused now */ + if (0 == lock->rec_write_lock_count) { + lock->lock_type = H5TS_REC_RWLOCK_UNUSED; + + /* Indicate that lock is unused now */ + /* Prioritize pending writers if there are any */ + if (lock->waiting_writers_count > 0) { + if (H5_UNLIKELY(H5TS_cond_signal(&lock->writers_cv) < 0)) + HGOTO_DONE(FAIL); + } + else { + if (H5_UNLIKELY(H5TS_cond_broadcast(&lock->readers_cv) < 0)) + HGOTO_DONE(FAIL); + } + } + +done: + if (H5_LIKELY(have_mutex)) + if (H5_UNLIKELY(H5TS_mutex_unlock(&lock->mutex) < 0)) + ret_value = FAIL; + + FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) +} /* end H5TS__rec_rwlock_wrunlock() */ + +#endif /* H5_HAVE_THREADS */ diff --git a/src/H5TSrwlock.c b/src/H5TSrwlock.c index 43bac524c17..d8f772318a5 100644 --- a/src/H5TSrwlock.c +++ b/src/H5TSrwlock.c @@ -11,10 +11,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Purpose: This file contains support for recursive R/W locks, equivalent to - * the pthread 'pthread_rwlock_t' type and capabilities, except that - * threads that hold write access for the lock are allowed to acquire - * write access again (and must match each lock with an unlock operation). + * Purpose: This file contains support for non-recursive R/W locks, equivalent + * to the pthread 'pthread_rwlock_t' type and capabilities. * * Note: Because this threadsafety framework operates outside the library, * it does not use the error stack (although it does use error macros @@ -45,28 +43,6 @@ /* Local Typedefs */ /******************/ -/****************************************************************************** - * - * Structure H5TS_rec_entry_count_t; - * - * Structure associated with the rec_read_lock_count_key defined in - * H5TS_rw_lock_t. - * - * This structure maintains a count of recursive read locks so that the lock can - * be decremented when the thread-specific count drops to zero. - * - * Individual fields are: - * - * rec_lock_count: Count of the number of active [recursive] read lock calls - * for a given thread. The # of readers for the lock in question - * is decremented when the recursive read lock count drops to zero. - * - ******************************************************************************/ - -typedef struct H5TS_rec_entry_count { - int64_t rec_lock_count; -} H5TS_rec_entry_count_t; - /********************/ /* Local Prototypes */ /********************/ @@ -83,635 +59,183 @@ typedef struct H5TS_rec_entry_count { /* Local Variables */ /*******************/ -#if H5TS_ENABLE_REC_RW_LOCK_STATS -/*-------------------------------------------------------------------------- - * Function: H5TS__update_stats_rd_lock - * - * Purpose: Update stats for acquiring a read lock - * - * Return: none - * - *-------------------------------------------------------------------------- - */ -static void -H5TS__update_stats_rd_lock(H5TS_rw_lock_t *rw_lock, const H5TS_rec_entry_count_t *count) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - assert(rw_lock); - assert(H5TS_RW_LOCK_READ == rw_lock->lock_type); - assert(count); - assert(count->rec_lock_count >= 1); - - rw_lock->stats.read_locks_granted++; - - if (count->rec_lock_count == 1) { - rw_lock->stats.real_read_locks_granted++; - if (rw_lock->reader_thread_count > rw_lock->stats.max_read_locks) - rw_lock->stats.max_read_locks = rw_lock->reader_thread_count; - } - - if (count->rec_lock_count > rw_lock->stats.max_read_lock_recursion_depth) - rw_lock->stats.max_read_lock_recursion_depth = count->rec_lock_count; - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__update_stats_rd_lock() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__update_stats_rd_lock_delay - * - * Purpose: Update stats for delay in acquiring a read lock - * - * Return: none - * - *-------------------------------------------------------------------------- - */ -static void -H5TS__update_stats_rd_lock_delay(H5TS_rw_lock_t *rw_lock) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - assert(rw_lock); - - rw_lock->stats.read_locks_delayed++; - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__update_stats_rd_lock_delay() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__update_stats_rd_unlock +#ifdef H5_HAVE_C11_THREADS +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_init * - * Purpose: Update stats for releasing a read lock + * Purpose: Initialize a H5TS_rwlock_t (does not allocate it) * - * Return: none + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- - */ -static void -H5TS__update_stats_rd_unlock(H5TS_rw_lock_t *rw_lock, const H5TS_rec_entry_count_t *count) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - assert(rw_lock); - assert(H5TS_RW_LOCK_READ == rw_lock->lock_type); - assert(count); - assert(count->rec_lock_count >= 0); - - rw_lock->stats.read_locks_released++; - - if (count->rec_lock_count == 0) - rw_lock->stats.real_read_locks_released++; - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__update_stats_rd_unlock() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__update_stats_wr_lock - * - * Purpose: Update stats for acquiring a write lock - * - * Return: none - * - *-------------------------------------------------------------------------- - */ -static void -H5TS__update_stats_wr_lock(H5TS_rw_lock_t *rw_lock) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - assert(rw_lock); - assert(H5TS_RW_LOCK_WRITE == rw_lock->lock_type); - assert(rw_lock->rec_write_lock_count >= 1); - - rw_lock->stats.write_locks_granted++; - - if (rw_lock->rec_write_lock_count == 1) { - rw_lock->stats.real_write_locks_granted++; - if (rw_lock->rec_write_lock_count > rw_lock->stats.max_write_locks) - rw_lock->stats.max_write_locks = rw_lock->rec_write_lock_count; - } - - if (rw_lock->rec_write_lock_count > rw_lock->stats.max_write_lock_recursion_depth) - rw_lock->stats.max_write_lock_recursion_depth = rw_lock->rec_write_lock_count; - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__update_stats_wr_lock() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__update_stats_wr_lock_delay - * - * Purpose: Update stats for delay in acquiring a write lock - * - * Return: none - * - *-------------------------------------------------------------------------- - */ -static void -H5TS__update_stats_wr_lock_delay(H5TS_rw_lock_t *rw_lock) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - assert(rw_lock); - - rw_lock->stats.write_locks_delayed++; - - if (rw_lock->stats.max_write_locks_pending <= rw_lock->waiting_writers_count) - rw_lock->stats.max_write_locks_pending = rw_lock->waiting_writers_count + 1; - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__update_stats_wr_lock_delay() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__update_stats_wr_unlock - * - * Purpose: Update stats for releasing a write lock - * - * Return: none - * - *-------------------------------------------------------------------------- - */ -static void -H5TS__update_stats_wr_unlock(H5TS_rw_lock_t *rw_lock) -{ - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - assert(rw_lock); - assert(H5TS_RW_LOCK_WRITE == rw_lock->lock_type); - assert(rw_lock->rec_write_lock_count >= 0); - - rw_lock->stats.write_locks_released++; - - if (rw_lock->rec_write_lock_count == 0) - rw_lock->stats.real_write_locks_released++; - - FUNC_LEAVE_NOAPI_VOID_NAMECHECK_ONLY -} /* end H5TS__update_stats_wr_unlock() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_lock_get_stats - * - * Purpose: Obtain a copy of the current statistics for a recursive - * read / write lock. - * - * Note: To obtain a consistent set of statistics, the function must - * obtain the lock mutex. - * - * Return: Non-negative on success / Negative on failure - * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__rw_lock_get_stats(H5TS_rw_lock_t *rw_lock, H5TS_rw_lock_stats_t *stats) +H5TS_rwlock_init(H5TS_rwlock_t *lock) { - bool have_mutex = false; - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - if (H5_UNLIKELY(NULL == rw_lock || NULL == stats)) + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) HGOTO_DONE(FAIL); - /* Acquire the mutex */ - if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex))) + /* Initialize synchronization primitives */ + if (H5_UNLIKELY(mtx_init(&lock->mutex, mtx_plain) != thrd_success)) HGOTO_DONE(FAIL); - have_mutex = true; - - /* Copy R/W lock stats */ - *stats = rw_lock->stats; - -done: - if (H5_LIKELY(have_mutex)) - if (H5_UNLIKELY(H5TS_mutex_unlock(&rw_lock->mutex) < 0)) - ret_value = FAIL; - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_lock_get_stats() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_lock_reset_stats - * - * Purpose: Reset the statistics for the supplied recursive read / write - * lock. - * - * Note: To obtain a consistent set of statistics, the function must - * obtain the lock mutex. - * - * Return: Non-negative on success / Negative on failure - * - *-------------------------------------------------------------------------- - */ -herr_t -H5TS__rw_lock_reset_stats(H5TS_rw_lock_t *rw_lock) -{ - bool have_mutex = false; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - if (H5_UNLIKELY(NULL == rw_lock)) + if (H5_UNLIKELY(cnd_init(&lock->read_cv) != thrd_success)) HGOTO_DONE(FAIL); - - /* Acquire the mutex */ - if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex) < 0)) + if (H5_UNLIKELY(cnd_init(&lock->write_cv) != thrd_success)) HGOTO_DONE(FAIL); - have_mutex = true; - /* Reset stats */ - memset(&rw_lock->stats, 0, sizeof(rw_lock->stats)); + /* Initialize scalar fields */ + lock->readers = 0; + lock->writers = 0; + lock->read_waiters = 0; + lock->write_waiters = 0; done: - if (H5_LIKELY(have_mutex)) - if (H5_UNLIKELY(H5TS_mutex_unlock(&rw_lock->mutex) < 0)) - ret_value = FAIL; - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_lock_reset_stats() */ +} /* end H5TS_rwlock_init() */ -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_lock_print_stats +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_destroy * - * Purpose: Print the supplied pthresds recursive R/W lock statistics. + * Purpose: Destroy a H5TS_rwlock_t (does not free it) * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__rw_lock_print_stats(const char *header_str, H5TS_rw_lock_stats_t *stats) +H5TS_rwlock_destroy(H5TS_rwlock_t *lock) { herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - if (H5_UNLIKELY(NULL == header_str || NULL == stats)) + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) HGOTO_DONE(FAIL); - fprintf(stdout, "\n\n%s\n\n", header_str); - fprintf(stdout, " read_locks_granted = %" PRId64 "\n", stats->read_locks_granted); - fprintf(stdout, " read_locks_released = %" PRId64 "\n", stats->read_locks_released); - fprintf(stdout, " real_read_locks_granted = %" PRId64 "\n", stats->real_read_locks_granted); - fprintf(stdout, " real_read_locks_released = %" PRId64 "\n", stats->real_read_locks_released); - fprintf(stdout, " max_read_locks = %" PRId64 "\n", stats->max_read_locks); - fprintf(stdout, " max_read_lock_recursion_depth = %" PRId64 "\n", stats->max_read_lock_recursion_depth); - fprintf(stdout, " read_locks_delayed = %" PRId64 "\n", stats->read_locks_delayed); - fprintf(stdout, " write_locks_granted = %" PRId64 "\n", stats->write_locks_granted); - fprintf(stdout, " write_locks_released = %" PRId64 "\n", stats->write_locks_released); - fprintf(stdout, " real_write_locks_granted = %" PRId64 "\n", stats->real_write_locks_granted); - fprintf(stdout, " real_write_locks_released = %" PRId64 "\n", stats->real_write_locks_released); - fprintf(stdout, " max_write_locks = %" PRId64 "\n", stats->max_write_locks); - fprintf(stdout, " max_write_lock_recursion_depth = %" PRId64 "\n", - stats->max_write_lock_recursion_depth); - fprintf(stdout, " write_locks_delayed = %" PRId64 "\n", stats->write_locks_delayed); - fprintf(stdout, " max_write_locks_pending = %" PRId64 "\n\n", stats->max_write_locks_pending); + /* Destroy synchronization primitives */ + /* NOTE: mtx_destroy() & cnd_destroy() can't fail */ + mtx_destroy(&lock->mutex); + cnd_destroy(&lock->read_cv); + cnd_destroy(&lock->write_cv); done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_lock_print_stats() */ -#endif /* H5TS_ENABLE_REC_RW_LOCK_STATS */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_lock_init +} /* end H5TS_rwlock_destroy() */ +#else +#ifdef H5_HAVE_WIN_THREADS +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_init * - * Purpose: Initialize the supplied instance of H5TS_rw_lock_t. + * Purpose: Initialize a H5TS_rwlock_t (does not allocate it) * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__rw_lock_init(H5TS_rw_lock_t *rw_lock) +H5TS_rwlock_init(H5TS_rwlock_t *lock) { herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - if (H5_UNLIKELY(NULL == rw_lock)) + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) HGOTO_DONE(FAIL); -#ifdef H5_HAVE_WIN_THREADS - /* The current H5TS_rw_lock_t implementation uses H5TS_key_create() with a - * key destructor callback, which is not [currently] supported by Windows. - */ - HGOTO_DONE(FAIL); -#else - /* Initialize the lock */ - memset(rw_lock, 0, sizeof(*rw_lock)); - HDcompile_assert(H5TS_RW_LOCK_UNUSED == 0); - if (H5_UNLIKELY(H5TS_mutex_init(&rw_lock->mutex, H5TS_MUTEX_TYPE_PLAIN) < 0)) - HGOTO_DONE(FAIL); - if (H5_UNLIKELY(H5TS_cond_init(&rw_lock->writers_cv) < 0)) - HGOTO_DONE(FAIL); - if (H5_UNLIKELY(H5TS_cond_init(&rw_lock->readers_cv) < 0)) - HGOTO_DONE(FAIL); -#endif + InitializeSRWLock(lock); done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_lock_init() */ +} /* end H5TS_rwlock_init() */ -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_lock_destroy +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_destroy * - * Purpose: Take down an instance of H5TS_rw_lock_t. All mutex, condition - * variables, and keys are destroyed. However, the instance of - * H5TS_rw_lock_t is not freed. + * Purpose: Destroy a H5TS_rwlock_t (does not free it) * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__rw_lock_destroy(H5TS_rw_lock_t *rw_lock) +H5TS_rwlock_destroy(H5TS_rwlock_t *lock) { herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - if (H5_UNLIKELY(NULL == rw_lock)) + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) HGOTO_DONE(FAIL); - /* Call the appropriate destroy routines. We are committed - * to the destroy at this point, so call them all, even if one fails - * along the way. - */ - if (H5_UNLIKELY(H5TS_mutex_destroy(&rw_lock->mutex) < 0)) - ret_value = FAIL; - if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->readers_cv) < 0)) - ret_value = FAIL; - if (H5_UNLIKELY(H5TS_cond_destroy(&rw_lock->writers_cv) < 0)) - ret_value = FAIL; - if (rw_lock->is_key_registered) - if (H5_UNLIKELY(H5TS_key_delete(rw_lock->rec_read_lock_count_key) < 0)) - ret_value = FAIL; + /* Destroy synchronization primitives */ + /* SRWLOCKs don't have to be destroyed */ done: FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_lock_destroy() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_rdlock +} /* end H5TS_rwlock_destroy() */ +#else +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_init * - * Purpose: Attempt to obtain a read lock on the associated recursive - * read / write lock. + * Purpose: Initialize a H5TS_rwlock_t (does not allocate it) * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__rw_rdlock(H5TS_rw_lock_t *rw_lock) +H5TS_rwlock_init(H5TS_rwlock_t *lock) { - H5TS_rec_entry_count_t *count; - H5TS_thread_t my_thread = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_PACKAGE_NAMECHECK_ONLY - - if (H5_UNLIKELY(NULL == rw_lock)) - HGOTO_DONE(FAIL); + herr_t ret_value = SUCCEED; - /* Acquire the mutex */ - if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex) < 0)) - HGOTO_DONE(FAIL); - have_mutex = true; + FUNC_ENTER_NOAPI_NAMECHECK_ONLY - /* Fail if attempting to acquire a read lock on a thread that holds - * a write lock - */ - if (H5_UNLIKELY(H5TS_RW_LOCK_WRITE == rw_lock->lock_type && - H5TS_thread_equal(my_thread, rw_lock->write_thread))) + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) HGOTO_DONE(FAIL); - /* If there is no thread-specific data for this thread, set it up */ - if (!rw_lock->is_key_registered) { - if (H5_UNLIKELY(H5TS_key_create(&rw_lock->rec_read_lock_count_key, free) < 0)) - HGOTO_DONE(FAIL); - rw_lock->is_key_registered = true; - count = NULL; - } - else if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) + if (H5_UNLIKELY(pthread_rwlock_init(lock, NULL))) HGOTO_DONE(FAIL); - if (NULL == count) { - if (H5_UNLIKELY(NULL == (count = calloc(1, sizeof(*count))))) - HGOTO_DONE(FAIL); - if (H5_UNLIKELY(H5TS_key_set_value(rw_lock->rec_read_lock_count_key, (void *)count) < 0)) - HGOTO_DONE(FAIL); - } - - if (count->rec_lock_count > 0) { /* This is a recursive lock */ - assert(H5TS_RW_LOCK_READ == rw_lock->lock_type); - assert(rw_lock->reader_thread_count > 0 && rw_lock->rec_write_lock_count == 0); - } - else { /* This is an initial read lock request, on this thread */ - /* Readers defer to current or pending writers */ - if (H5TS_RW_LOCK_WRITE == rw_lock->lock_type) { -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS__update_stats_rd_lock_delay(rw_lock); -#endif - - do { - if (H5_UNLIKELY(H5TS_cond_wait(&rw_lock->readers_cv, &rw_lock->mutex) < 0)) - HGOTO_DONE(FAIL); - } while (H5TS_RW_LOCK_WRITE == rw_lock->lock_type); - } - - /* Set counter's lock type (which might already be set) & increment - * number of reader threads - */ - rw_lock->lock_type = H5TS_RW_LOCK_READ; - rw_lock->reader_thread_count++; - } - - /* Increment read lock count for this thread */ - count->rec_lock_count++; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS__update_stats_rd_lock(rw_lock, count); -#endif done: - if (H5_LIKELY(have_mutex)) - if (H5_UNLIKELY(H5TS_mutex_unlock(&rw_lock->mutex) < 0)) - ret_value = FAIL; - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_rdlock() */ +} /* end H5TS_rwlock_init() */ -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_wrlock +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_destroy * - * Purpose: Attempt to obtain a write lock on the associated recursive - * read / write lock. + * Purpose: Destroy a H5TS_rwlock_t (does not free it) * - * Return: Non-negative on success / Negative on failure + * Return: Non-negative on success / Negative on failure * - *-------------------------------------------------------------------------- + *------------------------------------------------------------------------- */ herr_t -H5TS__rw_wrlock(H5TS_rw_lock_t *rw_lock) +H5TS_rwlock_destroy(H5TS_rwlock_t *lock) { - H5TS_thread_t my_thread = H5TS_thread_self(); - bool have_mutex = false; - herr_t ret_value = SUCCEED; + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NAMECHECK_ONLY - if (H5_UNLIKELY(NULL == rw_lock)) + /* Check argument */ + if (H5_UNLIKELY(NULL == lock)) HGOTO_DONE(FAIL); - /* Acquire the mutex */ - if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex) < 0)) + if (H5_UNLIKELY(pthread_rwlock_destroy(lock))) HGOTO_DONE(FAIL); - have_mutex = true; - - /* Check for initial write lock request on this thread */ - if (H5TS_RW_LOCK_WRITE != rw_lock->lock_type || !H5TS_thread_equal(my_thread, rw_lock->write_thread)) { - /* Fail if attempting to acquire a write lock on a thread that holds - * a read lock - */ - if (H5TS_RW_LOCK_READ == rw_lock->lock_type) { - H5TS_rec_entry_count_t *count; - - /* Sanity check */ - assert(rw_lock->is_key_registered); - - /* Fail if read lock count for this thread is > 0 */ - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) - HGOTO_DONE(FAIL); - if (H5_UNLIKELY(NULL != count && count->rec_lock_count > 0)) - HGOTO_DONE(FAIL); - } - - /* If lock is already held, wait to acquire it */ - if (H5TS_RW_LOCK_UNUSED != rw_lock->lock_type) { -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS__update_stats_wr_lock_delay(rw_lock); -#endif - - do { - int result; - - rw_lock->waiting_writers_count++; - result = H5TS_cond_wait(&rw_lock->writers_cv, &rw_lock->mutex); - rw_lock->waiting_writers_count--; - if (H5_UNLIKELY(result != 0)) - HGOTO_DONE(FAIL); - } while (H5TS_RW_LOCK_UNUSED != rw_lock->lock_type); - } - - /* Set lock type & owner thread */ - rw_lock->lock_type = H5TS_RW_LOCK_WRITE; - rw_lock->write_thread = my_thread; - } - - /* Increment write lock count for this thread */ - rw_lock->rec_write_lock_count++; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS__update_stats_wr_lock(rw_lock); -#endif done: - if (H5_LIKELY(have_mutex)) - if (H5_UNLIKELY(H5TS_mutex_unlock(&rw_lock->mutex) < 0)) - ret_value = FAIL; - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_wrlock() */ - -/*-------------------------------------------------------------------------- - * Function: H5TS__rw_unlock - * - * Purpose: Attempt to unlock either a read or a write lock on a - * recursive read / write lock. - * - * Return: Non-negative on success / Negative on failure - * - *-------------------------------------------------------------------------- - */ -herr_t -H5TS__rw_unlock(H5TS_rw_lock_t *rw_lock) -{ - bool have_mutex = false; - herr_t ret_value = SUCCEED; - - FUNC_ENTER_NOAPI_NAMECHECK_ONLY - - if (H5_UNLIKELY(NULL == rw_lock)) - HGOTO_DONE(FAIL); - - /* Acquire the mutex */ - if (H5_UNLIKELY(H5TS_mutex_lock(&rw_lock->mutex) < 0)) - HGOTO_DONE(FAIL); - have_mutex = true; - - /* Error check */ - if (H5_UNLIKELY(H5TS_RW_LOCK_UNUSED == rw_lock->lock_type)) /* Unlocking an unused lock? */ - HGOTO_DONE(FAIL); - - if (H5TS_RW_LOCK_WRITE == rw_lock->lock_type) { /* Drop a write lock */ - /* Sanity checks */ - assert(0 == rw_lock->reader_thread_count); - assert(rw_lock->rec_write_lock_count > 0); - - /* Decrement recursive lock count */ - rw_lock->rec_write_lock_count--; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS__update_stats_wr_unlock(rw_lock); +} /* end H5TS_rwlock_destroy() */ #endif - - /* Check if lock is unused now */ - if (0 == rw_lock->rec_write_lock_count) - rw_lock->lock_type = H5TS_RW_LOCK_UNUSED; - } - else { /* Drop a read lock */ - H5TS_rec_entry_count_t *count; - - /* Sanity and error checks */ - assert(rw_lock->is_key_registered); - assert(rw_lock->reader_thread_count > 0); - assert(0 == rw_lock->rec_write_lock_count); - if (H5_UNLIKELY(H5TS_key_get_value(rw_lock->rec_read_lock_count_key, (void **)&count) < 0)) - HGOTO_DONE(FAIL); - if (H5_UNLIKELY(NULL == count)) - HGOTO_DONE(FAIL); - assert(count->rec_lock_count > 0); - - /* Decrement recursive lock count for this thread */ - count->rec_lock_count--; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS__update_stats_rd_unlock(rw_lock, count); #endif - /* Check if this thread is releasing its last read lock */ - if (0 == count->rec_lock_count) { - /* Decrement the # of threads with a read lock */ - rw_lock->reader_thread_count--; - - /* Check if lock is unused now */ - if (0 == rw_lock->reader_thread_count) - rw_lock->lock_type = H5TS_RW_LOCK_UNUSED; - } - } - - /* Signal condition variable if lock is unused now */ - if (H5TS_RW_LOCK_UNUSED == rw_lock->lock_type) { - /* Prioritize pending writers if there are any */ - if (rw_lock->waiting_writers_count > 0) { - if (H5_UNLIKELY(H5TS_cond_signal(&rw_lock->writers_cv) < 0)) - HGOTO_DONE(FAIL); - } - else { - if (H5_UNLIKELY(H5TS_cond_broadcast(&rw_lock->readers_cv) < 0)) - HGOTO_DONE(FAIL); - } - } - -done: - if (H5_LIKELY(have_mutex)) - if (H5_UNLIKELY(H5TS_mutex_unlock(&rw_lock->mutex) < 0)) - ret_value = FAIL; - - FUNC_LEAVE_NOAPI_NAMECHECK_ONLY(ret_value) -} /* end H5TS__rw_unlock() */ - #endif /* H5_HAVE_THREADS */ diff --git a/src/H5TSrwlock.h b/src/H5TSrwlock.h new file mode 100644 index 00000000000..16c36d46e5e --- /dev/null +++ b/src/H5TSrwlock.h @@ -0,0 +1,405 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Purpose: This file contains support for non-recursive R/W locks, equivalent + * to the pthread 'pthread_rwlock_t' type and capabilities. + * + * Note: Because this threadsafety framework operates outside the library, + * it does not use the error stack (although it does use error macros + * that don't push errors on a stack) and only uses the "namecheck only" + * FUNC_ENTER_* / FUNC_LEAVE_* macros. + */ + +/****************/ +/* Module Setup */ +/****************/ + +/***********/ +/* Headers */ +/***********/ + +/****************/ +/* Local Macros */ +/****************/ + +/******************/ +/* Local Typedefs */ +/******************/ + +/********************/ +/* Local Prototypes */ +/********************/ + +/*********************/ +/* Package Variables */ +/*********************/ + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + +/*******************/ +/* Local Variables */ +/*******************/ + +#ifdef H5_HAVE_C11_THREADS +/*------------------------------------------------------------------------- + * 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(mtx_lock(&lock->mutex) != thrd_success)) + return FAIL; + + /* Check for writers */ + if (lock->writers || lock->write_waiters) { + /* Read waiting */ + lock->read_waiters++; + + /* Wait for writers */ + do { + if (H5_UNLIKELY(thrd_success != cnd_wait(&lock->read_cv, &lock->mutex))) { + mtx_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(mtx_unlock(&lock->mutex) != thrd_success)) + 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(mtx_lock(&lock->mutex) != thrd_success)) + return FAIL; + + /* Decrement # of readers */ + lock->readers--; + + /* Check for waiting writers when last readers */ + if (lock->write_waiters && 0 == lock->readers) + if (H5_UNLIKELY(cnd_signal(&lock->write_cv) != thrd_success)) { + mtx_unlock(&lock->mutex); + return FAIL; + } + + /* Release mutex */ + if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success)) + 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(mtx_lock(&lock->mutex) != thrd_success)) + 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(thrd_success != cnd_wait(&lock->write_cv, &lock->mutex))) { + mtx_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(mtx_unlock(&lock->mutex) != thrd_success)) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_wrlock() */ + +/*------------------------------------------------------------------------- + * 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(mtx_lock(&lock->mutex) != thrd_success)) + return FAIL; + + /* Decrement # of writers */ + lock->writers--; + + /* Check for waiting writers */ + if (lock->write_waiters) { + if (H5_UNLIKELY(cnd_signal(&lock->write_cv) != thrd_success)) { + mtx_unlock(&lock->mutex); + return FAIL; + } + } + else if (lock->read_waiters) + if (H5_UNLIKELY(cnd_broadcast(&lock->read_cv) != thrd_success)) { + mtx_unlock(&lock->mutex); + return FAIL; + } + + /* Release mutex */ + if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success)) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_wrunlock() */ + +#else +#ifdef H5_HAVE_WIN_THREADS +/*------------------------------------------------------------------------- + * 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; + + AcquireSRWLockShared(lock); + + 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; + + ReleaseSRWLockShared(lock); + + 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; + + AcquireSRWLockExclusive(lock); + + return SUCCEED; +} /* end H5TS_rwlock_wrlock() */ + +/*------------------------------------------------------------------------- + * 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; + + ReleaseSRWLockExclusive(lock); + + return SUCCEED; +} /* end H5TS_rwlock_wrunlock() */ + +#else +/*------------------------------------------------------------------------- + * 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; + + if (H5_UNLIKELY(pthread_rwlock_rdlock(lock))) + 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; + + if (H5_UNLIKELY(pthread_rwlock_unlock(lock))) + 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; + + if (H5_UNLIKELY(pthread_rwlock_wrlock(lock))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_wrlock() */ + +/*------------------------------------------------------------------------- + * Function: H5TS_rwlock_rdunlock + * + * 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; + + if (H5_UNLIKELY(pthread_rwlock_unlock(lock))) + return FAIL; + + return SUCCEED; +} /* end H5TS_rwlock_wrunlock() */ +#endif +#endif diff --git a/src/Makefile.am b/src/Makefile.am index c887a9aa73a..87b12d08b06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -99,7 +99,7 @@ libhdf5_la_SOURCES= H5.c H5build_settings.c H5checksum.c H5dbg.c H5system.c \ H5Tvlen.c \ H5TS.c H5TSatomic.c H5TSbarrier.c H5TSc11.c H5TScond.c \ H5TSint.c H5TSkey.c H5TSmutex.c H5TSonce.c H5TSpool.c H5TSpthread.c \ - H5TSrwlock.c H5TSsemaphore.c H5TSthread.c H5TSwin.c \ + H5TSrec_rwlock.c H5TSrwlock.c H5TSsemaphore.c H5TSthread.c H5TSwin.c \ H5VL.c H5VLcallback.c H5VLdyn_ops.c H5VLint.c H5VLnative.c \ H5VLnative_attr.c H5VLnative_blob.c H5VLnative_dataset.c \ H5VLnative_datatype.c H5VLnative_file.c H5VLnative_group.c \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5a7e483210a..02a9891d512 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -350,7 +350,8 @@ set (ttsafe_SOURCES ${HDF5_TEST_SOURCE_DIR}/ttsafe_dcreate.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_develop.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_error.c - ${HDF5_TEST_SOURCE_DIR}/ttsafe_rec_rw_lock.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_rwlock.c + ${HDF5_TEST_SOURCE_DIR}/ttsafe_rec_rwlock.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_semaphore.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_thread_id.c ${HDF5_TEST_SOURCE_DIR}/ttsafe_thread_pool.c diff --git a/test/Makefile.am b/test/Makefile.am index 3625ac3dcce..061bfcf0df5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -162,7 +162,8 @@ LDADD=libh5test.la $(LIBHDF5) # List the source files for tests that have more than one ttsafe_SOURCES=ttsafe.c ttsafe_acreate.c ttsafe_atomic.c ttsafe_attr_vlen.c \ ttsafe_cancel.c ttsafe_dcreate.c ttsafe_develop.c ttsafe_error.c \ - ttsafe_rec_rw_lock.c ttsafe_semaphore.c ttsafe_thread_id.c ttsafe_thread_pool.c + ttsafe_rwlock.c ttsafe_rec_rwlock.c ttsafe_semaphore.c \ + ttsafe_thread_id.c ttsafe_thread_pool.c cache_image_SOURCES=cache_image.c genall5.c mirror_vfd_SOURCES=mirror_vfd.c genall5.c diff --git a/test/ttsafe.c b/test/ttsafe.c index 76dfa22bcbd..2f5f26db331 100644 --- a/test/ttsafe.c +++ b/test/ttsafe.c @@ -127,15 +127,16 @@ main(int argc, char *argv[]) /* C11 atomics only tested when emulated */ AddTest("atomics", tts_atomics, NULL, "emulation of C11 atomics", NULL); #endif /* H5_HAVE_STDATOMIC_H */ + AddTest("rwlock", tts_rwlock, NULL, "simple R/W locks", NULL); #ifndef H5_HAVE_WIN_THREADS /* Recursive R/W locks */ - AddTest("rec_rwlock_1", tts_rec_rw_lock_smoke_check_1, NULL, "recursive R/W lock smoke check 1 -- basic", + AddTest("rec_rwlock_1", tts_rec_rwlock_smoke_check_1, NULL, "recursive R/W lock smoke check 1 -- basic", NULL); - AddTest("rec_rwlock_2", tts_rec_rw_lock_smoke_check_2, NULL, + AddTest("rec_rwlock_2", tts_rec_rwlock_smoke_check_2, NULL, "recursive R/W lock smoke check 2 -- mob of readers", NULL); - AddTest("rec_rwlock_3", tts_rec_rw_lock_smoke_check_3, NULL, + AddTest("rec_rwlock_3", tts_rec_rwlock_smoke_check_3, NULL, "recursive R/W lock smoke check 3 -- mob of writers", NULL); - AddTest("rec_rwlock_4", tts_rec_rw_lock_smoke_check_4, NULL, + AddTest("rec_rwlock_4", tts_rec_rwlock_smoke_check_4, NULL, "recursive R/W lock smoke check 4 -- mixed mob", NULL); #endif /* !H5_HAVE_WIN_THREADS */ AddTest("semaphore", tts_semaphore, NULL, "lightweight system semaphores", NULL); diff --git a/test/ttsafe.h b/test/ttsafe.h index f551e40462a..7544b3ff32d 100644 --- a/test/ttsafe.h +++ b/test/ttsafe.h @@ -38,11 +38,14 @@ void tts_is_threadsafe(void); #ifdef H5_HAVE_THREADS void tts_thread_pool(void); void tts_atomics(void); +void tts_rwlock(void); void tts_semaphore(void); -void tts_rec_rw_lock_smoke_check_1(void); -void tts_rec_rw_lock_smoke_check_2(void); -void tts_rec_rw_lock_smoke_check_3(void); -void tts_rec_rw_lock_smoke_check_4(void); +#ifndef H5_HAVE_WIN_THREADS +void tts_rec_rwlock_smoke_check_1(void); +void tts_rec_rwlock_smoke_check_2(void); +void tts_rec_rwlock_smoke_check_3(void); +void tts_rec_rwlock_smoke_check_4(void); +#endif /* !H5_HAVE_WIN_THREADS */ #ifdef H5_HAVE_THREADSAFE void tts_dcreate(void); void tts_error(void); diff --git a/test/ttsafe_rec_rw_lock.c b/test/ttsafe_rec_rwlock.c similarity index 77% rename from test/ttsafe_rec_rw_lock.c rename to test/ttsafe_rec_rwlock.c index f7230af3d9d..3e17011e11c 100644 --- a/test/ttsafe_rec_rw_lock.c +++ b/test/ttsafe_rec_rwlock.c @@ -40,9 +40,9 @@ */ /*********************************************************************** * - * Structure rec_rw_lock_test_udata_t + * Structure rec_rwlock_test_udata_t * - * Arrays of instances of rec_rw_lock_test_udata_t are used to configure + * Arrays of instances of rec_rwlock_test_udata_t are used to configure * the threads used to test the recursive R/W lock, and to collect * statistics on their behaviour. These statistics are aggregated and * used to cross-check the statistics collected by the recursive R/W @@ -50,7 +50,7 @@ * * The fields of the structure are discussed below: * - * rw_lock: Pointer to the recursive R/W under test. + * lock: Pointer to the recursive R/W lock under test. * * target_rd_lock_cycles: The number of times the test thread is * required to obtain and drop the read lock. Note @@ -73,17 +73,17 @@ * * The remaining fields are used for statistics collection. They are * thread specific versions of the fields of the same name in - * H5TS_rw_lock_stats_t. See the header comment for that + * H5TS_rec_rwlock_stats_t. See the header comment for that * structure (in H5TSprivate.h) for further details. * ***********************************************************************/ -typedef struct rec_rw_lock_test_udata_t { +typedef struct rec_rwlock_test_udata_t { /* thread control fields */ - H5TS_rw_lock_t *rw_lock; - int32_t target_rd_lock_cycles; - int32_t target_wr_lock_cycles; - int32_t max_recursive_lock_depth; + H5TS_rec_rwlock_t *lock; + int32_t target_rd_lock_cycles; + int32_t target_wr_lock_cycles; + int32_t max_recursive_lock_depth; /* thread stats fields */ int64_t read_locks_granted; @@ -95,11 +95,11 @@ typedef struct rec_rw_lock_test_udata_t { int64_t real_write_locks_granted; int64_t real_write_locks_released; -} rec_rw_lock_test_udata_t; +} rec_rwlock_test_udata_t; /* ********************************************************************** - * tts_rw_lock_smoke_check_test_thread + * tts_rec_rwlock_smoke_check_test_thread * * Perform a sequence of recursive read and/or write locks on the * target recursive R/W lock as directed by the supplied user data. @@ -113,22 +113,22 @@ typedef struct rec_rw_lock_test_udata_t { ********************************************************************** */ static H5TS_THREAD_RETURN_TYPE -tts_rw_lock_smoke_check_test_thread(void *_udata) +tts_rec_rwlock_smoke_check_test_thread(void *_udata) { - hbool_t read; - int32_t rec_lock_depth = 0; - int32_t max_rec_lock_depth; - int32_t rd_locks_remaining; - int32_t wr_locks_remaining; - herr_t result; - H5TS_rw_lock_t *rw_lock; - rec_rw_lock_test_udata_t *udata = (rec_rw_lock_test_udata_t *)_udata; + hbool_t read; + int32_t rec_lock_depth = 0; + int32_t max_rec_lock_depth; + int32_t rd_locks_remaining; + int32_t wr_locks_remaining; + herr_t result; + H5TS_rec_rwlock_t *lock; + rec_rwlock_test_udata_t *udata = (rec_rwlock_test_udata_t *)_udata; assert(_udata); rd_locks_remaining = udata->target_rd_lock_cycles; wr_locks_remaining = udata->target_wr_lock_cycles; max_rec_lock_depth = udata->max_recursive_lock_depth; - rw_lock = udata->rw_lock; + lock = udata->lock; while (rd_locks_remaining > 0 || wr_locks_remaining > 0) { if (wr_locks_remaining == 0) @@ -143,8 +143,8 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) } if (read) { - result = H5TS__rw_rdlock(rw_lock); - CHECK_I(result, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(lock); + CHECK_I(result, "H5TS__rec_rwlock_rdlock"); udata->read_locks_granted++; udata->real_read_locks_granted++; @@ -153,15 +153,15 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) while (rec_lock_depth > 0) { if (rec_lock_depth >= max_rec_lock_depth || (rand() % 2) == 0) { - result = H5TS__rw_unlock(rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_rdunlock(lock); + CHECK_I(result, "H5TS__rec_rwlock_rdunlock"); rec_lock_depth--; udata->read_locks_released++; } else { - result = H5TS__rw_rdlock(rw_lock); - CHECK_I(result, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(lock); + CHECK_I(result, "H5TS__rec_rwlock_rdlock"); rec_lock_depth++; udata->read_locks_granted++; @@ -171,8 +171,8 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) udata->real_read_locks_released++; } else { - result = H5TS__rw_wrlock(rw_lock); - CHECK_I(result, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(lock); + CHECK_I(result, "H5TS__rec_rwlock_wrlock"); udata->write_locks_granted++; udata->real_write_locks_granted++; @@ -181,15 +181,15 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) while (rec_lock_depth > 0) { if (rec_lock_depth >= max_rec_lock_depth || (rand() % 2) == 0) { - result = H5TS__rw_unlock(rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_wrunlock(lock); + CHECK_I(result, "H5TS__rec_rwlock_wrunlock"); rec_lock_depth--; udata->write_locks_released++; } else { - result = H5TS__rw_wrlock(rw_lock); - CHECK_I(result, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(lock); + CHECK_I(result, "H5TS__rec_rwlock_wrlock"); rec_lock_depth++; udata->write_locks_granted++; @@ -201,11 +201,11 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) } return (H5TS_thread_ret_t)0; -} /* end tts_rw_lock_smoke_check_test_thread() */ +} /* end tts_rec_rwlock_smoke_check_test_thread() */ /* ********************************************************************** - * tts_rec_rw_lock_smoke_check_1 + * tts_rec_rwlock_smoke_check_1 * * Single thread test to verify basic functionality and error * rejection of the recursive R/W lock. @@ -263,33 +263,33 @@ tts_rw_lock_smoke_check_test_thread(void *_udata) ********************************************************************** */ void -tts_rec_rw_lock_smoke_check_1(void) +tts_rec_rwlock_smoke_check_1(void) { herr_t result; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - H5TS_rw_lock_stats_t stats; +#if H5TS_ENABLE_REC_RWLOCK_STATS + H5TS_rec_rwlock_stats_t stats; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rec_rwlock_t lock; /* 1) Initialize an instance of the recursive R/W lock. */ - result = H5TS__rw_lock_init(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_init"); + result = H5TS__rec_rwlock_init(&lock); + CHECK_I(result, "H5TS__rec_rwlock_init"); /* 2) Obtain a read lock. */ - result = H5TS__rw_rdlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdlock"); /* 3) Drop the read lock. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_rdunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdunlock"); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* 4) Verify the expected stats, and then reset them. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); - result = H5TS__rw_lock_reset_stats(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_reset_stats"); + result = H5TS__rec_rwlock_reset_stats(&lock); + CHECK_I(result, "H5TS__rec_rwlock_reset_stats"); /* clang-format makes this conditional unreadable, so turn it off. */ /* clang-format off */ @@ -310,34 +310,34 @@ tts_rec_rw_lock_smoke_check_1(void) stats.max_write_locks_pending != 0 ) { TestErrPrintf("Unexpected recursive R/W lock stats -- 1"); - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); } /* clang-format on */ #endif /* 5) Obtain a read lock. */ - result = H5TS__rw_rdlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdlock"); /* 6) Obtain the read lock a second time. */ - result = H5TS__rw_rdlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdlock"); /* 7) Drop the read lock. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_rdunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdunlock"); /* 8) Drop the read lock a second time. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_rdunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdunlock"); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* 9) Verify the expected stats, and then reset them. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); - result = H5TS__rw_lock_reset_stats(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_reset_stats"); + result = H5TS__rec_rwlock_reset_stats(&lock); + CHECK_I(result, "H5TS__rec_rwlock_reset_stats"); /* clang-format makes this conditional unreadable, so turn it off. */ /* clang-format off */ @@ -358,26 +358,26 @@ tts_rec_rw_lock_smoke_check_1(void) stats.max_write_locks_pending != 0 ) { TestErrPrintf("Unexpected recursive R/W lock stats -- 2"); - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); } /* clang-format on */ #endif /* 10) Obtain a write lock. */ - result = H5TS__rw_wrlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrlock"); /* 11) Drop the write lock. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_wrunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrunlock"); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* 12) Verify the expected stats, and then reset them. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); - result = H5TS__rw_lock_reset_stats(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_reset_stats"); + result = H5TS__rec_rwlock_reset_stats(&lock); + CHECK_I(result, "H5TS__rec_rwlock_reset_stats"); /* clang-format makes this conditional unreadable, so turn it off. */ /* clang-format off */ @@ -398,34 +398,34 @@ tts_rec_rw_lock_smoke_check_1(void) stats.max_write_locks_pending != 0 ) { TestErrPrintf("Unexpected recursive R/W lock stats -- 3"); - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); } /* clang-format on */ #endif /* 13) Obtain a write lock. */ - result = H5TS__rw_wrlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrlock"); /* 14) Obtain the write lock a second time. */ - result = H5TS__rw_wrlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrlock"); /* 15) Drop the write lock. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_wrunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrunlock"); /* 16) Drop the write lock a second time. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_wrunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrunlock"); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* 17) Verify the expected stats, and then reset them. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); - result = H5TS__rw_lock_reset_stats(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_reset_stats"); + result = H5TS__rec_rwlock_reset_stats(&lock); + CHECK_I(result, "H5TS__rec_rwlock_reset_stats"); /* clang-format makes this conditional unreadable, so turn it off. */ /* clang-format off */ @@ -446,42 +446,42 @@ tts_rec_rw_lock_smoke_check_1(void) stats.max_write_locks_pending != 0 ) { TestErrPrintf("Unexpected recursive R/W lock stats -- 4"); - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); } /* clang-format on */ #endif /* 18) Obtain a write lock. */ - result = H5TS__rw_wrlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrlock"); /* 19) Attempt to obtain a read lock -- should fail. */ - result = H5TS__rw_rdlock(&rec_rw_lock); - VERIFY(result, FAIL, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(&lock); + VERIFY(result, FAIL, "H5TS__rec_rwlock_rdlock"); /* 20) Drop the write lock. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_wrunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_wrunlock"); /* 21) Obtain a read lock. */ - result = H5TS__rw_rdlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_rdlock"); + result = H5TS__rec_rwlock_rdlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdlock"); /* 22) Attempt to obtain a write lock -- should fail. */ - result = H5TS__rw_wrlock(&rec_rw_lock); - VERIFY(result, FAIL, "H5TS__rw_wrlock"); + result = H5TS__rec_rwlock_wrlock(&lock); + VERIFY(result, FAIL, "H5TS__rec_rwlock_wrlock"); /* 23) Drop the read lock. */ - result = H5TS__rw_unlock(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_unlock"); + result = H5TS__rec_rwlock_rdunlock(&lock); + CHECK_I(result, "H5TS__rec_rwlock_rdunlock"); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* 24) Verify the expected stats, and then reset them. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); - result = H5TS__rw_lock_reset_stats(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_reset_stats"); + result = H5TS__rec_rwlock_reset_stats(&lock); + CHECK_I(result, "H5TS__rec_rwlock_reset_stats"); /* clang-format makes this conditional unreadable, so turn it off. */ /* clang-format off */ @@ -502,19 +502,19 @@ tts_rec_rw_lock_smoke_check_1(void) stats.max_write_locks_pending != 0 ) { TestErrPrintf("Unexpected recursive R/W lock stats"); - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); } /* clang-format on */ #endif /* 25) Shut down the recursive R/W lock. */ - result = H5TS__rw_lock_destroy(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_destroy"); -} /* end tts_rec_rw_lock_smoke_check_1() */ + result = H5TS__rec_rwlock_destroy(&lock); + CHECK_I(result, "H5TS__rec_rwlock_destroy"); +} /* end tts_rec_rwlock_smoke_check_1() */ /* ********************************************************************** - * tts_rec_rw_lock_smoke_check_2 -- mob of readers + * tts_rec_rwlock_smoke_check_2 -- mob of readers * * Multi-threaded test to check management of multiple readers ONLY by * the recursive R/W lock. Test proceeds as follows: @@ -525,7 +525,7 @@ tts_rec_rw_lock_smoke_check_1(void) * * 3) Create the reader threads, each with its own user data. * Activities of the reader threads is discussed in the header - * comment to tts_rw_lock_smoke_check_test_thread(). + * comment to tts_rec_rwlock_smoke_check_test_thread(). * * 4) Wait for all threads to complete. * @@ -546,25 +546,25 @@ tts_rec_rw_lock_smoke_check_1(void) ********************************************************************** */ void -tts_rec_rw_lock_smoke_check_2(void) +tts_rec_rwlock_smoke_check_2(void) { - herr_t result; - int express_test; - int i; - int num_threads = MAX_NUM_THREADS; - int lock_cycles = MAX_LOCK_CYCLES; - H5TS_thread_t threads[MAX_NUM_THREADS]; - rec_rw_lock_test_udata_t *udata = NULL; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - hbool_t verbose = FALSE; - int32_t total_target_rd_lock_cycles = 0; - int32_t total_target_wr_lock_cycles = 0; - H5TS_rw_lock_stats_t stats; - H5TS_rw_lock_stats_t expected; + herr_t result; + int express_test; + int i; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rwlock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RWLOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rec_rwlock_stats_t stats; + H5TS_rec_rwlock_stats_t expected; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rec_rwlock_t lock; -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Reset expected stats fields to zero -- we will construct the expected * stats from the thread udata after completion. */ @@ -596,30 +596,30 @@ tts_rec_rw_lock_smoke_check_2(void) } /* 1) Initialize an instance of the recursive R/W lock. */ - result = H5TS__rw_lock_init(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_init"); + result = H5TS__rec_rwlock_init(&lock); + CHECK_I(result, "H5TS__rec_rwlock_init"); /* 2) Setup the user data to be passed to each reader test thread. */ for (i = 0; i < MAX_NUM_THREADS; i++) { memset(&udata[i], 0, sizeof(udata[i])); - udata[i].rw_lock = &rec_rw_lock; + udata[i].lock = &lock; udata[i].target_rd_lock_cycles = lock_cycles; udata[i].max_recursive_lock_depth = 10; } -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS uint64_t start_time = H5_now_usec(); #endif /* 3) Create the reader threads, each with its own user data. */ for (i = 0; i < num_threads; i++) - if (H5TS_thread_create(&threads[i], tts_rw_lock_smoke_check_test_thread, &udata[i]) < 0) + if (H5TS_thread_create(&threads[i], tts_rec_rwlock_smoke_check_test_thread, &udata[i]) < 0) TestErrPrintf("thread # %d did not start", i); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) if (H5TS_thread_join(threads[i], NULL) < 0) TestErrPrintf("thread %d failed to join", i); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS uint64_t end_time = H5_now_usec(); uint64_t elap_time = (unsigned long long)(end_time - start_time); if (verbose) @@ -643,7 +643,7 @@ tts_rec_rw_lock_smoke_check_2(void) assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; @@ -658,7 +658,7 @@ tts_rec_rw_lock_smoke_check_2(void) #endif } -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Verify that the threads executed the expected number of read and write * lock cycles. If they didn't, some thread probably encountered an error * and exited early. @@ -677,8 +677,8 @@ tts_rec_rw_lock_smoke_check_2(void) * with the data gathered above. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); /* turn off clang-format for readability */ /* clang-format off */ @@ -700,27 +700,27 @@ tts_rec_rw_lock_smoke_check_2(void) stats.write_locks_delayed != expected.write_locks_delayed || stats.max_write_locks_pending != expected.max_write_locks_pending) { TestErrPrintf("Unexpected recursive R/W lock stats"); - H5TS__rw_lock_print_stats("Actual stats", &stats); - H5TS__rw_lock_print_stats("Expected stats", &expected); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Expected stats", &expected); } /* clang-format on */ if (verbose) - H5TS__rw_lock_print_stats("mob of readers stats", &stats); + H5TS__rec_rwlock_print_stats("mob of readers stats", &stats); #endif /* 7) Shut down the recursive R/W lock. */ - result = H5TS__rw_lock_destroy(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_destroy"); + result = H5TS__rec_rwlock_destroy(&lock); + CHECK_I(result, "H5TS__rec_rwlock_destroy"); /* discard the udata if it exists */ if (udata) free(udata); -} /* end tts_rec_rw_lock_smoke_check_2() */ +} /* end tts_rec_rwlock_smoke_check_2() */ /* ********************************************************************** - * tts_rec_rw_lock_smoke_check_3 -- mob of writers + * tts_rec_rwlock_smoke_check_3 -- mob of writers * * Multi-thread test to check management of multiple writers ONLY by * the recursive R/W lock. Test proceeds as follows: @@ -731,7 +731,7 @@ tts_rec_rw_lock_smoke_check_2(void) * * 3) Create the writer threads, each with its own user data. * Activities of the writer threads is discussed in the header - * comment to tts_rw_lock_smoke_check_test_thread(). + * comment to tts_rec_rwlock_smoke_check_test_thread(). * * 4) Wait for all threads to complete. * @@ -752,25 +752,25 @@ tts_rec_rw_lock_smoke_check_2(void) ********************************************************************** */ void -tts_rec_rw_lock_smoke_check_3(void) +tts_rec_rwlock_smoke_check_3(void) { - herr_t result; - int i; - int express_test; - int num_threads = MAX_NUM_THREADS; - int lock_cycles = MAX_LOCK_CYCLES; - H5TS_thread_t threads[MAX_NUM_THREADS]; - rec_rw_lock_test_udata_t *udata = NULL; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - hbool_t verbose = FALSE; - int32_t total_target_rd_lock_cycles = 0; - int32_t total_target_wr_lock_cycles = 0; - H5TS_rw_lock_stats_t stats; - H5TS_rw_lock_stats_t expected; + herr_t result; + int i; + int express_test; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rwlock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RWLOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rec_rwlock_stats_t stats; + H5TS_rec_rwlock_stats_t expected; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rec_rwlock_t lock; -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Reset expected stats fields to zero -- we will construct the expected * stats from the thread udata after completion. */ @@ -802,30 +802,30 @@ tts_rec_rw_lock_smoke_check_3(void) } /* 1) Initialize an instance of the recursive R/W lock. */ - result = H5TS__rw_lock_init(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_init"); + result = H5TS__rec_rwlock_init(&lock); + CHECK_I(result, "H5TS__rec_rwlock_init"); /* 2) Setup the user data to be passed to each writer test thread. */ for (i = 0; i < MAX_NUM_THREADS; i++) { memset(&udata[i], 0, sizeof(udata[i])); - udata[i].rw_lock = &rec_rw_lock; + udata[i].lock = &lock; udata[i].target_wr_lock_cycles = lock_cycles; udata[i].max_recursive_lock_depth = 10; } -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS uint64_t start_time = H5_now_usec(); #endif /* 3) Create the writer threads, each with its own user data. */ for (i = 0; i < num_threads; i++) - if (H5TS_thread_create(&threads[i], tts_rw_lock_smoke_check_test_thread, &udata[i]) < 0) + if (H5TS_thread_create(&threads[i], tts_rec_rwlock_smoke_check_test_thread, &udata[i]) < 0) TestErrPrintf("thread # %d did not start", i); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) if (H5TS_thread_join(threads[i], NULL) < 0) TestErrPrintf("thread %d failed to join", i); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS uint64_t end_time = H5_now_usec(); uint64_t elap_time = (unsigned long long)(end_time - start_time); if (verbose) @@ -849,7 +849,7 @@ tts_rec_rw_lock_smoke_check_3(void) assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; @@ -864,7 +864,7 @@ tts_rec_rw_lock_smoke_check_3(void) #endif } -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Verify that the threads executed the expected number of read and write * lock cycles. If they didn't, some thread probably encountered an error * and exited early. @@ -883,8 +883,8 @@ tts_rec_rw_lock_smoke_check_3(void) /* 6) Obtain the stats from the recursive R/W lock, and compare * with the data gathered above. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); /* turn off clang-format for readability */ /* clang-format off */ @@ -905,27 +905,27 @@ tts_rec_rw_lock_smoke_check_3(void) stats.write_locks_delayed < expected.write_locks_delayed || stats.max_write_locks_pending > expected.max_write_locks_pending) { TestErrPrintf("Unexpected recursive R/W lock stats"); - H5TS__rw_lock_print_stats("Actual stats", &stats); - H5TS__rw_lock_print_stats("Expected stats", &expected); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Expected stats", &expected); } /* clang-format on */ if (verbose) - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); #endif /* 7) Shut down the recursive R/W lock. */ - result = H5TS__rw_lock_destroy(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_destroy"); + result = H5TS__rec_rwlock_destroy(&lock); + CHECK_I(result, "H5TS__rec_rwlock_destroy"); /* discard the udata if it exists */ if (udata) free(udata); -} /* end tts_rec_rw_lock_smoke_check_3() */ +} /* end tts_rec_rwlock_smoke_check_3() */ /* ********************************************************************** - * tts_rec_rw_lock_smoke_check_4 -- mixed mob + * tts_rec_rwlock_smoke_check_4 -- mixed mob * * Multi-thread test to check management of multiple readers and * writers by the recursive R/W lock. Test proceeds as follows: @@ -936,7 +936,7 @@ tts_rec_rw_lock_smoke_check_3(void) * * 3) Create the reader / writer threads, each with its own user data. * Activities of the reader / writer threads is discussed in the - * header comment to tts_rw_lock_smoke_check_test_thread(). + * header comment to tts_rec_rwlock_smoke_check_test_thread(). * * 4) Wait for all threads to complete. * @@ -958,25 +958,25 @@ tts_rec_rw_lock_smoke_check_3(void) ********************************************************************** */ void -tts_rec_rw_lock_smoke_check_4(void) +tts_rec_rwlock_smoke_check_4(void) { - herr_t result; - int i; - int express_test; - int num_threads = MAX_NUM_THREADS; - int lock_cycles = MAX_LOCK_CYCLES; - H5TS_thread_t threads[MAX_NUM_THREADS]; - rec_rw_lock_test_udata_t *udata = NULL; -#if H5TS_ENABLE_REC_RW_LOCK_STATS - hbool_t verbose = FALSE; - int32_t total_target_rd_lock_cycles = 0; - int32_t total_target_wr_lock_cycles = 0; - H5TS_rw_lock_stats_t stats; - H5TS_rw_lock_stats_t expected; + herr_t result; + int i; + int express_test; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rwlock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RWLOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rec_rwlock_stats_t stats; + H5TS_rec_rwlock_stats_t expected; #endif - H5TS_rw_lock_t rec_rw_lock; + H5TS_rec_rwlock_t lock; -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Reset expected stats fields to zero -- we will construct the expected * stats from the thread udata after completion. */ @@ -1008,31 +1008,31 @@ tts_rec_rw_lock_smoke_check_4(void) } /* 1) Initialize an instance of the recursive R/W lock. */ - result = H5TS__rw_lock_init(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_init"); + result = H5TS__rec_rwlock_init(&lock); + CHECK_I(result, "H5TS__rec_rwlock_init"); /* 2) Setup the user data to be passed to each writer test thread. */ for (i = 0; i < MAX_NUM_THREADS; i++) { memset(&udata[i], 0, sizeof(udata[i])); - udata[i].rw_lock = &rec_rw_lock; + udata[i].lock = &lock; udata[i].target_rd_lock_cycles = lock_cycles; udata[i].target_wr_lock_cycles = lock_cycles; udata[i].max_recursive_lock_depth = 10; } -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS uint64_t start_time = H5_now_usec(); #endif /* 3) Create the reader threads, each with its own user data. */ for (i = 0; i < num_threads; i++) - if (H5TS_thread_create(&threads[i], tts_rw_lock_smoke_check_test_thread, &udata[i]) < 0) + if (H5TS_thread_create(&threads[i], tts_rec_rwlock_smoke_check_test_thread, &udata[i]) < 0) TestErrPrintf("thread # %d did not start", i); /* 4) Wait for all threads to complete. */ for (i = 0; i < num_threads; i++) if (H5TS_thread_join(threads[i], NULL) < 0) TestErrPrintf("thread %d failed to join", i); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS uint64_t end_time = H5_now_usec(); uint64_t elap_time = (unsigned long long)(end_time - start_time); if (verbose) @@ -1056,7 +1056,7 @@ tts_rec_rw_lock_smoke_check_4(void) assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; @@ -1071,7 +1071,7 @@ tts_rec_rw_lock_smoke_check_4(void) #endif } -#if H5TS_ENABLE_REC_RW_LOCK_STATS +#if H5TS_ENABLE_REC_RWLOCK_STATS /* Verify that the threads executed the expected number of read and write * lock cycles. If they didn't, some thread probably encountered an error * and exited early. @@ -1092,8 +1092,8 @@ tts_rec_rw_lock_smoke_check_4(void) /* 6) Obtain the stats from the recursive R/W lock, and compare * with the data gathered above. */ - result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); - CHECK_I(result, "H5TS__rw_lock_get_stats"); + result = H5TS__rec_rwlock_get_stats(&lock, &stats); + CHECK_I(result, "H5TS__rec_rwlock_get_stats"); /* turn off clang-format for readability */ /* clang-format off */ @@ -1115,23 +1115,23 @@ tts_rec_rw_lock_smoke_check_4(void) stats.write_locks_delayed < expected.write_locks_delayed || stats.max_write_locks_pending > expected.max_write_locks_pending) { TestErrPrintf("Unexpected recursive R/W lock stats"); - H5TS__rw_lock_print_stats("Actual stats", &stats); - H5TS__rw_lock_print_stats("Expected stats", &expected); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Expected stats", &expected); } /* clang-format on */ if (verbose) - H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rec_rwlock_print_stats("Actual stats", &stats); #endif /* 7) Shut down the recursive R/W lock. */ - result = H5TS__rw_lock_destroy(&rec_rw_lock); - CHECK_I(result, "H5TS__rw_lock_destroy"); + result = H5TS__rec_rwlock_destroy(&lock); + CHECK_I(result, "H5TS__rec_rwlock_destroy"); /* discard the udata if it exists */ if (udata) free(udata); -} /* end tts_rec_rw_lock_smoke_check_4() */ +} /* end tts_rec_rwlock_smoke_check_4() */ #endif /* H5_HAVE_WIN_THREADS */ #endif /* H5_HAVE_THREADS */ diff --git a/test/ttsafe_rwlock.c b/test/ttsafe_rwlock.c new file mode 100644 index 00000000000..c85434288ee --- /dev/null +++ b/test/ttsafe_rwlock.c @@ -0,0 +1,317 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/******************************************************************** + * + * Test the correctness of the non-recursive R/W lock routines + * + ********************************************************************/ + +#include "ttsafe.h" + +#ifdef H5_HAVE_THREADS + +#define NUM_THREADS 16 +#define NUM_WRITERS 4 + +#define NUM_ITERS 32 +#define COUNT_MAX 1024 + +typedef struct { + H5TS_rwlock_t lock; + int val; + H5TS_barrier_t barrier; +} atomic_counter_t; + +static H5TS_THREAD_RETURN_TYPE +incr_task(void *_counter) +{ + atomic_counter_t *counter = (atomic_counter_t *)_counter; + herr_t result; + H5TS_thread_ret_t ret_value = 0; + + result = H5TS_rwlock_wrlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_wrlock"); + + /* Increment value */ + counter->val++; + + result = H5TS_rwlock_wrunlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_wrunlock"); + + return ret_value; +} + +static H5TS_THREAD_RETURN_TYPE +many_read(void *_counter) +{ + atomic_counter_t *counter = (atomic_counter_t *)_counter; + herr_t result; + H5TS_thread_ret_t ret_value = 0; + + result = H5TS_rwlock_rdlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_rdlock"); + + /* Wait at barrier, to confirm that many readers can hold lock */ + result = H5TS_barrier_wait(&counter->barrier); + CHECK_I(result, "H5TS_barrier_wait"); + + result = H5TS_rwlock_rdunlock(&counter->lock); + CHECK_I(result, "H5TS_rdlock_rdunlock"); + + return ret_value; +} + +static H5TS_THREAD_RETURN_TYPE +count_up_and_down(void *_counter) +{ + atomic_counter_t *counter = (atomic_counter_t *)_counter; + herr_t result; + H5TS_thread_ret_t ret_value = 0; + + /* Count up & down a number of times */ + for (unsigned u = 0; u < NUM_ITERS; u++) { + /* Wait at barrier, to ensure all threads are ready to count */ + result = H5TS_barrier_wait(&counter->barrier); + CHECK_I(result, "H5TS_barrier_wait"); + + /* Count up */ + for (unsigned v = 0; v < COUNT_MAX; v++) { + result = H5TS_rwlock_wrlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_wrlock"); + + /* Increment value */ + counter->val++; + + result = H5TS_rwlock_wrunlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_wrunlock"); + } + + /* Wait at barrier, to ensure all threads have finishend counting up */ + result = H5TS_barrier_wait(&counter->barrier); + CHECK_I(result, "H5TS_barrier_wait"); + + /* Count down */ + for (unsigned v = 0; v < COUNT_MAX; v++) { + result = H5TS_rwlock_wrlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_wrlock"); + + /* Decrement value */ + counter->val--; + + result = H5TS_rwlock_wrunlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_wrunlock"); + } + } + + return ret_value; +} + +static H5TS_THREAD_RETURN_TYPE +verify_counting(void *_counter) +{ + atomic_counter_t *counter = (atomic_counter_t *)_counter; + herr_t result; + int last_val = 0; + H5TS_thread_ret_t ret_value = 0; + + /* Count up & down a number of times */ + for (unsigned u = 0; u < NUM_ITERS; u++) { + /* Wait at barrier, to ensure all threads are ready to count */ + result = H5TS_barrier_wait(&counter->barrier); + CHECK_I(result, "H5TS_barrier_wait"); + + /* Verify that counter goes only up */ + do { + result = H5TS_rwlock_rdlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_rdlock"); + + /* Check counter value */ + if (counter->val < last_val) + ERROR("incorrect counter value"); + + /* Save value */ + last_val = counter->val; + + result = H5TS_rwlock_rdunlock(&counter->lock); + CHECK_I(result, "H5TS_rdlock_wrunlock"); + + /* Give the writers a chance to make progress */ + H5TS_thread_yield(); + } while (last_val < (NUM_WRITERS * COUNT_MAX)); + + /* Wait at barrier, to ensure all threads have finishend counting up */ + result = H5TS_barrier_wait(&counter->barrier); + CHECK_I(result, "H5TS_barrier_wait"); + + /* Verify that counter goes only down */ + do { + result = H5TS_rwlock_rdlock(&counter->lock); + CHECK_I(result, "H5TS_rwlock_rdlock"); + + /* Check counter value */ + if (counter->val > last_val) + ERROR("incorrect counter value"); + + /* Save value */ + last_val = counter->val; + + result = H5TS_rwlock_rdunlock(&counter->lock); + CHECK_I(result, "H5TS_rdlock_wrunlock"); + + /* Give the writers a chance to make progress */ + H5TS_thread_yield(); + } while (last_val > 0); + } + + return ret_value; +} + +/* + ********************************************************************** + * tts_rwlock + ********************************************************************** + */ +void +tts_rwlock(void) +{ + H5TS_thread_t threads[NUM_THREADS]; + H5TS_pool_t *pool = NULL; + H5TS_rwlock_t lock; + atomic_counter_t counter; + herr_t result; + + /* Sanity checks on bad input */ + result = H5TS_rwlock_init(NULL); + VERIFY(result, FAIL, "H5TS_rwlock_init"); + result = H5TS_rwlock_rdlock(NULL); + VERIFY(result, FAIL, "H5TS_rwlock_rdlock"); + result = H5TS_rwlock_rdunlock(NULL); + VERIFY(result, FAIL, "H5TS_rwlock_rdunlock"); + result = H5TS_rwlock_wrlock(NULL); + VERIFY(result, FAIL, "H5TS_rwlock_wrlock"); + result = H5TS_rwlock_wrunlock(NULL); + VERIFY(result, FAIL, "H5TS_rwlock_wrunlock"); + result = H5TS_rwlock_destroy(NULL); + VERIFY(result, FAIL, "H5TS_rwlock_destroy"); + + /* Create & destroy lock */ + result = H5TS_rwlock_init(&lock); + CHECK_I(result, "H5TS_rwlock_init"); + + result = H5TS_rwlock_destroy(&lock); + CHECK_I(result, "H5TS_rwlock_destroy"); + + /* Read lock & unlock */ + result = H5TS_rwlock_init(&lock); + CHECK_I(result, "H5TS_rwlock_init"); + + result = H5TS_rwlock_rdlock(&lock); + CHECK_I(result, "H5TS_rwlock_rdlock"); + + result = H5TS_rwlock_rdunlock(&lock); + CHECK_I(result, "H5TS_rwlock_rdunlock"); + + result = H5TS_rwlock_destroy(&lock); + CHECK_I(result, "H5TS_rwlock_destroy"); + + /* Write lock & unlock */ + result = H5TS_rwlock_init(&lock); + CHECK_I(result, "H5TS_rwlock_init"); + + result = H5TS_rwlock_wrlock(&lock); + CHECK_I(result, "H5TS_rwlock_wrlock"); + + result = H5TS_rwlock_wrunlock(&lock); + CHECK_I(result, "H5TS_rwlock_wrunlock"); + + result = H5TS_rwlock_destroy(&lock); + CHECK_I(result, "H5TS_rwlock_destroy"); + + /* Hold read lock w/many threads */ + result = H5TS_rwlock_init(&counter.lock); + CHECK_I(result, "H5TS_rwlock_init"); + + result = H5TS_barrier_init(&counter.barrier, NUM_THREADS); + CHECK_I(result, "H5TS_barrier_init"); + + for (unsigned u = 0; u < NUM_THREADS; u++) { + result = H5TS_thread_create(&threads[u], many_read, &counter); + CHECK_I(result, "H5TS_thread_create"); + } + + for (unsigned u = 0; u < NUM_THREADS; u++) { + result = H5TS_thread_join(threads[u], NULL); + CHECK_I(result, "H5TS_thread_join"); + } + + result = H5TS_barrier_destroy(&counter.barrier); + CHECK_I(result, "H5TS_barrier_destroy"); + + result = H5TS_rwlock_destroy(&counter.lock); + CHECK_I(result, "H5TS_rwlock_destroy"); + + /* Increment counter w/many threads */ + result = H5TS_rwlock_init(&counter.lock); + CHECK_I(result, "H5TS_rwlock_init"); + + result = H5TS_pool_create(&pool, NUM_THREADS); + CHECK_I(result, "H5TS_pool_create"); + + counter.val = 0; + for (unsigned u = 0; u < NUM_THREADS; u++) { + result = H5TS_pool_add_task(pool, incr_task, &counter); + CHECK_I(result, "H5TS_pool_add_task"); + } + + result = H5TS_pool_destroy(pool); + CHECK_I(result, "H5TS_pool_destroy"); + + VERIFY(counter.val, NUM_THREADS, "many incr"); + + result = H5TS_rwlock_destroy(&counter.lock); + CHECK_I(result, "H5TS_rwlock_destroy"); + + /* Increment & decrement counter w/many threads while reading */ + result = H5TS_rwlock_init(&counter.lock); + CHECK_I(result, "H5TS_rwlock_init"); + + result = H5TS_barrier_init(&counter.barrier, NUM_THREADS); + CHECK_I(result, "H5TS_barrier_init"); + + result = H5TS_pool_create(&pool, NUM_THREADS); + CHECK_I(result, "H5TS_pool_create"); + + counter.val = 0; + for (unsigned u = 0; u < NUM_WRITERS; u++) { + result = H5TS_pool_add_task(pool, count_up_and_down, &counter); + CHECK_I(result, "H5TS_pool_add_task"); + } + for (unsigned u = 0; u < (NUM_THREADS - NUM_WRITERS); u++) { + result = H5TS_pool_add_task(pool, verify_counting, &counter); + CHECK_I(result, "H5TS_pool_add_task"); + } + + result = H5TS_pool_destroy(pool); + CHECK_I(result, "H5TS_pool_destroy"); + + VERIFY(counter.val, 0, "count up & down"); + + result = H5TS_barrier_destroy(&counter.barrier); + CHECK_I(result, "H5TS_barrier_destroy"); + + result = H5TS_rwlock_destroy(&counter.lock); + CHECK_I(result, "H5TS_rwlock_destroy"); + +} /* end tts_rwlock() */ + +#endif /*H5_HAVE_THREADS*/ diff --git a/test/ttsafe_semaphore.c b/test/ttsafe_semaphore.c index b8a3dece723..4d1a6a308cf 100644 --- a/test/ttsafe_semaphore.c +++ b/test/ttsafe_semaphore.c @@ -26,9 +26,9 @@ #define NUM_THREADS 16 typedef struct { - H5TS_semaphore_t ping_sem, pong_sem; - H5TS_atomic_uint_t ping_counter; - H5TS_atomic_uint_t pong_counter; + H5TS_semaphore_t ping_sem, pong_sem; + unsigned ping_counter; + unsigned pong_counter; } pingpong_t; typedef struct { @@ -48,11 +48,11 @@ ping(void *_test_info) result = H5TS_semaphore_wait(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_wait"); - H5TS_atomic_fetch_add_uint(&test_info->ping_counter, (unsigned)1); + test_info->ping_counter++; result = H5TS_semaphore_signal(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (H5TS_atomic_load_uint(&test_info->ping_counter) < NUM_PINGPONG); + } while (test_info->ping_counter < NUM_PINGPONG); return ret_value; } @@ -68,11 +68,11 @@ pong(void *_test_info) result = H5TS_semaphore_wait(&test_info->pong_sem); CHECK_I(result, "H5TS_semaphore_wait"); - H5TS_atomic_fetch_add_uint(&test_info->pong_counter, (unsigned)1); + test_info->pong_counter++; result = H5TS_semaphore_signal(&test_info->ping_sem); CHECK_I(result, "H5TS_semaphore_signal"); - } while (H5TS_atomic_load_uint(&test_info->pong_counter) < NUM_PINGPONG); + } while (test_info->pong_counter < NUM_PINGPONG); return ret_value; } @@ -94,8 +94,8 @@ tts_semaphore_pingpong(void) CHECK_I(result, "H5TS_semaphore_init"); result = H5TS_semaphore_init(&test_info.pong_sem, 0); CHECK_I(result, "H5TS_semaphore_init"); - H5TS_atomic_init_uint(&test_info.ping_counter, (unsigned)0); - H5TS_atomic_init_uint(&test_info.pong_counter, (unsigned)0); + test_info.ping_counter = 0; + test_info.pong_counter = 0; /* Start ping & pong threads */ result = H5TS_thread_create(&ping_thread, ping, &test_info); @@ -113,17 +113,14 @@ tts_semaphore_pingpong(void) result = H5TS_thread_join(pong_thread, NULL); CHECK_I(result, "H5TS_thread_join"); - VERIFY(H5TS_atomic_load_uint(&test_info.ping_counter), NUM_PINGPONG, "ping counter"); - VERIFY(H5TS_atomic_load_uint(&test_info.pong_counter), NUM_PINGPONG, "pong counter"); + VERIFY(test_info.ping_counter, NUM_PINGPONG, "ping counter"); + VERIFY(test_info.pong_counter, NUM_PINGPONG, "pong counter"); - /* Destroy semaphores, etc. */ + /* Destroy semaphores */ result = H5TS_semaphore_destroy(&test_info.ping_sem); CHECK_I(result, "H5TS_semaphore_destroy"); result = H5TS_semaphore_destroy(&test_info.pong_sem); CHECK_I(result, "H5TS_semaphore_destroy"); - - H5TS_atomic_destroy_uint(&test_info.ping_counter); - H5TS_atomic_destroy_uint(&test_info.pong_counter); } /* end tts_semaphore_pingpong() */ static H5TS_THREAD_RETURN_TYPE From 784fa01f702bc29c8668838e12bcc4138b688f2e Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Sat, 7 Sep 2024 13:49:18 -0700 Subject: [PATCH 72/94] Update NVHPC optimization settings (#4815) * Use -gopt in Autotools/CMake instead of -g * Autotools uses -O3 for release, -O1 for debug * Remove CMake optimization flag removal hack --- config/cmake/HDFCompilerFlags.cmake | 40 +---------------------------- config/nvidia-flags | 7 +++-- 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/config/cmake/HDFCompilerFlags.cmake b/config/cmake/HDFCompilerFlags.cmake index d8a444b84d2..e3364826ba6 100644 --- a/config/cmake/HDFCompilerFlags.cmake +++ b/config/cmake/HDFCompilerFlags.cmake @@ -54,46 +54,8 @@ if (CMAKE_C_COMPILER_ID STREQUAL "NVHPC" ) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s") endif () else () - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Mbounds -g") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Mbounds -gopt") endif () - - # With at least NVHPC 23.5 - 23.9, compiling with -O2 or higher and -DNDEBUG - # appears to have issues that manifest in the tests as incorrect metadata - # checksums being read or memory being corrupted. Compiling without -DNDEBUG - # does not appear to have these issues, but is not ideal due to compiling in - # asserts and other library debug code. Compiling with -O1 also does not appear - # to have these issues, so set maximum optimization level to -O1 for now until - # it can be determined whether these issues are compiler-specific or issues - # in the library. - set (cmake_c_flags_minsizerel_edited "${CMAKE_C_FLAGS_MINSIZEREL}") - string (REPLACE "-O2" "" cmake_c_flags_minsizerel_edited "${cmake_c_flags_minsizerel_edited}") - string (REPLACE "-O3" "" cmake_c_flags_minsizerel_edited "${cmake_c_flags_minsizerel_edited}") - string (REPLACE "-O4" "" cmake_c_flags_minsizerel_edited "${cmake_c_flags_minsizerel_edited}") - string (REPLACE "-Ofast" "" cmake_c_flags_minsizerel_edited "${cmake_c_flags_minsizerel_edited}") - string (REPLACE "-fast" "" cmake_c_flags_minsizerel_edited "${cmake_c_flags_minsizerel_edited}") - string (STRIP "${cmake_c_flags_minsizerel_edited}" cmake_c_flags_minsizerel_edited) - string (PREPEND cmake_c_flags_minsizerel_edited "-O1 ") - set (CMAKE_C_FLAGS_MINSIZEREL "${cmake_c_flags_minsizerel_edited}") - - set (cmake_c_flags_release_edited "${CMAKE_C_FLAGS_RELEASE}") - string (REPLACE "-O2" "" cmake_c_flags_release_edited "${cmake_c_flags_release_edited}") - string (REPLACE "-O3" "" cmake_c_flags_release_edited "${cmake_c_flags_release_edited}") - string (REPLACE "-O4" "" cmake_c_flags_release_edited "${cmake_c_flags_release_edited}") - string (REPLACE "-Ofast" "" cmake_c_flags_release_edited "${cmake_c_flags_release_edited}") - string (REPLACE "-fast" "" cmake_c_flags_release_edited "${cmake_c_flags_release_edited}") - string (STRIP "${cmake_c_flags_release_edited}" cmake_c_flags_release_edited) - string (PREPEND cmake_c_flags_release_edited "-O1 ") - set (CMAKE_C_FLAGS_RELEASE "${cmake_c_flags_release_edited}") - - set (cmake_c_flags_relwithdebinfo_edited "${CMAKE_C_FLAGS_RELWITHDEBINFO}") - string (REPLACE "-O2" "" cmake_c_flags_relwithdebinfo_edited "${cmake_c_flags_relwithdebinfo_edited}") - string (REPLACE "-O3" "" cmake_c_flags_relwithdebinfo_edited "${cmake_c_flags_relwithdebinfo_edited}") - string (REPLACE "-O4" "" cmake_c_flags_relwithdebinfo_edited "${cmake_c_flags_relwithdebinfo_edited}") - string (REPLACE "-Ofast" "" cmake_c_flags_relwithdebinfo_edited "${cmake_c_flags_relwithdebinfo_edited}") - string (REPLACE "-fast" "" cmake_c_flags_relwithdebinfo_edited "${cmake_c_flags_relwithdebinfo_edited}") - string (STRIP "${cmake_c_flags_relwithdebinfo_edited}" cmake_c_flags_relwithdebinfo_edited) - string (PREPEND cmake_c_flags_relwithdebinfo_edited "-O1 ") - set (CMAKE_C_FLAGS_RELWITHDEBINFO "${cmake_c_flags_relwithdebinfo_edited}") endif () if (CMAKE_C_COMPILER_ID STREQUAL "GNU") diff --git a/config/nvidia-flags b/config/nvidia-flags index c140edd9830..39bca831314 100644 --- a/config/nvidia-flags +++ b/config/nvidia-flags @@ -92,7 +92,7 @@ if test "X-nvc" = "X-$cc_vendor" -o "X-nvcc" = "X-$cc_vendor"; then ########### NO_SYMBOLS_CFLAGS="-s" - SYMBOLS_CFLAGS="-g" + SYMBOLS_CFLAGS="-gopt" ############# # Profiling # @@ -106,9 +106,8 @@ if test "X-nvc" = "X-$cc_vendor" -o "X-nvcc" = "X-$cc_vendor"; then # Optimization # ################ - HIGH_OPT_CFLAGS="-O1" # -O2+ currently has test failures. - #DEBUG_OPT_CFLAGS="-gopt -O2" - DEBUG_OPT_CFLAGS="-gopt -O1" # -O2+ currently has test failures. + HIGH_OPT_CFLAGS="-O3" + DEBUG_OPT_CFLAGS="-O1" # -O0 can be very slow NO_OPT_CFLAGS="-O0" ################# From 66cfc803ff0a22e614bdf1a71442739c83f2dda5 Mon Sep 17 00:00:00 2001 From: Dana Robinson <43805+derobins@users.noreply.github.com> Date: Sat, 7 Sep 2024 16:27:44 -0700 Subject: [PATCH 73/94] Add mirror VFD to serial -Werror CI action (#4753) * Add mirror VFD to serial -Werror CI action * NUL terminate mirror_vfd.c strings --- .github/workflows/main-auto-spc.yml | 4 ++-- test/mirror_vfd.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main-auto-spc.yml b/.github/workflows/main-auto-spc.yml index b7ac7c4f50b..f019bb12501 100644 --- a/.github/workflows/main-auto-spc.yml +++ b/.github/workflows/main-auto-spc.yml @@ -428,7 +428,7 @@ jobs: --enable-cxx \ --disable-fortran \ --enable-java \ - --disable-mirror-vfd \ + --enable-mirror-vfd \ --enable-direct-vfd \ --disable-ros3-vfd \ --with-szlib=yes @@ -491,7 +491,7 @@ jobs: --enable-cxx \ --disable-fortran \ --enable-java \ - --disable-mirror-vfd \ + --enable-mirror-vfd \ --enable-direct-vfd \ --disable-ros3-vfd \ --with-szlib=yes diff --git a/test/mirror_vfd.c b/test/mirror_vfd.c index 124fc6a6b0c..fe6695b9a06 100644 --- a/test/mirror_vfd.c +++ b/test/mirror_vfd.c @@ -1236,6 +1236,7 @@ create_mirroring_split_fapl(const char *basename, struct mirrortest_filenames *n mirror_conf.handshake_port = opts->portno; if (strncpy(mirror_conf.remote_ip, opts->ip, H5FD_MIRROR_MAX_IP_LEN) == NULL) TEST_ERROR; + mirror_conf.remote_ip[H5FD_MIRROR_MAX_IP_LEN] = '\0'; if ((splitter_config->wo_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) TEST_ERROR; if (H5Pset_fapl_mirror(splitter_config->wo_fapl_id, &mirror_conf) < 0) @@ -1248,8 +1249,10 @@ create_mirroring_split_fapl(const char *basename, struct mirrortest_filenames *n /* Set file paths for w/o and logfile */ if (strncpy(splitter_config->wo_path, (const char *)names->wo, H5FD_SPLITTER_PATH_MAX) == NULL) TEST_ERROR; + splitter_config->wo_path[H5FD_SPLITTER_PATH_MAX] = '\0'; if (strncpy(splitter_config->log_file_path, (const char *)names->log, H5FD_SPLITTER_PATH_MAX) == NULL) TEST_ERROR; + splitter_config->log_file_path[H5FD_SPLITTER_PATH_MAX] = '\0'; /* Create Splitter FAPL */ if ((ret_value = H5Pcreate(H5P_FILE_ACCESS)) < 0) From 5e94301e7150d0cce626760a2833899b953f0abf Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Sat, 7 Sep 2024 20:45:12 -0500 Subject: [PATCH 74/94] Add THREADS check to configuration file (#4746) * Cleanup threads package checks * Check first if package was found * Remove unnecessary dependent checks * Remove Unused options and fix names of option prefix --- HDF5Examples/C/CMakeLists.txt | 2 +- HDF5Examples/CMakeLists.txt | 99 +++++-------------- HDF5Examples/CMakePresets.json | 6 +- HDF5Examples/FORTRAN/H5D/CMakeLists.txt | 2 +- HDF5Examples/FORTRAN/H5G/CMakeLists.txt | 8 +- .../FORTRAN/H5G/Fortran_sourcefiles.cmake | 2 +- HDF5Examples/FORTRAN/H5PAR/CMakeLists.txt | 2 +- HDF5Examples/FORTRAN/H5T/CMakeLists.txt | 8 +- HDF5Examples/FORTRAN/TUTR/CMakeLists.txt | 6 +- HDF5Examples/Using_CMake.txt | 4 +- .../config/cmake/HDFExampleMacros.cmake | 48 ++++----- HDF5Examples/config/cmake/cacheinit.cmake | 12 +-- config/cmake/HDF5ExampleCache.cmake | 18 ++-- .../examples/HDF5_Examples_options.cmake | 35 +++---- config/cmake/hdf5-config.cmake.in | 2 +- release_docs/USING_CMake_Examples.txt | 15 ++- 16 files changed, 106 insertions(+), 163 deletions(-) diff --git a/HDF5Examples/C/CMakeLists.txt b/HDF5Examples/C/CMakeLists.txt index 97a9ea1f672..b394212150e 100644 --- a/HDF5Examples/C/CMakeLists.txt +++ b/HDF5Examples/C/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory (${PROJECT_SOURCE_DIR}/H5T) if (${H5_LIBVER_DIR} GREATER 16) # add_subdirectory (${PROJECT_SOURCE_DIR}/Perf) - if (USE_SHARED_LIBS AND HDF_BUILD_FILTERS AND HDF5_ENABLE_PLUGIN_SUPPORT) + if (USE_SHARED_LIBS AND H5EX_BUILD_FILTERS AND HDF5_ENABLE_PLUGIN_SUPPORT) add_subdirectory (${PROJECT_SOURCE_DIR}/H5FLT) endif () endif () diff --git a/HDF5Examples/CMakeLists.txt b/HDF5Examples/CMakeLists.txt index b155fb4025d..5ce806f6253 100644 --- a/HDF5Examples/CMakeLists.txt +++ b/HDF5Examples/CMakeLists.txt @@ -39,8 +39,8 @@ message (STATUS "HDF5 H5_LIBVER_DIR: ${H5_LIBVER_DIR} HDF5_VERSION_MAJOR: ${HDF5 #----------------------------------------------------------------------------- # Option to build JAVA examples #----------------------------------------------------------------------------- -option (HDF_BUILD_JAVA "Build JAVA support" OFF) -if (HDF_BUILD_JAVA) +option (H5EX_BUILD_JAVA "Build JAVA support" OFF) +if (H5EX_BUILD_JAVA) find_package (Java) include (${H5EX_RESOURCES_DIR}/UseJava.cmake) @@ -73,8 +73,8 @@ endif () # Option to Enable MPI Parallel #----------------------------------------------------------------------------- set (CMAKE_MODULE_PATH ${H5EX_RESOURCES_DIR} ${CMAKE_MODULE_PATH}) -option (HDF_ENABLE_PARALLEL "Enable parallel build (requires MPI)" OFF) -if (HDF_ENABLE_PARALLEL) +option (H5EX_ENABLE_PARALLEL "Enable parallel build (requires MPI)" OFF) +if (H5EX_ENABLE_PARALLEL) find_package(MPI REQUIRED) if (MPI_C_FOUND) set (H5_HAVE_PARALLEL 1) @@ -99,55 +99,6 @@ if (H5_HAVE_PARALLEL) INCLUDE_DIRECTORIES (${MPI_C_INCLUDE_DIRS}) endif () -# Determine if a threading package is available on this system -option (HDF5_ENABLE_THREADS "Enable thread support" ON) -set (THREADS_PREFER_PTHREAD_FLAG ON) -find_package (Threads) -if (Threads_FOUND) - set (H5_HAVE_THREADS 1) - set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) - - # Determine which threading package to use - # Comment out check for C11 threads for now, since it conflicts with the - # current --std=c99 compile flags at configuration time. When we switch to - # --std=c11, this can be uncommented. - #CHECK_INCLUDE_FILE("threads.h" HAVE_THREADS_H) - if (WIN32) - # When Win32 is available, we use those threads - set (H5_HAVE_WIN_THREADS 1) - elseif (HAVE_THREADS_H) - # When C11 threads are available, those are the top choice - set (H5_HAVE_C11_THREADS 1) - elseif (CMAKE_USE_PTHREADS_INIT) - set (H5_HAVE_PTHREAD_H 1) - else () - message (FATAL_ERROR " **** thread support requires C11 threads, Win32 threads or Pthreads **** ") - endif () - - # Check for compiler support for atomic variables - CHECK_INCLUDE_FILE("stdatomic.h" HAVE_STDATOMIC_H) - if (HAVE_STDATOMIC_H) - set (H5_HAVE_STDATOMIC_H 1) - endif() -endif () - -#----------------------------------------------------------------------------- -# Option to use threadsafe -#----------------------------------------------------------------------------- -option (HDF_ENABLE_THREADSAFE "Enable Threadsafety" OFF) -# Note that HDF_ENABLE_THREADSAFE is the CMake option for determining -# whether to enable thread-safety in the examples. HDF5_ENABLE_THREADSAFE -# is the CMake option determining whether HDF5 was configured with -# thread-safety enabled. -if (HDF_ENABLE_THREADSAFE AND HDF5_ENABLE_THREADSAFE) - # Check for threading package - if (NOT Threads_FOUND) - message (FATAL_ERROR " **** thread-safety option requires a threading package and none was found **** ") - endif () - - set (H5_HAVE_THREADSAFE 1) -endif () - set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES "${H5EX_HDF5_INCLUDE_DIRS}" ) @@ -176,8 +127,8 @@ if (${H5_LIBVER_DIR} GREATER 16) set (H5_FC_FUNC "H5_FC_FUNC(name,NAME) name ## _") set (H5_FC_FUNC_ "H5_FC_FUNC_(name,NAME) name ## _") if (EXISTS "${H5EXAMPLES_SOURCE_DIR}/FORTRAN" AND IS_DIRECTORY "${H5EXAMPLES_SOURCE_DIR}/FORTRAN") - option (HDF_BUILD_FORTRAN "Build examples FORTRAN support" OFF) - if (HDF_BUILD_FORTRAN AND HDF5_BUILD_FORTRAN) + option (H5EX_BUILD_FORTRAN "Build examples FORTRAN support" OFF) + if (H5EX_BUILD_FORTRAN AND HDF5_BUILD_FORTRAN) set (H5EX_LINK_Fortran_LIBS ${H5EX_HDF5_LINK_LIBS}) # Parallel IO usage requires MPI to be Linked and Included @@ -191,10 +142,10 @@ if (${H5_LIBVER_DIR} GREATER 16) configure_file (${H5EX_F90_SRC_DIR}/H5D/h5_version.h.in ${PROJECT_BINARY_DIR}/FORTRAN/H5D/h5_version.h @ONLY) configure_file (${H5EX_F90_SRC_DIR}/H5D/h5_version.h.in ${PROJECT_BINARY_DIR}/FORTRAN/H5G/h5_version.h @ONLY) else () - set (HDF_BUILD_FORTRAN OFF CACHE BOOL "Build examples FORTRAN support" FORCE) + set (H5EX_BUILD_FORTRAN OFF CACHE BOOL "Build examples FORTRAN support" FORCE) endif () else () - set (HDF_BUILD_FORTRAN OFF CACHE BOOL "Build examples FORTRAN support" FORCE) + set (H5EX_BUILD_FORTRAN OFF CACHE BOOL "Build examples FORTRAN support" FORCE) endif () if (${H5_LIBVER_DIR} GREATER 18) @@ -202,29 +153,29 @@ if (${H5_LIBVER_DIR} GREATER 16) # Option to build JAVA examples #----------------------------------------------------------------------------- if (EXISTS "${H5EXAMPLES_SOURCE_DIR}/JAVA" AND IS_DIRECTORY "${H5EXAMPLES_SOURCE_DIR}/JAVA") - option (HDF_BUILD_JAVA "Build examples JAVA support" OFF) + option (H5EX_BUILD_JAVA "Build examples JAVA support" OFF) else () - set (HDF_BUILD_JAVA OFF CACHE BOOL "Build examples JAVA support" FORCE) + set (H5EX_BUILD_JAVA OFF CACHE BOOL "Build examples JAVA support" FORCE) endif () else () - set (HDF_BUILD_JAVA OFF CACHE BOOL "Build examples JAVA support" FORCE) + set (H5EX_BUILD_JAVA OFF CACHE BOOL "Build examples JAVA support" FORCE) endif () #----------------------------------------------------------------------------- # Build the CPP Examples #----------------------------------------------------------------------------- if (EXISTS "${H5EXAMPLES_SOURCE_DIR}/CXX" AND IS_DIRECTORY "${H5EXAMPLES_SOURCE_DIR}/CXX") - option (HDF_BUILD_CPP_LIB "Build examples C++ support" OFF) + option (H5EX_BUILD_CPP_LIB "Build examples C++ support" OFF) else () - set (HDF_BUILD_CPP_LIB OFF CACHE BOOL "Build examples C++ support" FORCE) + set (H5EX_BUILD_CPP_LIB OFF CACHE BOOL "Build examples C++ support" FORCE) endif () #----------------------------------------------------------------------------- # Option to build filter examples #----------------------------------------------------------------------------- if (EXISTS "${H5EXAMPLES_SOURCE_DIR}/C/H5FLT" AND IS_DIRECTORY "${H5EXAMPLES_SOURCE_DIR}/C/H5FLT") - option (HDF_BUILD_FILTERS "Build examples PLUGIN filter support" OFF) - if (HDF_BUILD_FILTERS AND HDF5_ENABLE_PLUGIN_SUPPORT) + option (H5EX_BUILD_FILTERS "Build examples PLUGIN filter support" OFF) + if (H5EX_BUILD_FILTERS AND HDF5_ENABLE_PLUGIN_SUPPORT) if(DEFINED ENV{HDF5_PLUGIN_PATH}) message (STATUS "ENV PATH=$ENV{HDF5_PLUGIN_PATH}") set (H5EX_HDF5_PLUGIN_PATH $ENV{HDF5_PLUGIN_PATH}) @@ -236,32 +187,32 @@ if (${H5_LIBVER_DIR} GREATER 16) endif () message (STATUS "H5EX_HDF5_PLUGIN_PATH=${H5EX_HDF5_PLUGIN_PATH}") else () - set (HDF_BUILD_FILTERS OFF CACHE BOOL "Build examples PLUGIN filter support" FORCE) + set (H5EX_BUILD_FILTERS OFF CACHE BOOL "Build examples PLUGIN filter support" FORCE) endif () else () - set (HDF_BUILD_FILTERS OFF CACHE BOOL "Build examples PLUGIN filter support" FORCE) + set (H5EX_BUILD_FILTERS OFF CACHE BOOL "Build examples PLUGIN filter support" FORCE) endif () else () - set (HDF_BUILD_FORTRAN OFF} CACHE BOOL "Build examples FORTRAN support" FORCE) - set (HDF_BUILD_JAVA OFF CACHE BOOL "Build examples JAVA support" FORCE) - set (HDF_BUILD_CPP_LIB OFF CACHE BOOL "Build examples C++ support" FORCE) - set (HDF_BUILD_FILTERS OFF CACHE BOOL "Build examples PLUGIN filter support" FORCE) + set (H5EX_BUILD_FORTRAN OFF} CACHE BOOL "Build examples FORTRAN support" FORCE) + set (H5EX_BUILD_JAVA OFF CACHE BOOL "Build examples JAVA support" FORCE) + set (H5EX_BUILD_CPP_LIB OFF CACHE BOOL "Build examples C++ support" FORCE) + set (H5EX_BUILD_FILTERS OFF CACHE BOOL "Build examples PLUGIN filter support" FORCE) endif () #----------------------------------------------------------------------------- # Build examples #----------------------------------------------------------------------------- add_subdirectory (C) -if (HDF_BUILD_FORTRAN AND HDF5_BUILD_FORTRAN) +if (H5EX_BUILD_FORTRAN AND HDF5_BUILD_FORTRAN) add_subdirectory (FORTRAN) endif () -if (HDF_BUILD_JAVA AND HDF5_BUILD_JAVA) +if (H5EX_BUILD_JAVA AND HDF5_BUILD_JAVA) add_subdirectory (JAVA) endif () -if (HDF_BUILD_CPP_LIB AND HDF5_BUILD_CPP_LIB) +if (H5EX_BUILD_CPP_LIB AND HDF5_BUILD_CPP_LIB) add_subdirectory (CXX) endif () -if (HDF_BUILD_PYTHON) +if (H5EX_BUILD_PYTHON) add_subdirectory (PYTHON) endif () diff --git a/HDF5Examples/CMakePresets.json b/HDF5Examples/CMakePresets.json index 2dbf304111d..0f2c1b5e013 100644 --- a/HDF5Examples/CMakePresets.json +++ b/HDF5Examples/CMakePresets.json @@ -18,21 +18,21 @@ "name": "ci-StdJava", "hidden": true, "cacheVariables": { - "HDF_BUILD_JAVA": "ON" + "H5EX_BUILD_JAVA": "ON" } }, { "name": "ci-StdFortran", "hidden": true, "cacheVariables": { - "HDF_BUILD_FORTRAN": "ON" + "H5EX_BUILD_FORTRAN": "ON" } }, { "name": "ci-StdPlugins", "hidden": true, "cacheVariables": { - "HDF_BUILD_FILTERS": "ON" + "H5EX_BUILD_FILTERS": "ON" } }, { diff --git a/HDF5Examples/FORTRAN/H5D/CMakeLists.txt b/HDF5Examples/FORTRAN/H5D/CMakeLists.txt index b784df864a2..e7c59b420e2 100644 --- a/HDF5Examples/FORTRAN/H5D/CMakeLists.txt +++ b/HDF5Examples/FORTRAN/H5D/CMakeLists.txt @@ -10,7 +10,7 @@ project (HDF5Examples_FORTRAN_H5D Fortran) # Setup include Directories #----------------------------------------------------------------------------- set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES - "${CMAKE_Fortran_MODULE_DIRECTORY}${HDF_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + "${CMAKE_Fortran_MODULE_DIRECTORY}${H5EX_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" ) #----------------------------------------------------------------------------- diff --git a/HDF5Examples/FORTRAN/H5G/CMakeLists.txt b/HDF5Examples/FORTRAN/H5G/CMakeLists.txt index 4b85e4eba37..6a58c5258ab 100644 --- a/HDF5Examples/FORTRAN/H5G/CMakeLists.txt +++ b/HDF5Examples/FORTRAN/H5G/CMakeLists.txt @@ -10,7 +10,7 @@ project (HDF5Examples_FORTRAN_H5G Fortran) # Setup include Directories #----------------------------------------------------------------------------- set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES - "${CMAKE_Fortran_MODULE_DIRECTORY}${HDF_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + "${CMAKE_Fortran_MODULE_DIRECTORY}${H5EX_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" ) #----------------------------------------------------------------------------- @@ -47,7 +47,7 @@ foreach (example_name ${common_examples}) endif () endforeach () -#if (HDF_ENABLE_F2003) +#if (H5EX_ENABLE_F2003) # foreach (example_name ${f03examples}) # add_executable (${EXAMPLE_VARNAME}_f90_${example_name} ${PROJECT_SOURCE_DIR}/${example_name}.c) # target_compile_options(${EXAMPLE_VARNAME}_f90_${example_name} @@ -149,7 +149,7 @@ if (HDF5_BUILD_TOOLS) ) endif () -#if (HDF_ENABLE_F2003) +#if (H5EX_ENABLE_F2003) # foreach (example_name ${f03examples}) # add_custom_command ( # TARGET ${EXAMPLE_VARNAME}_f90_${example_name} @@ -432,7 +432,7 @@ if (H5EX_BUILD_TESTING) #ADD_H5_CMP_TEST (h5ex_g_traverse) #endif() else () - if (HDF_ENABLE_F2003) + if (H5EX_ENABLE_F2003) ADD_H5_CMP_TEST (h5ex_g_intermediate) ADD_H5_CMP_TEST (h5ex_g_iterate) # ADD_H5_CMP_TEST (h5ex_g_traverse) diff --git a/HDF5Examples/FORTRAN/H5G/Fortran_sourcefiles.cmake b/HDF5Examples/FORTRAN/H5G/Fortran_sourcefiles.cmake index e2e8e9d42b8..f5586e61f8c 100644 --- a/HDF5Examples/FORTRAN/H5G/Fortran_sourcefiles.cmake +++ b/HDF5Examples/FORTRAN/H5G/Fortran_sourcefiles.cmake @@ -23,7 +23,7 @@ if (HDF5_VERSION_STRING VERSION_GREATER_EQUAL "1.10.0") ) endif() else () - if (HDF_ENABLE_F2003) + if (H5EX_ENABLE_F2003) set (common_examples ${common_examples} h5ex_g_intermediate diff --git a/HDF5Examples/FORTRAN/H5PAR/CMakeLists.txt b/HDF5Examples/FORTRAN/H5PAR/CMakeLists.txt index c8301c78a5e..e1d147d434c 100644 --- a/HDF5Examples/FORTRAN/H5PAR/CMakeLists.txt +++ b/HDF5Examples/FORTRAN/H5PAR/CMakeLists.txt @@ -10,7 +10,7 @@ project (HDF5Examples_FORTRAN_H5PAR Fortran) # Setup include Directories #----------------------------------------------------------------------------- set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES - "${CMAKE_Fortran_MODULE_DIRECTORY}${HDF_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + "${CMAKE_Fortran_MODULE_DIRECTORY}${H5EX_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" ) #----------------------------------------------------------------------------- diff --git a/HDF5Examples/FORTRAN/H5T/CMakeLists.txt b/HDF5Examples/FORTRAN/H5T/CMakeLists.txt index 63d4dd78b7b..14fd8528664 100644 --- a/HDF5Examples/FORTRAN/H5T/CMakeLists.txt +++ b/HDF5Examples/FORTRAN/H5T/CMakeLists.txt @@ -5,7 +5,7 @@ project (HDF5Examples_FORTRAN_H5T Fortran) # Setup include Directories #----------------------------------------------------------------------------- set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES - "${CMAKE_Fortran_MODULE_DIRECTORY}${HDF_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + "${CMAKE_Fortran_MODULE_DIRECTORY}${H5EX_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" ) #----------------------------------------------------------------------------- @@ -13,7 +13,7 @@ set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES #----------------------------------------------------------------------------- include (Fortran_sourcefiles.cmake) -#if (HDF_ENABLE_F2003) +#if (H5EX_ENABLE_F2003) foreach (example_name ${f03_examples}) add_executable (${EXAMPLE_VARNAME}_f90_${example_name} ${PROJECT_SOURCE_DIR}/${example_name}.F90) target_compile_options(${EXAMPLE_VARNAME}_f90_${example_name} @@ -126,7 +126,7 @@ if (HDF5_BUILD_TOOLS) ) endforeach () - #if (HDF_ENABLE_F2003) + #if (H5EX_ENABLE_F2003) foreach (example_name ${f03_examples}) if (NOT ${example_name} STREQUAL "h5ex_t_convert_F03") if (${example_name} STREQUAL "h5ex_t_vlen_F03" OR ${example_name} STREQUAL "h5ex_t_vlenatt_F03") @@ -404,7 +404,7 @@ if (H5EX_BUILD_TESTING) endif () endmacro () - #if (HDF_ENABLE_F2003) + #if (H5EX_ENABLE_F2003) foreach (example_name ${f03_examples} ${common_examples}) TEST_EXAMPLE (${example_name}) endforeach () diff --git a/HDF5Examples/FORTRAN/TUTR/CMakeLists.txt b/HDF5Examples/FORTRAN/TUTR/CMakeLists.txt index 4b866d4ec17..7c5b2189838 100644 --- a/HDF5Examples/FORTRAN/TUTR/CMakeLists.txt +++ b/HDF5Examples/FORTRAN/TUTR/CMakeLists.txt @@ -5,7 +5,7 @@ project (HDF5Examples_FORTRAN_TUTR Fortran) # Setup include Directories #----------------------------------------------------------------------------- set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES - "${CMAKE_Fortran_MODULE_DIRECTORY}${HDF_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + "${CMAKE_Fortran_MODULE_DIRECTORY}${H5EX_MOD_EXT};${HDF5_F90_BINARY_DIR};${PROJECT_BINARY_DIR};${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" ) #----------------------------------------------------------------------------- @@ -13,7 +13,7 @@ set_directory_properties(PROPERTIES INCLUDE_DIRECTORIES #----------------------------------------------------------------------------- include (Fortran_sourcefiles.cmake) -#if (HDF_ENABLE_F2003) +#if (H5EX_ENABLE_F2003) foreach (example_name ${f03_examples}) add_executable (${EXAMPLE_VARNAME}_f90_tutr_${example_name} ${PROJECT_SOURCE_DIR}/${example_name}.f90) target_compile_options(${EXAMPLE_VARNAME}_f90_tutr_${example_name} @@ -112,7 +112,7 @@ if (H5EX_BUILD_TESTING) set (last_test "${EXAMPLE_VARNAME}_f90_tutr_${testname}") endmacro () - #if (HDF_ENABLE_F2003) + #if (H5EX_ENABLE_F2003) foreach (example_name ${f03_examples} ${common_examples}) ADD_H5_TEST (${example_name}) endforeach () diff --git a/HDF5Examples/Using_CMake.txt b/HDF5Examples/Using_CMake.txt index 778fa7534b5..baef3565194 100644 --- a/HDF5Examples/Using_CMake.txt +++ b/HDF5Examples/Using_CMake.txt @@ -99,8 +99,8 @@ These steps are described in more detail below. is: * H5EX_BUILD_TESTING:BOOL=ON * BUILD_SHARED_LIBS:BOOL=[ON | OFF] - * HDF_BUILD_FORTRAN:BOOL=[ON | OFF] - * HDF_BUILD_JAVA:BOOL=[ON | OFF] + * H5EX_BUILD_FORTRAN:BOOL=[ON | OFF] + * H5EX_BUILD_JAVA:BOOL=[ON | OFF] if the hdf5 library was built with a namespace (i.e. "hdf5::") add: -D HDF5_NAMESPACE:STRING=hdf5:: diff --git a/HDF5Examples/config/cmake/HDFExampleMacros.cmake b/HDF5Examples/config/cmake/HDFExampleMacros.cmake index 9888c06d36a..bbb042177a3 100644 --- a/HDF5Examples/config/cmake/HDFExampleMacros.cmake +++ b/HDF5Examples/config/cmake/HDFExampleMacros.cmake @@ -34,7 +34,7 @@ macro (BASIC_SETTINGS varname) set (CMAKE_C_STANDARD 99) set (CMAKE_C_STANDARD_REQUIRED TRUE) - if (HDF_BUILD_CPP_LIB) + if (H5EX_BUILD_CPP_LIB) ENABLE_LANGUAGE (CXX) set (CMAKE_CXX_STANDARD 98) @@ -66,12 +66,12 @@ macro (BASIC_SETTINGS varname) #----------------------------------------------------------------------------- # Option to allow the user to disable compiler warnings #----------------------------------------------------------------------------- - option (HDF_DISABLE_COMPILER_WARNINGS "Disable compiler warnings" OFF) - if (HDF_DISABLE_COMPILER_WARNINGS) + option (H5EX_DISABLE_COMPILER_WARNINGS "Disable compiler warnings" OFF) + if (H5EX_DISABLE_COMPILER_WARNINGS) # MSVC uses /w to suppress warnings. It also complains if another # warning level is given, so remove it. if (MSVC) - set (HDF_WARNINGS_BLOCKED 1) + set (H5EX_WARNINGS_BLOCKED 1) string (REGEX REPLACE "(^| )([/-])W[0-9]( |$)" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /w") if (CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") @@ -84,12 +84,12 @@ macro (BASIC_SETTINGS varname) endif () # Borland uses -w- to suppress warnings. if (BORLAND) - set (HDF_WARNINGS_BLOCKED 1) + set (H5EX_WARNINGS_BLOCKED 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-") endif () # Most compilers use -w to suppress warnings. - if (NOT HDF_WARNINGS_BLOCKED) + if (NOT H5EX_WARNINGS_BLOCKED) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") if (CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") @@ -106,8 +106,8 @@ macro (BASIC_SETTINGS varname) endmacro () macro (PYTHON_SUPPORT) - option (HDF_BUILD_PYTHON "Test Python3 support" OFF) - if (HDF_BUILD_PYTHON) + option (H5EX_BUILD_PYTHON "Test Python3 support" OFF) + if (H5EX_BUILD_PYTHON) find_package (Python3 COMPONENTS Interpreter Development NumPy) if (Python3_FOUND AND Python3_NumPy_FOUND) include (ExternalProject) @@ -122,7 +122,7 @@ macro (PYTHON_SUPPORT) INSTALL_COMMAND python3 -m pip --no-cache-dir install -v . ) else () - set (HDF_BUILD_PYTHON OFF CACHE BOOL "Test Python3 support" FORCE) + set (H5EX_BUILD_PYTHON OFF CACHE BOOL "Test Python3 support" FORCE) message (STATUS "Python3:${Python3_FOUND} or numpy:${Python3_NumPy_FOUND} not found - disable test of Python examples") endif () endif () @@ -137,16 +137,16 @@ macro (HDF5_SUPPORT) set (FIND_HDF_COMPONENTS C shared) else () set (FIND_HDF_COMPONENTS C static) - set (HDF_BUILD_JAVA OFF CACHE BOOL "Build Java support" FORCE) + set (HDEXF_BUILD_JAVA OFF CACHE BOOL "Build Java support" FORCE) message (STATUS "Using static HDF5 - disable build of Java examples") endif () - if (HDF_BUILD_FORTRAN) + if (H5EX_BUILD_FORTRAN) set (FIND_HDF_COMPONENTS ${FIND_HDF_COMPONENTS} Fortran) endif () - if (HDF_BUILD_CPP_LIB) + if (H5EX_BUILD_CPP_LIB) set (FIND_HDF_COMPONENTS ${FIND_HDF_COMPONENTS} CXX) endif () - if (HDF_BUILD_JAVA) + if (H5EX_BUILD_JAVA) set (FIND_HDF_COMPONENTS ${FIND_HDF_COMPONENTS} Java) set (HDF5_Java_FOUND 1) #default setting for 1.10.1 and earlier endif () @@ -161,13 +161,13 @@ macro (HDF5_SUPPORT) if (NOT HDF5_static_C_FOUND AND NOT HDF5_shared_C_FOUND) #find library from non-dual-binary package set (FIND_HDF_COMPONENTS C) - if (HDF_BUILD_FORTRAN) + if (H5EX_BUILD_FORTRAN) set (FIND_HDF_COMPONENTS ${FIND_HDF_COMPONENTS} Fortran) endif () - if (HDF_BUILD_JAVA) + if (H5EX_BUILD_JAVA) set (FIND_HDF_COMPONENTS ${FIND_HDF_COMPONENTS} Java) endif () - if (HDF_BUILD_CPP_LIB) + if (H5EX_BUILD_CPP_LIB) set (FIND_HDF_COMPONENTS ${FIND_HDF_COMPONENTS} CXX) endif () message (STATUS "HDF5 find comps: ${FIND_HDF_COMPONENTS}") @@ -185,7 +185,7 @@ macro (HDF5_SUPPORT) else () set_property (TARGET ${HDF5_NAMESPACE}h5dump PROPERTY IMPORTED_LOCATION "${HDF5_TOOLS_DIR}/h5dump") endif () - if (HDF_BUILD_JAVA) + if (H5EX_BUILD_JAVA) set (CMAKE_JAVA_INCLUDE_PATH "${CMAKE_JAVA_INCLUDE_PATH};${HDF5_JAVA_INCLUDE_DIRS}") message (STATUS "HDF5 jars:${HDF5_JAVA_INCLUDE_DIRS}") endif () @@ -218,21 +218,21 @@ macro (HDF5_SUPPORT) endif() if (NOT HDF5_static_Fortran_FOUND AND NOT HDF5_shared_Fortran_FOUND) - set (HDF_BUILD_FORTRAN OFF CACHE BOOL "Build FORTRAN support" FORCE) + set (H5EX_BUILD_FORTRAN OFF CACHE BOOL "Build FORTRAN support" FORCE) message (STATUS "HDF5 Fortran libs not found - disable build of Fortran examples") else () - if (HDF_BUILD_FORTRAN AND ${HDF5_BUILD_FORTRAN}) + if (H5EX_BUILD_FORTRAN AND ${HDF5_BUILD_FORTRAN}) if (BUILD_SHARED_LIBS AND HDF5_shared_Fortran_FOUND) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_FORTRAN_SHARED_LIBRARY}) elseif (HDF5_static_Fortran_FOUND) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_FORTRAN_STATIC_LIBRARY}) else () - set (HDF_BUILD_FORTRAN OFF CACHE BOOL "Build FORTRAN support" FORCE) + set (H5EX_BUILD_FORTRAN OFF CACHE BOOL "Build FORTRAN support" FORCE) message (STATUS "HDF5 Fortran libs not found - disable build of Fortran examples") endif () endif () endif () - if (HDF_BUILD_JAVA AND HDF5_Java_FOUND) + if (H5EX_BUILD_JAVA AND HDF5_Java_FOUND) if (${HDF5_BUILD_JAVA}) set (CMAKE_JAVA_INCLUDE_PATH "${CMAKE_JAVA_INCLUDE_PATH};${HDF5_JAVA_INCLUDE_DIRS}") get_target_property (libsoname ${HDF5_JAVA_LIBRARY} IMPORTED_SONAME${UPPER_BUILD_TYPE}) @@ -243,11 +243,11 @@ macro (HDF5_SUPPORT) set (H5EX_JAVA_LIBRARIES ${HDF5_JAVA_LIBRARY}) message (STATUS "HDF5 lib:${H5EX_JAVA_LIBRARY} jars:${HDF5_JAVA_INCLUDE_DIRS}}") else () - set (HDF_BUILD_JAVA OFF CACHE BOOL "Build Java support" FORCE) + set (H5EX_BUILD_JAVA OFF CACHE BOOL "Build Java support" FORCE) message (STATUS "HDF5 Java libs not found - disable build of Java examples") endif () else () - set (HDF_BUILD_JAVA OFF CACHE BOOL "Build Java support" FORCE) + set (H5EX_BUILD_JAVA OFF CACHE BOOL "Build Java support" FORCE) endif () endif () else () @@ -283,7 +283,7 @@ macro (HDF5_SUPPORT) set (H5EX_HDF5_HAVE_HDF5 1) message (STATUS "HDF5-${HDF5_VERSION_STRING} used") endif () - if (HDF_BUILD_FORTRAN) + if (H5EX_BUILD_FORTRAN) list (APPEND H5EX_HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR_FORTRAN}) endif () message (STATUS "HDF5 link libs: ${H5EX_HDF5_LINK_LIBS} Includes: ${H5EX_HDF5_INCLUDE_DIRS}") diff --git a/HDF5Examples/config/cmake/cacheinit.cmake b/HDF5Examples/config/cmake/cacheinit.cmake index 3e5a8eb8c5a..0ef3a0e1b9c 100644 --- a/HDF5Examples/config/cmake/cacheinit.cmake +++ b/HDF5Examples/config/cmake/cacheinit.cmake @@ -8,17 +8,15 @@ set (BUILD_SHARED_LIBS ON CACHE BOOL "Build Shared Libraries" FORCE) set (H5EX_BUILD_TESTING ON CACHE BOOL "Build HDF5 Unit Testing" FORCE) -#set (HDF_ENABLE_PARALLEL ON CACHE BOOL "Enable parallel build (requires MPI)" FORCE) +#set (H5EX_ENABLE_PARALLEL ON CACHE BOOL "Enable parallel build (requires MPI)" FORCE) -#set (HDF_BUILD_FORTRAN ON CACHE BOOL "Build FORTRAN support" FORCE) +#set (H5EX_BUILD_FORTRAN ON CACHE BOOL "Build FORTRAN support" FORCE) -#set (HDF_BUILD_FILTERS ON CACHE BOOL "Build filter support" FORCE) +#set (H5EX_BUILD_FILTERS ON CACHE BOOL "Build filter support" FORCE) -#set (HDF_ENABLE_F2003 ON CACHE BOOL "Enable FORTRAN 2003 Standard" FORCE) +#set (H5EX_ENABLE_F2003 ON CACHE BOOL "Enable FORTRAN 2003 Standard" FORCE) -#set (HDF_ENABLE_THREADSAFE ON CACHE BOOL "Enable Threadsafety" FORCE) - -#set (HDF_BUILD_JAVA ON CACHE BOOL "Build JAVA support" FORCE) +#set (H5EX_BUILD_JAVA ON CACHE BOOL "Build JAVA support" FORCE) set (HDF5_PACKAGE_NAME "hdf5" CACHE STRING "Name of HDF5 package" FORCE) diff --git a/config/cmake/HDF5ExampleCache.cmake b/config/cmake/HDF5ExampleCache.cmake index 7d5b7be0c40..99232cc06ca 100644 --- a/config/cmake/HDF5ExampleCache.cmake +++ b/config/cmake/HDF5ExampleCache.cmake @@ -7,13 +7,13 @@ # set example options to match build options set (H5EX_BUILD_TESTING ${BUILD_TESTING} CACHE BOOL "Enable examples testing" FORCE) set (H5EX_BUILD_EXAMPLES ${HDF5_BUILD_EXAMPLES} CACHE BOOL "Build Examples" FORCE) -set (HDF_BUILD_FORTRAN ${HDF5_BUILD_FORTRAN} CACHE BOOL "Build examples FORTRAN support" FORCE) -set (HDF_BUILD_JAVA ${HDF5_BUILD_JAVA} CACHE BOOL "Build examples JAVA support" FORCE) -set (HDF_BUILD_FILTERS ${HDF5_ENABLE_PLUGIN_SUPPORT} CACHE BOOL "Build examples PLUGIN filter support" FORCE) -set (HDF_BUILD_CPP_LIB ${HDF5_BUILD_CPP_LIB} CACHE BOOL "Build HDF5 C++ Library" FORCE) -set (HDF_BUILD_HL_LIB ${HDF5_BUILD_HL_LIB} CACHE BOOL "Build HIGH Level examples" FORCE) -set (HDF_ENABLE_THREADSAFE ${HDF5_ENABLE_THREADSAFE} CACHE BOOL "Enable examples thread-safety" FORCE) -set (HDF_ENABLE_PARALLEL ${HDF5_ENABLE_PARALLEL} CACHE BOOL "Enable examples parallel build (requires MPI)" FORCE) +set (H5EX_BUILD_FORTRAN ${HDF5_BUILD_FORTRAN} CACHE BOOL "Build examples FORTRAN support" FORCE) +set (H5EX_BUILD_JAVA ${HDF5_BUILD_JAVA} CACHE BOOL "Build examples JAVA support" FORCE) +set (H5EX_BUILD_FILTERS ${HDF5_ENABLE_PLUGIN_SUPPORT} CACHE BOOL "Build examples PLUGIN filter support" FORCE) +set (H5EX_BUILD_CPP_LIB ${HDF5_BUILD_CPP_LIB} CACHE BOOL "Build HDF5 C++ Library" FORCE) +set (H5EX_BUILD_HL_LIB ${HDF5_BUILD_HL_LIB} CACHE BOOL "Build HIGH Level examples" FORCE) +set (H5EX_ENABLE_THREADSAFE ${HDF5_ENABLE_THREADSAFE} CACHE BOOL "Enable examples thread-safety" FORCE) +set (H5EX_ENABLE_PARALLEL ${HDF5_ENABLE_PARALLEL} CACHE BOOL "Enable examples parallel build (requires MPI)" FORCE) set (H5EX_USE_GNU_DIRS ${HDF5_USE_GNU_DIRS} CACHE BOOL "ON to use GNU Coding Standard install directory variables, OFF to use historical settings" FORCE) #preset HDF5 cache vars to this projects libraries instead of searching @@ -46,7 +46,7 @@ if (NOT BUILD_SHARED_LIBS AND BUILD_STATIC_LIBS) set (H5EX_HDF5_LINK_LIBS ${HDF5_LIB_TARGET} CACHE STRING "HDF5 target" FORCE) if (HDF5_BUILD_FORTRAN) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_F90_LIB_TARGET}) - set (HDF_MOD_EXT "/static" CACHE STRING "Use Static Modules for Examples" FORCE) + set (H5EX_MOD_EXT "/static" CACHE STRING "Use Static Modules for Examples" FORCE) endif () if (HDF5_BUILD_CPP_LIB) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_CPP_LIB_TARGET}) @@ -56,7 +56,7 @@ else () set (H5EX_HDF5_LINK_LIBS ${HDF5_LIBSH_TARGET} CACHE STRING "HDF5 target" FORCE) if (HDF5_BUILD_FORTRAN) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_F90_LIBSH_TARGET}) - set (HDF_MOD_EXT "/shared" CACHE STRING "Use Shared Modules for Examples" FORCE) + set (H5EX_MOD_EXT "/shared" CACHE STRING "Use Shared Modules for Examples" FORCE) endif () if (HDF5_BUILD_CPP_LIB) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_CPP_LIBSH_TARGET}) diff --git a/config/cmake/examples/HDF5_Examples_options.cmake b/config/cmake/examples/HDF5_Examples_options.cmake index 684ec5bf641..2fe145c4704 100644 --- a/config/cmake/examples/HDF5_Examples_options.cmake +++ b/config/cmake/examples/HDF5_Examples_options.cmake @@ -14,14 +14,13 @@ #### format: set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DXXX:YY=ZZZZ") ### #### DEFAULT: ### #### BUILD_SHARED_LIBS:BOOL=OFF ### -#### HDF_BUILD_C:BOOL=ON ### -#### HDF_BUILD_CXX:BOOL=OFF ### -#### HDF_BUILD_FORTRAN:BOOL=OFF ### -#### HDF_BUILD_JAVA:BOOL=OFF ### -#### HDF_BUILD_FILTERS:BOOL=OFF ### -#### BUILD_TESTING:BOOL=OFF ### -#### HDF_ENABLE_PARALLEL:BOOL=OFF ### -#### HDF_ENABLE_THREADSAFE:BOOL=OFF ### +#### H5EX_BUILD_C:BOOL=ON ### +#### H5EX_BUILD_CXX:BOOL=OFF ### +#### H5EX_BUILD_FORTRAN:BOOL=OFF ### +#### H5EX_BUILD_JAVA:BOOL=OFF ### +#### H5EX_BUILD_FILTERS:BOOL=OFF ### +#### H5EX_BUILD_TESTING:BOOL=OFF ### +#### H5EX_ENABLE_PARALLEL:BOOL=OFF ### ############################################################################################# ### uncomment/comment and change the following lines for other configuration options @@ -44,38 +43,34 @@ ############################################################################################# #### languages #### ### disable C builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_BUILD_C:BOOL=OFF") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_BUILD_C:BOOL=OFF") ### enable C++ builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_BUILD_CXX:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_BUILD_CXX:BOOL=ON") ### enable Fortran builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_BUILD_FORTRAN:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_BUILD_FORTRAN:BOOL=ON") ### enable JAVA builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_BUILD_JAVA:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_BUILD_JAVA:BOOL=ON") ############################################################################################# ### enable FILTERS builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_BUILD_FILTERS:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_BUILD_FILTERS:BOOL=ON") ### default HDF5_PLUGIN_PATH to where the filter libraries are located #set(ENV{HDF5_PLUGIN_PATH} "${INSTALLDIR}/lib/plugin") ############################################################################################# ### enable parallel program builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_ENABLE_PARALLEL:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_ENABLE_PARALLEL:BOOL=ON") ############################################################################################# ### match the hdf5 library namespace set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF5_NAMESPACE:STRING=hdf5::") -############################################################################################# -### enable threadsafe program builds -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DHDF_ENABLE_THREADSAFE:BOOL=ON") - ############################################################################################# ### enable test program builds, requires reference files in testfiles subdirectory -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DBUILD_TESTING:BOOL=ON") -#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DCOMPARE_TESTING:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_BUILD_TESTING:BOOL=ON") +#set(ADD_BUILD_OPTIONS "${ADD_BUILD_OPTIONS} -DH5EX_COMPARE_TESTING:BOOL=ON") ############################################################################################# diff --git a/config/cmake/hdf5-config.cmake.in b/config/cmake/hdf5-config.cmake.in index 5ee4d85e4d3..325492ca9ec 100644 --- a/config/cmake/hdf5-config.cmake.in +++ b/config/cmake/hdf5-config.cmake.in @@ -92,7 +92,7 @@ if (${HDF5_PACKAGE_NAME}_ENABLE_PARALLEL) find_package(MPI QUIET REQUIRED) endif () -if (${HDF5_PACKAGE_NAME}_ENABLE_THREADSAFE OR ${HDF5_PACKAGE_NAME}_ENABLE_SUBFILING_VFD) +if (${HDF5_PACKAGE_NAME}_ENABLE_THREADS) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads QUIET REQUIRED) endif () diff --git a/release_docs/USING_CMake_Examples.txt b/release_docs/USING_CMake_Examples.txt index 2769fda3395..276cc03de00 100644 --- a/release_docs/USING_CMake_Examples.txt +++ b/release_docs/USING_CMake_Examples.txt @@ -78,12 +78,11 @@ III. Defaults in the HDF5_Examples_options.cmake file #### DEFAULT: ### #### BUILD_SHARED_LIBS:BOOL=OFF ### -#### HDF_BUILD_C:BOOL=ON ### -#### HDF_BUILD_CXX:BOOL=OFF ### -#### HDF_BUILD_FORTRAN:BOOL=OFF ### -#### HDF_BUILD_JAVA:BOOL=OFF ### -#### HDF_BUILD_FILTERS:BOOL=OFF ### -#### BUILD_TESTING:BOOL=OFF ### -#### HDF_ENABLE_PARALLEL:BOOL=OFF ### -#### HDF_ENABLE_THREADSAFE:BOOL=OFF ### +#### H5EX_BUILD_C:BOOL=ON ### +#### H5EX_BUILD_CXX:BOOL=OFF ### +#### H5EX_BUILD_FORTRAN:BOOL=OFF ### +#### H5EX_BUILD_JAVA:BOOL=OFF ### +#### H5EX_BUILD_FILTERS:BOOL=OFF ### +#### H5EX_BUILD_TESTING:BOOL=OFF ### +#### H5EX_ENABLE_PARALLEL:BOOL=OFF ### From b757ea94a100360ce00adeb980251fe1721bcda6 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Sun, 8 Sep 2024 07:12:56 -0500 Subject: [PATCH 75/94] Rework RFC url in aliases (#4813) --- doxygen/aliases | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doxygen/aliases b/doxygen/aliases index 24a496c2203..831ec7786b1 100644 --- a/doxygen/aliases +++ b/doxygen/aliases @@ -7,12 +7,12 @@ ALIASES += THG="The HDF Group" ALIASES += HDFURL="support.hdfgroup.org" # URL for archived files ALIASES += ARCURL="\HDFURL/archive/support/HDF5/doc" -# URL for RFCs -ALIASES += RFCURL="\HDFURL/hdf5/rfc" # URL for documentation ALIASES += DOCURL="\HDFURL/releases/hdf5/documentation" # URL for downloads ALIASES += DWNURL="\HDFURL/releases/hdf5/downloads" +# URL for RFCs +ALIASES += RFCURL="\DOCURL/rfc" ALIASES += AEXURL="\HDFURL/archive/support/ftp/HDF5/examples" # doxygen subdir (develop, v1_14) ALIASES += DOXURL="hdfgroup.github.io/hdf5/develop" From 2fb61bd641579f2baf8a6d789f92c9412c852152 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:34:08 -0500 Subject: [PATCH 76/94] Correct URL reference to downloads (#4817) --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e54d02c9587..7c1173f6868 100644 --- a/README.md +++ b/README.md @@ -103,14 +103,18 @@ in which a feature is introduced may change. SNAPSHOTS, PREVIOUS RELEASES AND SOURCE CODE -------------------------------------------- Periodically development code snapshots are provided at the following URL: - + https://github.com/HDFGroup/hdf5/releases/tag/snapshot Source packages for current and previous releases are located at: - - https://support.hdfgroup.org/downloads/hdf5 + + hdf5 1.14 releases: + https://support.hdfgroup.org/releases/hdf5/v1_14/index.html + + Archived releases: + https://support.hdfgroup.org/archive/support/ftp/HDF5/releases/index.html Development code is available at our Github location: - + https://github.com/HDFGroup/hdf5.git From 2f2192d677db6e4c41f8ea6dee5a3157bd677cfb Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:37:49 -0500 Subject: [PATCH 77/94] Convert exec_program to execute_process (#4819) --- config/cmake/FindHDFS.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/cmake/FindHDFS.cmake b/config/cmake/FindHDFS.cmake index e401a94fb81..61990cf6b7d 100644 --- a/config/cmake/FindHDFS.cmake +++ b/config/cmake/FindHDFS.cmake @@ -7,8 +7,8 @@ # HDFS_LIBRARIES, location of libhdfs.so # HDFS_FOUND, whether HDFS is found. -exec_program($ENV{HADOOP_HOME}/bin/hadoop ARGS version OUTPUT_VARIABLE Hadoop_VERSION - RETURN_VALUE Hadoop_RETURN) +execute_process(COMMAND $ENV{HADOOP_HOME}/bin/hadoop version OUTPUT_VARIABLE Hadoop_VERSION + RESULT_VARIABLE_VALUE Hadoop_RETURN) # currently only looking in HADOOP_HOME find_path(HDFS_INCLUDE_DIR hdfs.h PATHS From 98c5411f020bffe9039912775810c948b1418d7c Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Thu, 12 Sep 2024 08:01:08 -0500 Subject: [PATCH 78/94] Fix a bug in Subfiling VFD vector I/O setup (#4821) Fixes a bug where the vector I/O sizes weren't being extended when one of the entries in the array is 0. This caused an over-read of the I/O sizes buffer and on some machines would cause a memory allocation failure due to the calculated I/O vector size being too large. --- release_docs/RELEASE.txt | 18 +++++ src/H5FDsubfiling/H5FDsubfiling.c | 117 ++++++++++++++++++------------ testpar/t_subfiling_vfd.c | 116 +++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 46 deletions(-) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 0686bd47739..68f75531adf 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -823,6 +823,24 @@ Bug Fixes since HDF5-1.14.0 release =================================== Library ------- + - Fixed a bug in the Subfiling VFD that could cause a buffer over-read + and memory allocation failures + + When performing vector I/O with the Subfiling VFD, making use of the + vector I/O size extension functionality could cause the VFD to read + past the end of the "I/O sizes" array that is passed in. When an entry + in the "I/O sizes" array has the value 0 and that entry is at an array + index greater than 0, this signifies that the value in the preceding + array entry should be used for the rest of the I/O vectors, effectively + extending the last valid I/O size across the remaining entries. This + allows an application to save a bit on memory by passing in a smaller + "I/O sizes" array. The Subfiling VFD didn't implement a check for this + functionality in the portion of the code that generates I/O vectors, + causing it to read past the end of the "I/O sizes" array when it was + shorter than expected. This could also result in memory allocation + failures, as the nearby memory allocations are based off the values + read from that array, which could be uninitialized. + - Fixed H5Rget_attr_name to return the length of the attribute's name without the null terminator diff --git a/src/H5FDsubfiling/H5FDsubfiling.c b/src/H5FDsubfiling/H5FDsubfiling.c index affcfcbe94a..796654254ad 100644 --- a/src/H5FDsubfiling/H5FDsubfiling.c +++ b/src/H5FDsubfiling/H5FDsubfiling.c @@ -196,14 +196,14 @@ static herr_t H5FD__subfiling_mirror_writes_to_stub(H5FD_subfiling_t *file, uint const void *bufs[]); static herr_t H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_count, H5FD_mem_t types[], haddr_t file_offsets[], - size_t nelemts[], H5_flexible_const_ptr_t bufs[], - H5FD_subfiling_io_type_t io_type, size_t *ioreq_count, - uint32_t *iovec_len, H5FD_mem_t **io_types, - haddr_t **io_addrs, size_t **io_sizes, - H5_flexible_const_ptr_t **io_bufs); -static void H5FD__subfiling_get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count, - haddr_t file_offsets[], size_t nelemts[], size_t *max_iovec_depth, - size_t *max_num_subfiles); + size_t io_sizes[], H5_flexible_const_ptr_t bufs[], + H5FD_subfiling_io_type_t io_type, size_t *ioreq_count_out, + uint32_t *iovec_len_out, H5FD_mem_t **io_types_out, + haddr_t **io_addrs_out, size_t **io_sizes_out, + H5_flexible_const_ptr_t **io_bufs_out); +static herr_t H5FD__subfiling_get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count, + haddr_t file_offsets[], size_t io_sizes[], + size_t *max_iovec_depth, size_t *max_num_subfiles); static herr_t H5FD__subfiling_translate_io_req_to_iovec( subfiling_context_t *sf_context, size_t iovec_idx, size_t iovec_len, size_t iovec_count, H5FD_mem_t type, haddr_t addr, size_t io_size, H5_flexible_const_ptr_t io_buf, H5FD_subfiling_io_type_t io_type, @@ -2023,7 +2023,7 @@ H5FD__subfiling_io_helper(H5FD_subfiling_t *file, size_t io_count, H5FD_mem_t ty io_count, /* IN: Number of entries in `types`, `addrs`, `sizes` and `bufs` */ types, /* IN: Array of memory types */ addrs, /* IN: Array of starting file offsets */ - sizes, /* IN: Array of I/O sizes (in terms of elements) */ + sizes, /* IN: Array of I/O sizes */ bufs, /* IN: Array of I/O buffers */ io_type, /* IN: Type of I/O being performed (IO_TYPE_WRITE or IO_TYPE_READ) */ &ioreq_count, /* OUT: Number of I/O requests to be made */ @@ -2335,30 +2335,30 @@ H5FD__subfiling_mirror_writes_to_stub(H5FD_subfiling_t *file, uint32_t count, H5 * - the type of I/O being performed (IO_TYPE_WRITE or * IO_TYPE_READ) * - * ioreq_count (OUT) + * ioreq_count_out (OUT) * - the number of I/O requests needed to fully satisfy the * I/O operation * - * iovec_len (OUT) + * iovec_len_out (OUT) * - the size of each I/O vector (in terms of array elements) * for each I/O request to be made * - * io_types (OUT) + * io_types_out (OUT) * - I/O vector of memory types for the I/O operation. * Allocated by this function and must be freed by the * caller. * - * io_addrs (OUT) + * io_addrs_out (OUT) * - I/O vector of file addresses for the I/O operation. * Allocated by this function and must be freed by the * caller. * - * io_sizes (OUT) + * io_sizes_out (OUT) * - I/O vector of the I/O sizes for the I/O operation. * Allocated by this function and must be freed by the * caller. * - * io_bufs (OUT) + * io_bufs_out (OUT) * - I/O vector of the I/O buffers for the I/O operation. * Allocated by this function and must be freed by the * caller. @@ -2368,10 +2368,11 @@ H5FD__subfiling_mirror_writes_to_stub(H5FD_subfiling_t *file, uint32_t count, H5 */ static herr_t H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_count, H5FD_mem_t types[], - haddr_t file_offsets[], size_t nelemts[], H5_flexible_const_ptr_t bufs[], - H5FD_subfiling_io_type_t io_type, size_t *ioreq_count, - uint32_t *iovec_len, H5FD_mem_t **io_types, haddr_t **io_addrs, - size_t **io_sizes, H5_flexible_const_ptr_t **io_bufs) + haddr_t file_offsets[], size_t io_sizes[], H5_flexible_const_ptr_t bufs[], + H5FD_subfiling_io_type_t io_type, size_t *ioreq_count_out, + uint32_t *iovec_len_out, H5FD_mem_t **io_types_out, + haddr_t **io_addrs_out, size_t **io_sizes_out, + H5_flexible_const_ptr_t **io_bufs_out) { H5_flexible_const_ptr_t *loc_io_bufs = NULL; H5FD_mem_t *loc_io_types = NULL; @@ -2395,18 +2396,18 @@ H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_c assert(sf_context->topology); assert(types || in_count == 0); assert(file_offsets || in_count == 0); - assert(nelemts || in_count == 0); + assert(io_sizes || in_count == 0); assert(bufs || in_count == 0); - assert(ioreq_count); - assert(iovec_len); - assert(io_types); - assert(io_addrs); - assert(io_sizes); - assert(io_bufs); + assert(ioreq_count_out); + assert(iovec_len_out); + assert(io_types_out); + assert(io_addrs_out); + assert(io_sizes_out); + assert(io_bufs_out); /* Set some returned values early */ - *ioreq_count = 0; - *iovec_len = 0; + *ioreq_count_out = 0; + *iovec_len_out = 0; /* Nothing to do */ if (in_count == 0) @@ -2416,11 +2417,16 @@ H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_c * Do some initial pre-processing to determine how large of I/O vectors we * will need to allocate to satisfy the entire I/O request */ - H5FD__subfiling_get_iovec_sizes(sf_context, in_count, file_offsets, nelemts, &max_iovec_depth, - &max_num_subfiles_touched); + if (H5FD__subfiling_get_iovec_sizes(sf_context, in_count, file_offsets, io_sizes, &max_iovec_depth, + &max_num_subfiles_touched) < 0) + HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "can't determine maximum I/O request size"); tot_iovec_len = in_count * max_iovec_depth * max_num_subfiles_touched; + /* Nothing to do */ + if (tot_iovec_len == 0) + HGOTO_DONE(SUCCEED); + #ifdef H5_SUBFILING_DEBUG H5FD__subfiling_log( sf_context->sf_context_id, @@ -2456,10 +2462,10 @@ H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_c } if (!extend_sizes) { - if (io_idx > 0 && nelemts[io_idx] == 0) + if (io_idx > 0 && io_sizes[io_idx] == 0) extend_sizes = true; else - io_size = nelemts[io_idx]; + io_size = io_sizes[io_idx]; } if (H5FD__subfiling_translate_io_req_to_iovec(sf_context, iovec_idx, max_num_subfiles_touched, @@ -2469,13 +2475,13 @@ H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_c HGOTO_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "can't translate I/O request to I/O vectors"); } - *ioreq_count = in_count * max_iovec_depth; + *ioreq_count_out = in_count * max_iovec_depth; H5_CHECK_OVERFLOW(max_num_subfiles_touched, size_t, uint32_t); - *iovec_len = (uint32_t)max_num_subfiles_touched; - *io_types = loc_io_types; - *io_addrs = loc_io_addrs; - *io_sizes = loc_io_sizes; - *io_bufs = loc_io_bufs; + *iovec_len_out = (uint32_t)max_num_subfiles_touched; + *io_types_out = loc_io_types; + *io_addrs_out = loc_io_addrs; + *io_sizes_out = loc_io_sizes; + *io_bufs_out = loc_io_bufs; done: if (ret_value < 0) { @@ -2497,26 +2503,28 @@ H5FD__subfiling_generate_io_vectors(subfiling_context_t *sf_context, size_t in_c * info is used to calculate the total size of I/O vectors we * need to allocate to satisfy an entire I/O request. * - * Return: Maximum I/O vector depth and maximum number of subfiles - * touched (can't fail) + * Return: Non-negative on success/negative on failure * *------------------------------------------------------------------------- */ -static void +static herr_t H5FD__subfiling_get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count, haddr_t file_offsets[], - size_t nelemts[], size_t *max_iovec_depth, size_t *max_num_subfiles) + size_t io_sizes[], size_t *max_iovec_depth, size_t *max_num_subfiles) { int64_t stripe_size = 0; int64_t block_size = 0; size_t loc_max_iovec_depth = 0; size_t loc_max_num_subfiles = 0; + size_t io_size = 0; + bool extend_sizes = false; int num_subfiles = 0; + herr_t ret_value = SUCCEED; - FUNC_ENTER_PACKAGE_NOERR + FUNC_ENTER_PACKAGE assert(sf_context); assert(file_offsets); - assert(nelemts); + assert(io_sizes); assert(max_iovec_depth); assert(max_num_subfiles); @@ -2538,7 +2546,23 @@ H5FD__subfiling_get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count size_t cur_iovec_depth; H5_CHECKED_ASSIGN(cur_file_offset, int64_t, file_offsets[io_idx], haddr_t); - H5_CHECKED_ASSIGN(data_size, int64_t, nelemts[io_idx], size_t); + + if (!extend_sizes) { + if (io_idx > 0 && io_sizes[io_idx] == 0) + extend_sizes = true; + else + io_size = io_sizes[io_idx]; + } + + H5_CHECKED_ASSIGN(data_size, int64_t, io_size, size_t); + + if (cur_file_offset < 0) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, + "file offset of %" PRIuHADDR " at index %zu too large; wrapped around", + file_offsets[io_idx], io_idx); + if (data_size < 0) + HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "I/O size of %zu at index %zu too large; wrapped around", + io_size, io_idx); /* * Calculate the following from the starting file offset: @@ -2645,7 +2669,8 @@ H5FD__subfiling_get_iovec_sizes(subfiling_context_t *sf_context, size_t in_count *max_iovec_depth = loc_max_iovec_depth; *max_num_subfiles = loc_max_num_subfiles; - FUNC_LEAVE_NOAPI_VOID +done: + FUNC_LEAVE_NOAPI(ret_value) } /*------------------------------------------------------------------------- diff --git a/testpar/t_subfiling_vfd.c b/testpar/t_subfiling_vfd.c index 27c48250be4..aa2da851eaa 100644 --- a/testpar/t_subfiling_vfd.c +++ b/testpar/t_subfiling_vfd.c @@ -105,6 +105,7 @@ static void test_read_different_stripe_size(void); static void test_subfiling_precreate_rank_0(void); static void test_subfiling_write_many_read_one(void); static void test_subfiling_write_many_read_few(void); +static void test_subfiling_vector_io_extension(void); static void test_subfiling_h5fuse(void); static test_func tests[] = { @@ -118,6 +119,7 @@ static test_func tests[] = { test_subfiling_precreate_rank_0, test_subfiling_write_many_read_one, test_subfiling_write_many_read_few, + test_subfiling_vector_io_extension, test_subfiling_h5fuse, }; @@ -2568,6 +2570,120 @@ test_subfiling_write_many_read_few(void) #undef SUBF_HDF5_TYPE #undef SUBF_C_TYPE +/* + * Test to check for a bug where the vector I/O sizes + * array wasn't being extended when an entry in the + * array was 0. + */ +#define SUBF_FILENAME "test_subfiling_vector_io_extension.h5" +#define SUBF_C_TYPE int +static void +test_subfiling_vector_io_extension(void) +{ + H5FD_subfiling_params_t cfg; + h5_stat_size_t file_size; + SUBF_C_TYPE *read_buf = NULL; + H5FD_mem_t *types = NULL; + h5_stat_t file_info; + uint32_t count = 64; + haddr_t *addrs = NULL; + haddr_t file_end_addr; + herr_t read_status; + size_t *sizes = NULL; + H5FD_t *file_ptr = NULL; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dxpl_id = H5I_INVALID_HID; + void **bufs = NULL; + + curr_nerrors = nerrors; + + if (MAINPROCESS) + TESTING_2("I/O vector size extension functionality"); + + /* Must use at least 2 subfiles to cause generation of + * I/O vectors within the VFD. + */ + cfg.ioc_selection = SELECT_IOC_ONE_PER_NODE; + cfg.stripe_size = (stripe_size_g > 0) ? stripe_size_g : 1048576; + cfg.stripe_count = num_iocs_g > 1 ? num_iocs_g : 2; + + fapl_id = create_subfiling_ioc_fapl(comm_g, info_g, true, &cfg, H5FD_IOC_DEFAULT_THREAD_POOL_SIZE); + VRFY((fapl_id >= 0), "FAPL creation succeeded"); + + file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + VRFY((H5Fclose(file_id) >= 0), "File close succeeded"); + + /* Re-open file through H5FDopen for direct reads */ + file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF); + VRFY(file_ptr, "H5FDopen succeeded"); + + /* + * Get the current file size to see where we can safely + * write to in the file without overwriting the superblock + */ + memset(&file_info, 0, sizeof(h5_stat_t)); + VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded"); + file_size = (h5_stat_size_t)file_info.st_size; + + H5_CHECK_OVERFLOW(file_size, h5_stat_size_t, haddr_t); + file_end_addr = (haddr_t)file_size; + + dxpl_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_id >= 0), "DXPL creation succeeded"); + + /* Set independent I/O on DXPL */ + VRFY((H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_INDEPENDENT) >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* Set EOA for following read call */ + VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, file_end_addr + (count * sizeof(int))) >= 0), + "H5FDset_eoa succeeded"); + + read_buf = malloc(count * sizeof(*read_buf)); + types = malloc(count * sizeof(*types)); + addrs = malloc(count * sizeof(*addrs)); + sizes = malloc(2 * sizeof(size_t)); + bufs = malloc(count * sizeof(*bufs)); + + sizes[0] = sizeof(SUBF_C_TYPE); + sizes[1] = 0; + + for (size_t i = 0; i < count; i++) { + types[i] = H5FD_MEM_DRAW; + addrs[i] = file_end_addr + (i * sizeof(SUBF_C_TYPE)); + bufs[i] = (void *)&(read_buf[i]); + } + + read_status = H5FDread_vector(file_ptr, dxpl_id, count, types, addrs, sizes, bufs); + VRFY((read_status >= 0), "H5FDread_vector succeeded"); + + VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded"); + + mpi_code_g = MPI_Barrier(comm_g); + VRFY((mpi_code_g == MPI_SUCCESS), "MPI_Barrier succeeded"); + + H5E_BEGIN_TRY + { + H5Fdelete(SUBF_FILENAME, fapl_id); + } + H5E_END_TRY + + VRFY((H5Pclose(fapl_id) >= 0), "FAPL close succeeded"); + VRFY((H5Pclose(dxpl_id) >= 0), "DXPL close succeeded"); + + free(bufs); + free(sizes); + free(addrs); + free(types); + free(read_buf); + + CHECK_PASSED(); +} +#undef SUBF_FILENAME +#undef SUBF_C_TYPE + /* * Test that the subfiling file can be read with the * sec2 driver after being fused back together with From 9c9bde3dd8bbe8d549eaa2031970738a4698a2d6 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:23:53 -0500 Subject: [PATCH 79/94] Remove extensions from the package binaries - msi, dmg, deb,rpm (#4820) --- .github/workflows/cmake-ctest.yml | 50 ++++++----------------------- .github/workflows/release-files.yml | 30 ++++++++--------- .github/workflows/remove-files.yml | 10 +++--- 3 files changed, 30 insertions(+), 60 deletions(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 09f3dae35fe..3231f02d742 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -181,13 +181,7 @@ jobs: id: publish-ctest-msi-binary run: | mkdir "${{ runner.workspace }}/buildmsi" - mkdir "${{ runner.workspace }}/buildmsi/hdf5" - Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING -Destination ${{ runner.workspace }}/buildmsi/hdf5/ - Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 -Destination ${{ runner.workspace }}/buildmsi/hdf5/ - Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-MSVC/README.md -Destination ${{ runner.workspace }}/buildmsi/hdf5/ - Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-MSVC/* -Destination ${{ runner.workspace }}/buildmsi/hdf5/ -Include *.msi - cd "${{ runner.workspace }}/buildmsi" - 7z a -tzip ${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi.zip hdf5 + Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-MSVC/* -Destination ${{ runner.workspace }}/buildmsi/${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi -Include *.msi shell: pwsh - name: List files in the space (Windows) @@ -208,7 +202,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: msi-vs2022_cl-binary - path: ${{ runner.workspace }}/buildmsi/${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi.zip + path: ${{ runner.workspace }}/buildmsi/${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` build_and_test_linux: @@ -279,26 +273,14 @@ jobs: id: publish-ctest-deb-binary run: | mkdir "${{ runner.workspace }}/builddeb" - mkdir "${{ runner.workspace }}/builddeb/hdf5" - cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING ${{ runner.workspace }}/builddeb/hdf5 - cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 ${{ runner.workspace }}/builddeb/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/README.md ${{ runner.workspace }}/builddeb/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/*.deb ${{ runner.workspace }}/builddeb/hdf5 - cd "${{ runner.workspace }}/builddeb" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/*.deb ${{ runner.workspace }}/builddeb/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb shell: bash - name: Publish rpm binary (Linux) id: publish-ctest-rpm-binary run: | mkdir "${{ runner.workspace }}/buildrpm" - mkdir "${{ runner.workspace }}/buildrpm/hdf5" - cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING ${{ runner.workspace }}/buildrpm/hdf5 - cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 ${{ runner.workspace }}/buildrpm/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/README.md ${{ runner.workspace }}/buildrpm/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/*.rpm ${{ runner.workspace }}/buildrpm/hdf5 - cd "${{ runner.workspace }}/buildrpm" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/*.rpm ${{ runner.workspace }}/buildrpm/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm shell: bash - name: List files in the space (Linux) @@ -318,14 +300,14 @@ jobs: uses: actions/upload-artifact@v4 with: name: deb-ubuntu-2204_gcc-binary - path: ${{ runner.workspace }}/builddeb/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz + path: ${{ runner.workspace }}/builddeb/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` - name: Save published binary rpm (Linux) uses: actions/upload-artifact@v4 with: name: rpm-ubuntu-2204_gcc-binary - path: ${{ runner.workspace }}/buildrpm/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz + path: ${{ runner.workspace }}/buildrpm/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` # Save doxygen files created by ctest script @@ -528,13 +510,7 @@ jobs: id: publish-ctest-dmg-binary run: | mkdir "${{ runner.workspace }}/builddmg" - mkdir "${{ runner.workspace }}/builddmg/hdf5" - cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING ${{ runner.workspace }}/builddmg/hdf5 - cp ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 ${{ runner.workspace }}/builddmg/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/README.md ${{ runner.workspace }}/builddmg/hdf5 - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg ${{ runner.workspace }}/builddmg/hdf5 - cd "${{ runner.workspace }}/builddmg" - tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-macos-Clang/*.dmg ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg shell: bash - name: List files in the space (MacOS_latest) @@ -554,7 +530,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: tgz-macos14_clang-dmg-binary - path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + path: ${{ runner.workspace }}/builddmg/${{ steps.set-file-base.outputs.FILE_BASE }}-macos14_clang.dmg if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` build_and_test_S3_linux: @@ -745,13 +721,7 @@ jobs: id: publish-ctest-msi-binary run: | mkdir "${{ runner.workspace }}/buildmsi" - mkdir "${{ runner.workspace }}/buildmsi/hdf5" - Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING -Destination ${{ runner.workspace }}/buildmsi/hdf5/ - Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 -Destination ${{ runner.workspace }}/buildmsi/hdf5/ - Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Intel/README.md -Destination ${{ runner.workspace }}/buildmsi/hdf5/ - Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Intel/* -Destination ${{ runner.workspace }}/buildmsi/hdf5/ -Include *.msi - cd "${{ runner.workspace }}/buildmsi" - 7z a -tzip ${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi.zip hdf5 + Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Intel/* -Destination ${{ runner.workspace }}/buildmsi/${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi -Include *.msi shell: pwsh - name: List files in the space (Windows_intel) @@ -772,7 +742,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: msi-vs2022_intel-binary - path: ${{ runner.workspace }}/buildmsi/${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi.zip + path: ${{ runner.workspace }}/buildmsi/${{ steps.set-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` build_and_test_linux_intel: diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index c51c9754697..af5f98ba6c6 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -186,16 +186,16 @@ jobs: sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc_s3.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_intel.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi.zip >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt + sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt sha256sum ${{ steps.get-file-base.outputs.FILE_BASE }}.html.abi.reports.tar.gz >> ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt - name: Create sha256 sums for files for nonversioned files @@ -232,16 +232,16 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb + ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc_s3.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi.zip + ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_intel.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi.zip + ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi ${{ steps.get-file-base.outputs.FILE_BASE }}.html.abi.reports.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` @@ -261,16 +261,16 @@ jobs: hdf5.tar.gz hdf5.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb + ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc_s3.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi.zip + ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_intel.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi.zip + ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi ${{ steps.get-file-base.outputs.FILE_BASE }}.html.abi.reports.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.sha256sums.txt if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` diff --git a/.github/workflows/remove-files.yml b/.github/workflows/remove-files.yml index 643f2c1cf49..418065c8e00 100644 --- a/.github/workflows/remove-files.yml +++ b/.github/workflows/remove-files.yml @@ -51,13 +51,13 @@ jobs: ${{ steps.get-file-base.outputs.FILE_BASE }}.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}.zip ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-macos14_clang.dmg ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb.tar.gz - ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm.tar.gz + ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb + ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.rpm ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc_s3.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi.zip + ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_cl.msi ${{ steps.get-file-base.outputs.FILE_BASE }}-ubuntu-2204_intel.tar.gz ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.zip - ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi.zip + ${{ steps.get-file-base.outputs.FILE_BASE }}-win-vs2022_intel.msi From 901a8db2a203ffe7f92c1b782742c1599a7825d1 Mon Sep 17 00:00:00 2001 From: Larry Knox Date: Thu, 12 Sep 2024 15:23:31 -0500 Subject: [PATCH 80/94] Fix copyright notice urls in new test/ttsafe* files. (#4824) * Update obsolete COPYING file URLs in copyright headers. --- test/ttsafe_atomic.c | 2 +- test/ttsafe_develop.c | 2 +- test/ttsafe_rec_rwlock.c | 2 +- test/ttsafe_rwlock.c | 2 +- test/ttsafe_semaphore.c | 2 +- test/ttsafe_thread_id.c | 2 +- test/ttsafe_thread_pool.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/ttsafe_atomic.c b/test/ttsafe_atomic.c index 71046be44af..0150ccecade 100644 --- a/test/ttsafe_atomic.c +++ b/test/ttsafe_atomic.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/test/ttsafe_develop.c b/test/ttsafe_develop.c index 82ee8640ca1..1ecf1757618 100644 --- a/test/ttsafe_develop.c +++ b/test/ttsafe_develop.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/test/ttsafe_rec_rwlock.c b/test/ttsafe_rec_rwlock.c index 3e17011e11c..a09dc6ea9c5 100644 --- a/test/ttsafe_rec_rwlock.c +++ b/test/ttsafe_rec_rwlock.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/test/ttsafe_rwlock.c b/test/ttsafe_rwlock.c index c85434288ee..e160788816e 100644 --- a/test/ttsafe_rwlock.c +++ b/test/ttsafe_rwlock.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/test/ttsafe_semaphore.c b/test/ttsafe_semaphore.c index 4d1a6a308cf..563a4f5d3c1 100644 --- a/test/ttsafe_semaphore.c +++ b/test/ttsafe_semaphore.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/test/ttsafe_thread_id.c b/test/ttsafe_thread_id.c index 49678645819..cd063e05cda 100644 --- a/test/ttsafe_thread_id.c +++ b/test/ttsafe_thread_id.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ diff --git a/test/ttsafe_thread_pool.c b/test/ttsafe_thread_pool.c index 9dd28360e50..e5362111be1 100644 --- a/test/ttsafe_thread_pool.c +++ b/test/ttsafe_thread_pool.c @@ -5,7 +5,7 @@ * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * - * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ From 0737d0dbf74d7107ebb3dd2358f68cd3f2944094 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 12 Sep 2024 22:46:58 -0500 Subject: [PATCH 81/94] Correct URLs in documentation (#4823) --- CITATION.cff | 2 +- HDF5Examples/README.md | 30 +++++++++---------- config/cmake/README.md.cmake.in | 2 +- doc/parallel-compression.md | 6 ++-- doxygen/aliases | 10 +++---- doxygen/dox/IntroHDF5.dox | 1 - doxygen/dox/LearnBasics3.dox | 28 ++++++----------- doxygen/dox/LearnHDFView.dox | 2 +- doxygen/dox/VOLConnGuide.dox | 4 +-- doxygen/hdf5doxy_layout.xml | 6 ++-- hl/src/H5DOpublic.h | 2 +- hl/src/H5DSpublic.h | 4 +-- hl/src/H5LTpublic.h | 2 +- java/src/hdf/overview.html | 2 +- release_docs/INSTALL | 2 +- release_docs/INSTALL_Autotools.txt | 4 +-- release_docs/INSTALL_parallel | 2 +- release_docs/RELEASE.txt | 6 ++-- release_docs/RELEASE_PROCESS.md | 4 +-- src/H5Ppublic.h | 14 ++++----- src/H5VLmodule.h | 2 +- src/H5module.h | 2 +- tools/src/h5dump/h5dump.c | 7 ++--- tools/src/h5dump/h5dump.h | 6 ++-- tools/test/h5dump/expected/h5dump-help.txt | 2 +- .../pbits/tnofilename-with-packed-bits.ddl | 2 +- .../expected/pbits/tpbitsIncomplete.ddl | 2 +- .../expected/pbits/tpbitsLengthExceeded.ddl | 2 +- .../expected/pbits/tpbitsLengthPositive.ddl | 2 +- .../expected/pbits/tpbitsMaxExceeded.ddl | 2 +- .../expected/pbits/tpbitsOffsetExceeded.ddl | 2 +- .../expected/pbits/tpbitsOffsetNegative.ddl | 2 +- 32 files changed, 76 insertions(+), 90 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index f7eaf133318..c96341f138c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,4 +9,4 @@ authors: website: 'https://www.hdfgroup.org' repository-code: 'https://github.com/HDFGroup/hdf5' url: 'https://www.hdfgroup.org/HDF5/' -repository-artifact: 'https://support.hdfgroup.org/downloads/HDF5' +repository-artifact: 'https://support.hdfgroup.org/downloads/index.html' diff --git a/HDF5Examples/README.md b/HDF5Examples/README.md index c1a27d5fb12..82b3cfec46d 100644 --- a/HDF5Examples/README.md +++ b/HDF5Examples/README.md @@ -9,9 +9,7 @@ in science, engineering, and research communities worldwide. The HDF Group is the developer, maintainer, and steward of HDF5 software. Find more information about The HDF Group, the HDF5 Community, and other HDF5 software projects, -tools, and services at The HDF Group's website. - - https://www.hdfgroup.org/ +tools, and services at [The HDF Group's website](https://www.hdfgroup.org/). @@ -19,44 +17,44 @@ HELP AND SUPPORT ---------------- Information regarding Help Desk and Support services is available at - https://hdfgroup.atlassian.net/servicedesk/customer/portals + https://help.hdfgroup.org FORUM and NEWS -------------- -The following public forums are provided for public announcements and discussions +The [HDF Forum](https://forum.hdfgroup.org) is provided for public announcements and discussions of interest to the general HDF5 Community. - - Homepage of the Forum - https://forum.hdfgroup.org - - - News and Announcement + - News and Announcements https://forum.hdfgroup.org/c/news-and-announcements-from-the-hdf-group - - HDF5 and HDF4 Topics + - HDF5 Topics https://forum.hdfgroup.org/c/hdf5 These forums are provided as an open and public service for searching and reading. Posting requires completing a simple registration and allows one to join in the -conversation. Please read the following instructions pertaining to the Forum's -use and configuration - https://forum.hdfgroup.org/t/quickstart-guide-welcome-to-the-new-hdf-forum +conversation. Please read the [instructions](https://forum.hdfgroup.org/t/quickstart-guide-welcome-to-the-new-hdf-forum +) pertaining to the Forum's use and configuration. HDF5 SNAPSHOTS, PREVIOUS RELEASES AND SOURCE CODE -------------------------------------------- Full Documentation and Programming Resources for this HDF5 can be found at - https://support.hdfgroup.org/documentation/hdf5/index.html + https://support.hdfgroup.org/documentation/index.html Periodically development code snapshots are provided at the following URL: - https://github.com/HDFGroup/hdf5/releases + https://github.com/HDFGroup/hdf5/releases/tag/snapshot Source packages for current and previous releases are located at: - https://support.hdfgroup.org/releases/hdf5/downloads/ + hdf5 1.14 releases: + https://support.hdfgroup.org/releases/hdf5/v1_14/index.html + + Archived releases: + https://support.hdfgroup.org/archive/support/ftp/HDF5/releases/index.html Development code is available at our Github location: diff --git a/config/cmake/README.md.cmake.in b/config/cmake/README.md.cmake.in index 3f541e4e8a3..40294c15255 100644 --- a/config/cmake/README.md.cmake.in +++ b/config/cmake/README.md.cmake.in @@ -75,6 +75,6 @@ For more information see USING_CMake_Examples.txt in the install folder. =========================================================================== Documentation for this release can be found at the following URL: - https://support.hdfgroup.org/hdf5/@HDF5_PACKAGE_NAME@-@HDF5_PACKAGE_VERSION@/documentation/doxygen/index.html + https://support.hdfgroup.org/releases/hdf5/@${H5_VERS_MAJOR}@_@${H5_VERS_MINOR}@/@${H5_VERS_MAJOR}@_@${H5_VERS_MINOR}@_@${H5_VERS_RELEASE}@/documentation/doxygen/index.html Bugs should be reported to help@hdfgroup.org. diff --git a/doc/parallel-compression.md b/doc/parallel-compression.md index 0d16c448e65..9879f6efc91 100644 --- a/doc/parallel-compression.md +++ b/doc/parallel-compression.md @@ -340,9 +340,9 @@ hid_t file_id = H5Fcreate("file.h5", H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); [u5]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga85faefca58387bba409b65c470d7d851 [u6]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga4335bb45b35386daa837b4ff1b9cd4a4 [u7]: https://hdfgroup.github.io/hdf5/develop/group___d_c_p_l.html#ga6bd822266b31f86551a9a1d79601b6a2 -[u8]: https://support.hdfgroup.org/documentation/hdf5/parallel-compression-improvements-in-hdf5-1-13-1 -[u9]: https://support.hdfgroup.org/documentation/hdf5/chunking_in_hdf5.html -[u10]: https://support.hdfgroup.org/documentation/hdf5/technotes/TechNote-HDF5-ImprovingIOPerformanceCompressedDatasets.pdf +[u8]: https://www.hdfgroup.org/2022/03/04/parallel-compression-improvements-in-hdf5-1-13-1/ +[u9]: https://support.hdfgroup.org/releases/hdf5/documentation/advanced_topics/chunking_in_hdf5.md +[u10]: https://support.hdfgroup.org/releases/hdf5/documentation/hdf5_topics/HDF5ImprovingIOPerformanceCompressedDatasets.pdf [u11]: https://hdfgroup.github.io/hdf5/develop/group___f_a_p_l.html#gab99d5af749aeb3896fd9e3ceb273677a [u12]: https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#ga167ff65f392ca3b7f1933b1cee1b9f70 [u13]: https://hdfgroup.github.io/hdf5/develop/group___f_c_p_l.html#gad012d7f3c2f1e1999eb1770aae3a4963 diff --git a/doxygen/aliases b/doxygen/aliases index 831ec7786b1..3c79b179df0 100644 --- a/doxygen/aliases +++ b/doxygen/aliases @@ -258,13 +258,13 @@ ALIASES += sa_metadata_ops="\sa \li H5Pget_all_coll_metadata_ops() \li H5Pget_co ALIASES += ref_cons_semantics="Enabling a Strict Consistency Semantics Model in Parallel HDF5" ALIASES += ref_file_image_ops="HDF5 File Image Operations" -ALIASES += ref_filter_pipe="Data Flow Pipeline for H5Dread()" +ALIASES += ref_filter_pipe="Data Flow Pipeline for H5Dread()" ALIASES += ref_group_impls="Group implementations in HDF5" ALIASES += ref_h5lib_relver="HDF5 Library Release Version Numbers" -ALIASES += ref_mdc_in_hdf5="Metadata Caching in HDF5" -ALIASES += ref_mdc_logging="Metadata Cache Logging" -ALIASES += ref_news_112="New Features in HDF5 Release 1.12" -ALIASES += ref_h5ocopy="Copying Committed Datatypes with H5Ocopy()" +ALIASES += ref_mdc_in_hdf5="Metadata Caching in HDF5" +ALIASES += ref_mdc_logging="Metadata Cache Logging" +ALIASES += ref_news_112="New Features in HDF5 Release 1.12" +ALIASES += ref_h5ocopy="Copying Committed Datatypes with H5Ocopy()" ALIASES += ref_sencode_fmt_change="RFC H5Sencode() / H5Sdecode() Format Change" ALIASES += ref_vlen_strings="\Emph{Creating variable-length string datatypes}" ALIASES += ref_vol_doc="VOL documentation" diff --git a/doxygen/dox/IntroHDF5.dox b/doxygen/dox/IntroHDF5.dox index 6f3938ed8b2..acb497120da 100644 --- a/doxygen/dox/IntroHDF5.dox +++ b/doxygen/dox/IntroHDF5.dox @@ -617,7 +617,6 @@ on the HDF-EOS Tools and Information Center pag \li \ref LBExamples \li \ref ExAPI \li Examples in the Source Code -\li Other Examples \section secHDF5ExamplesCompile How To Compile For information on compiling in C, C++ and Fortran, see: \ref LBCompiling diff --git a/doxygen/dox/LearnBasics3.dox b/doxygen/dox/LearnBasics3.dox index d853c83d742..13cb4f43abd 100644 --- a/doxygen/dox/LearnBasics3.dox +++ b/doxygen/dox/LearnBasics3.dox @@ -181,9 +181,9 @@ created the dataset layout cannot be changed. The h5repack utility can be used t to a new with a new layout. \section secLBDsetLayoutSource Sources of Information -Chunking in HDF5 -(See the documentation on Advanced Topics in HDF5) -see \ref sec_plist in the HDF5 \ref UG. +Chunking in HDF5 +(See the documentation on Advanced Topics in HDF5) +\see \ref sec_plist in the HDF5 \ref UG.
    Previous Chapter \ref LBPropsList - Next Chapter \ref LBExtDset @@ -201,7 +201,7 @@ certain initial dimensions, then to later increase the size of any of the initia HDF5 requires you to use chunking to define extendible datasets. This makes it possible to extend datasets efficiently without having to excessively reorganize storage. (To use chunking efficiently, -be sure to see the advanced topic, Chunking in HDF5.) +be sure to see the advanced topic, Chunking in HDF5.) The following operations are required in order to extend a dataset: \li Declare the dataspace of the dataset to have unlimited dimensions for all dimensions that might eventually be extended. @@ -243,7 +243,7 @@ Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics \section secLBComDsetCreate Creating a Compressed Dataset HDF5 requires you to use chunking to create a compressed dataset. (To use chunking efficiently, -be sure to see the advanced topic, Chunking in HDF5.) +be sure to see the advanced topic, Chunking in HDF5.) The following operations are required in order to create a compressed dataset: \li Create a dataset creation property list. @@ -251,7 +251,7 @@ The following operations are required in order to create a compressed dataset: \li Create the dataset. \li Close the dataset creation property list and dataset. -For more information on compression, see the FAQ question on Using Compression in HDF5. +For more information on compression, see the FAQ question on Using Compression in HDF5. \section secLBComDsetProg Programming Example @@ -968,8 +968,7 @@ or on WINDOWS you may need to add the path to the bin folder to PATH. \section secLBCompilingCMake Compiling an Application with CMake \subsection subsecLBCompilingCMakeScripts CMake Scripts for Building Applications -Simple scripts are provided for building applications with different languages and options. -See CMake Scripts for Building Applications. +See Using CMake to Build Applications to build applications with different languages and options. For a more complete script (and to help resolve issues) see the script provided with the HDF5 Examples project. @@ -977,7 +976,7 @@ For a more complete script (and to help resolve issues) see the script provided The installed HDF5 can be verified by compiling the HDF5 Examples project, included with the CMake built HDF5 binaries in the share folder or you can go to the HDF5 Examples in the HDF5 github repository. -Go into the share directory and follow the instructions in USING_CMake_examples.txt to build the examples. +Go into the share directory and follow the instructions in Using CMake to Build Examples to build the examples. In general, users must first set the HDF5_ROOT environment variable to the installed location of the CMake configuration files for HDF5. For example, on Windows the following path might be set: @@ -1031,17 +1030,8 @@ For example, on Unix the log files will be in: There are log files for the configure, test, and build.
    -Previous Chapter \ref LBQuizAnswers - Next Chapter \ref LBTraining +Previous Chapter \ref LBQuizAnswers Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics -@page LBTraining Training Videos - -Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics - -Training Videos - -
    -Navigate back: \ref index "Main" / \ref GettingStarted / \ref LearnBasics - */ diff --git a/doxygen/dox/LearnHDFView.dox b/doxygen/dox/LearnHDFView.dox index cfe11e19137..2a1ed610ef2 100644 --- a/doxygen/dox/LearnHDFView.dox +++ b/doxygen/dox/LearnHDFView.dox @@ -246,7 +246,7 @@ in the file). Please note that the chunk sizes used in this topic are for demonstration purposes only. For information on chunking and specifying an appropriate chunk size, see the -Chunking in HDF5 documentation. +Chunking in HDF5 documentation. Also see the HDF5 Tutorial topic on \ref secLBComDsetCreate.
      diff --git a/doxygen/dox/VOLConnGuide.dox b/doxygen/dox/VOLConnGuide.dox index 1f0fb20b022..c693980be1a 100644 --- a/doxygen/dox/VOLConnGuide.dox +++ b/doxygen/dox/VOLConnGuide.dox @@ -92,7 +92,7 @@ Public header Files you will need to be familiar with include:
    Many VOL connectors are listed on The HDF Group's VOL plugin registration page, located at: -Registered VOL Connectors. +Registered VOL Connectors. Not all of these VOL connectors are supported by The HDF Group and the level of completeness varies, but the connectors found there can serve as examples of working implementations @@ -195,7 +195,7 @@ contact help@hdfgroup.org for help with this. We name you've chosen will appear on the registered VOL connectors page. As noted above, registered VOL connectors will be listed at: -Registered VOL Connectors +Registered VOL Connectors A new \b conn_version field has been added to the class struct for 1.13. This field is currently not used by the library so its use is determined by the connector author. Best practices for this field will be determined diff --git a/doxygen/hdf5doxy_layout.xml b/doxygen/hdf5doxy_layout.xml index 20e951856c7..8bd7aaf4c08 100644 --- a/doxygen/hdf5doxy_layout.xml +++ b/doxygen/hdf5doxy_layout.xml @@ -5,12 +5,12 @@ - + + --> diff --git a/hl/src/H5DOpublic.h b/hl/src/H5DOpublic.h index 09a8f64829f..b3ea31d67e1 100644 --- a/hl/src/H5DOpublic.h +++ b/hl/src/H5DOpublic.h @@ -161,7 +161,7 @@ H5_HLDLL herr_t H5DOappend(hid_t dset_id, hid_t dxpl_id, unsigned axis, size_t e * from one datatype to another, and the filter pipeline to write the chunk. * Developers should have experience with these processes before * using this function. Please see - * + * * Using the Direct Chunk Write Function * for more information. * diff --git a/hl/src/H5DSpublic.h b/hl/src/H5DSpublic.h index 6a08be8e5c2..a7c9c9326a8 100644 --- a/hl/src/H5DSpublic.h +++ b/hl/src/H5DSpublic.h @@ -147,7 +147,7 @@ H5_HLDLL herr_t H5DSattach_scale(hid_t did, hid_t dsid, unsigned int idx); * dimension \p idx of dataset \p did. This deletes the entries in the * #DIMENSION_LIST and #REFERENCE_LIST attributes, * as defined in section 4.2 of - * + * * HDF5 Dimension Scale Specification. * * Fails if: @@ -180,7 +180,7 @@ H5_HLDLL herr_t H5DSdetach_scale(hid_t did, hid_t dsid, unsigned int idx); * as defined above. Creates the CLASS attribute, set to the value * "DIMENSION_SCALE" and an empty #REFERENCE_LIST attribute, * as described in - * + * * HDF5 Dimension Scale Specification. * (PDF, see section 4.2). * diff --git a/hl/src/H5LTpublic.h b/hl/src/H5LTpublic.h index 514fe244e10..f5eea20eb60 100644 --- a/hl/src/H5LTpublic.h +++ b/hl/src/H5LTpublic.h @@ -1625,7 +1625,7 @@ H5_HLDLL htri_t H5LTpath_valid(hid_t loc_id, const char *path, hbool_t check_obj * \note **Recommended Reading:** * \note This function is part of the file image operations feature set. * It is highly recommended to study the guide - * + * * HDF5 File Image Operations before using this feature set.\n * See the “See Also” section below for links to other elements of * HDF5 file image operations. diff --git a/java/src/hdf/overview.html b/java/src/hdf/overview.html index 8329277cda7..84e945b2f87 100644 --- a/java/src/hdf/overview.html +++ b/java/src/hdf/overview.html @@ -91,6 +91,6 @@

    and the HDF5 library.

    To Obtain

    -The JHI5 is included with the HDF5 library. +The JHI5 is included with the HDF5 library. diff --git a/release_docs/INSTALL b/release_docs/INSTALL index 63f2115fdd6..afd077f772b 100644 --- a/release_docs/INSTALL +++ b/release_docs/INSTALL @@ -49,7 +49,7 @@ CONTENTS include the Szip library with the encoder enabled. These can be found here: - https://support.hdfgroup.org/downloads/HDF5 + https://support.hdfgroup.org/downloads/index.html Please notice that if HDF5 configure cannot find a valid Szip library, configure will not fail; in this case, the compression filter will diff --git a/release_docs/INSTALL_Autotools.txt b/release_docs/INSTALL_Autotools.txt index 0a2400dc096..dc394be4521 100644 --- a/release_docs/INSTALL_Autotools.txt +++ b/release_docs/INSTALL_Autotools.txt @@ -334,7 +334,7 @@ III. Full installation instructions for source distributions (or '--with-pthread=DIR') flag to the configure script. For further information, see: - https://support.hdfgroup.org/documentation/HDF5/Questions+about+thread-safety+and+concurrent+access + https://support.hdfgroup.org/releases/hdf5/documentation/gen_topics/Questions+about+thread-safety+and+concurrent+access The high-level, C++, Fortran and Java interfaces are not compatible with the thread-safety option because the lock is not hoisted @@ -492,7 +492,7 @@ IV. Using the Library For information on using HDF5 see the documentation, tutorials and examples found here: - https://support.hdfgroup.org/documentation/HDF5/index.html + https://support.hdfgroup.org/documentation/index.html A summary of the features included in the built HDF5 installation can be found in the libhdf5.settings file in the same directory as the static and/or diff --git a/release_docs/INSTALL_parallel b/release_docs/INSTALL_parallel index df255c6e0ad..e2ac46a471d 100644 --- a/release_docs/INSTALL_parallel +++ b/release_docs/INSTALL_parallel @@ -90,7 +90,7 @@ nodes. They would probably work for other Cray systems but have not been verified. Obtain the HDF5 source code: - https://support.hdfgroup.org/downloads/HDF5 + https://support.hdfgroup.org/downloads/index.html The entire build process should be done on a MOM node in an interactive allocation and on a file system accessible by all compute nodes. Request an interactive allocation with qsub: diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 68f75531adf..8be12c36ed9 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -15,16 +15,16 @@ final release. Links to HDF5 documentation can be found on: - https://support.hdfgroup.org/documentation/HDF5 + https://support.hdfgroup.org/releases/hdf5/latest-docs.html The official HDF5 releases can be obtained from: - https://support.hdfgroup.org/downloads/HDF5/ + https://support.hdfgroup.org/downloads/index.html Changes from Release to Release and New Features in the HDF5-1.16.x release series can be found at: - https://support.hdfgroup.org/documentation/HDF5/release_specific_info.html + https://support.hdfgroup.org/releases/hdf5/documentation/release_specific_info.html If you have any questions or comments, please send them to the HDF Help Desk: diff --git a/release_docs/RELEASE_PROCESS.md b/release_docs/RELEASE_PROCESS.md index b3d6f651bc8..900068022fa 100644 --- a/release_docs/RELEASE_PROCESS.md +++ b/release_docs/RELEASE_PROCESS.md @@ -95,7 +95,7 @@ For more information on the HDF5 versioning and backward and forward compatibili - `$ git push` 7. Update default configuration mode - `$ git checkout hdf5_X_Y_Z;` and `$ bin/switch_maint_mode -disable ./configure.ac` to disable `AM_MAINTAINER_MODE`. - - Need to set option `HDF5_GENERATE_HEADERS` to `OFF`, currently in line 996 of [src/CMakeLists.txt][11]. + - Need to set option `HDF5_GENERATE_HEADERS` to `OFF`, currently in line 996 of [src/CMakeLists.txt][u11]. - Change the **release preparation branch**'s (i.e. hdf5_X_Y_Z) default configuration mode from development to production in [configure.ac][u12]. - Find “Determine build mode” in [configure.ac][u12]. - Change `default=debug` to `default=production` at the bottom of the `AS_HELP_STRING` for `--enable-build-mode`. @@ -174,6 +174,6 @@ For more information on the HDF5 versioning and backward and forward compatibili [u10]: https://github.com/HDFGroup/hdf5/blob/develop/bin/h5vers [u11]: https://github.com/HDFGroup/hdf5/blob/develop/src/CMakeLists.txt [u12]: https://github.com/HDFGroup/hdf5/blob/develop/configure.ac -[u13]: https://support.hdfgroup.org/documentation/hdf5/v1_14/v1_14_4/api-compat-macros.html +[u13]: https://hdfgroup.github.io/hdf5/develop/api-compat-macros.html [u14]: https://github.com/HDFGroup/hdf5/releases/tag/snapshot-1.14 [u15]: https://github.com/HDFGroup/hdf5/releases/tag/snapshot diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 4d376c2b6be..ff46407a717 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -3708,7 +3708,7 @@ H5_DLL herr_t H5Pget_fclose_degree(hid_t fapl_id, H5F_close_degree_t *degree); * \see H5LTopen_file_image(), H5Fget_file_image(), H5Pset_file_image(), * H5Pset_file_image_callbacks(), H5Pget_file_image_callbacks(), * \ref H5FD_file_image_callbacks_t, \ref H5FD_file_image_op_t, - * + * * HDF5 File Image Operations. * * @@ -3748,7 +3748,7 @@ H5_DLL herr_t H5Pget_file_image(hid_t fapl_id, void **buf_ptr_ptr, size_t *buf_l * \see H5LTopen_file_image(), H5Fget_file_image(), H5Pset_file_image(), * H5Pset_file_image_callbacks(), H5Pget_file_image_callbacks(), * \ref H5FD_file_image_callbacks_t, \ref H5FD_file_image_op_t, - * + * * HDF5 File Image Operations. * * \since 1.8.9 @@ -4692,7 +4692,7 @@ H5_DLL herr_t H5Pset_fclose_degree(hid_t fapl_id, H5F_close_degree_t degree); * This function is part of the file image * operations feature set. It is highly recommended to study the guide * [HDF5 File Image Operations] - * (https://\DOCURL/advanced_topics/file_image_ops.html + * (https://\DOCURL/advanced_topics/file_image_ops.md * ) before using this feature set. See the “See Also” section below * for links to other elements of HDF5 file image operations. * @@ -4704,9 +4704,9 @@ H5_DLL herr_t H5Pset_fclose_degree(hid_t fapl_id, H5F_close_degree_t degree); * \li H5Pget_file_image_callbacks() * * \li [HDF5 File Image Operations] - * (https://\DOCURL/advanced_topics/file_image_ops.html) + * (https://\DOCURL/advanced_topics/file_image_ops.md) * in [Advanced Topics in HDF5] - * (https://\DOCURL/advanced_topics_list.html) + * (https://\DOCURL/advanced_topics_list.md) * * \li Within H5Pset_file_image_callbacks(): * \li Callback #H5FD_file_image_callbacks_t @@ -4729,7 +4729,7 @@ H5_DLL herr_t H5Pset_file_image(hid_t fapl_id, void *buf_ptr, size_t buf_len); * **Recommended Reading:** This function is part of the file * image operations feature set. It is highly recommended to study * the guide [HDF5 File Image Operations] - * (https://\DOCURL/advanced_topics/file_image_ops.html + * (https://\DOCURL/advanced_topics/file_image_ops.md * ) before using this feature set. See the “See Also” section below * for links to other elements of HDF5 file image operations. * @@ -5205,7 +5205,7 @@ H5_DLL herr_t H5Pset_mdc_config(hid_t plist_id, H5AC_cache_config_t *config_ptr) * current state of the logging flags. * * The log format is described in [Metadata Cache Logging] - * (https://\DOCURL/advanced_topics/Fine-tuning+the+Metadata+Cache). + * (https://\DOCURL/advanced_topics/FineTuningMetadataCache.md). * * \since 1.10.0 * diff --git a/src/H5VLmodule.h b/src/H5VLmodule.h index 4e998a1783c..535027325fe 100644 --- a/src/H5VLmodule.h +++ b/src/H5VLmodule.h @@ -83,7 +83,7 @@ * to be much more common than internal implementations. * * A list of VOL connectors can be found here: - * + * * Registered VOL Connectors * * This list is incomplete and only includes the VOL connectors that have been registered with diff --git a/src/H5module.h b/src/H5module.h index 083f40005c7..a0f1af77363 100644 --- a/src/H5module.h +++ b/src/H5module.h @@ -782,7 +782,7 @@ * item must be closed separately. * * For more information, - * @see Using Identifiers + * @see Using Identifiers * in the HDF5 Application Developer's Guide under General Topics in HDF5. * *

    How Closing a File Effects Other Open Structural Elements

    diff --git a/tools/src/h5dump/h5dump.c b/tools/src/h5dump/h5dump.c index bb916d9fb1f..6f37c1bc2be 100644 --- a/tools/src/h5dump/h5dump.c +++ b/tools/src/h5dump/h5dump.c @@ -333,10 +333,9 @@ usage(const char *prog) PRINTVALSTREAM( rawoutstream, " D - is the file driver to use in opening the file. Acceptable values are available from\n"); - PRINTVALSTREAM( - rawoutstream, - " " - "https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html.\n"); + PRINTVALSTREAM(rawoutstream, " " + "https://support.hdfgroup.org/releases/hdf5/documentation/" + "registered_virtual_file_drivers_vfds.md.\n"); PRINTVALSTREAM(rawoutstream, " Without the file driver flag, the file will be opened with each driver in\n"); PRINTVALSTREAM(rawoutstream, " turn and in the order specified above until one driver succeeds\n"); diff --git a/tools/src/h5dump/h5dump.h b/tools/src/h5dump/h5dump.h index 879206dfa62..f50950b5548 100644 --- a/tools/src/h5dump/h5dump.h +++ b/tools/src/h5dump/h5dump.h @@ -135,9 +135,9 @@ * * \subsubsection subsubsec_cltools_h5dump_options_args Option Argument Conventions * \li D - is the file driver to use in opening the file. Acceptable values are available - * from https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. Without - * the file driver flag, the file will be opened with each driver in turn and in the order specified above - * until one driver succeeds in opening the file. See examples below for family, split, and multi driver + * from https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. + * Without the file driver flag, the file will be opened with each driver in turn and in the order specified + * above until one driver succeeds in opening the file. See examples below for family, split, and multi driver * special file name usage. * * \li F - is a filename. diff --git a/tools/test/h5dump/expected/h5dump-help.txt b/tools/test/h5dump/expected/h5dump-help.txt index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/h5dump-help.txt +++ b/tools/test/h5dump/expected/h5dump-help.txt @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl b/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl +++ b/tools/test/h5dump/expected/pbits/tnofilename-with-packed-bits.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl b/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsIncomplete.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl b/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsLengthExceeded.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl b/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsLengthPositive.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl b/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsMaxExceeded.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl b/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsOffsetExceeded.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. diff --git a/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl b/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl index 694bc6ae975..2f17b51da95 100644 --- a/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl +++ b/tools/test/h5dump/expected/pbits/tpbitsOffsetNegative.ddl @@ -105,7 +105,7 @@ usage: h5dump [OPTIONS] files --------------- Option Argument Conventions --------------- D - is the file driver to use in opening the file. Acceptable values are available from - https://support.hdfgroup.org/documentation/HDF5/registered_virtual_file_drivers_vfds.html. + https://support.hdfgroup.org/releases/hdf5/documentation/registered_virtual_file_drivers_vfds.md. Without the file driver flag, the file will be opened with each driver in turn and in the order specified above until one driver succeeds in opening the file. From 63138140fe3f189a811240431b5b7588f6ef18df Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:13:35 -0500 Subject: [PATCH 82/94] Add release note for signed binaries (#4826) --- release_docs/RELEASE.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 8be12c36ed9..493133dab8f 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -47,6 +47,12 @@ New Features Configuration: ------------- + - Added signed Windows msi binary and signed Apple dmg binary files. + + The release process now provides signed Windows and Apple installation + binaries in addition to the debian and rpm installation binaries. Also + these installer files are no longer compressed into packaged archives. + - Added configuration option for internal threading/concurrency support: CMake: HDF5_ENABLE_THREADS (ON/OFF) (Default: ON) From 1e9a8ef0e83f595be348a44d59d4cffc69b3fa9f Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:14:48 -0500 Subject: [PATCH 83/94] Cleanup errors detected during merge compare (#4827) --- .github/workflows/cmake-ctest.yml | 2 +- config/cmake/CPack.Info.plist.in | 2 +- config/cmake/FindHDFS.cmake | 2 +- release_docs/RELEASE.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 3231f02d742..f594b1388cb 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -273,7 +273,7 @@ jobs: id: publish-ctest-deb-binary run: | mkdir "${{ runner.workspace }}/builddeb" - cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/*.deb ${{ runner.workspace }}/builddeb/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb + cp ${{ runner.workspace }}/hdf5/build114/${{ inputs.preset_name }}-GNUC/*.deb ${{ runner.workspace }}/builddeb/hdf5 shell: bash - name: Publish rpm binary (Linux) diff --git a/config/cmake/CPack.Info.plist.in b/config/cmake/CPack.Info.plist.in index a518f559cc9..f6e316e105b 100644 --- a/config/cmake/CPack.Info.plist.in +++ b/config/cmake/CPack.Info.plist.in @@ -18,7 +18,7 @@ ???? LSApplicationCategoryType - public.app-category.utilities + public.app-category.developer-tools CFBundleVersion @CPACK_PACKAGE_VERSION@ CFBundleShortVersionString diff --git a/config/cmake/FindHDFS.cmake b/config/cmake/FindHDFS.cmake index 61990cf6b7d..74de99a422d 100644 --- a/config/cmake/FindHDFS.cmake +++ b/config/cmake/FindHDFS.cmake @@ -8,7 +8,7 @@ # HDFS_FOUND, whether HDFS is found. execute_process(COMMAND $ENV{HADOOP_HOME}/bin/hadoop version OUTPUT_VARIABLE Hadoop_VERSION - RESULT_VARIABLE_VALUE Hadoop_RETURN) + RESULT_VARIABLE Hadoop_RETURN) # currently only looking in HADOOP_HOME find_path(HDFS_INCLUDE_DIR hdfs.h PATHS diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 493133dab8f..ac7a09ffb7a 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -24,7 +24,7 @@ The official HDF5 releases can be obtained from: Changes from Release to Release and New Features in the HDF5-1.16.x release series can be found at: - https://support.hdfgroup.org/releases/hdf5/documentation/release_specific_info.html + https://support.hdfgroup.org/releases/hdf5/documentation/release_specific_info.md If you have any questions or comments, please send them to the HDF Help Desk: From 19d3691571d087e9849f9502e4773d93105fda33 Mon Sep 17 00:00:00 2001 From: Larry Knox Date: Fri, 13 Sep 2024 11:49:17 -0500 Subject: [PATCH 84/94] Draw attention to 3rd step in process to update so numbers for release. (#4825) --- config/lt_vers.am | 9 +++++---- release_docs/RELEASE_PROCESS.md | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/config/lt_vers.am b/config/lt_vers.am index fade5bf1594..7ef44760918 100644 --- a/config/lt_vers.am +++ b/config/lt_vers.am @@ -19,17 +19,18 @@ LT_VERS_INTERFACE = 1000 LT_VERS_AGE = 0 LT_VERS_REVISION = 0 -## If the API changes *at all*, increment LT_VERS_INTERFACE and +## 1. If the API changes *at all*, increment LT_VERS_INTERFACE and ## reset LT_VERS_REVISION to 0. ## -## If the API changes but no function signatures are removed or +## 2. If the API changes but no function signatures are removed or ## changed, also increment LT_VERS_AGE. -## If any functions are removed from the API, or their signatures +## +## 3. If any functions are removed from the API, or their signatures ## are changed reset LT_VERS_AGE to 0 to indicate that previous ## versions of the API are not necessarily compatible with this ## version. ## -## If the source changes but there are no API changes, increment +## 4. If the source changes but there are no API changes, increment ## LT_VERS_REVISION. This will happen automatically when ## bin/h5vers is run, but doing it manually shouldn't hurt ## anything. diff --git a/release_docs/RELEASE_PROCESS.md b/release_docs/RELEASE_PROCESS.md index 900068022fa..2379de3b167 100644 --- a/release_docs/RELEASE_PROCESS.md +++ b/release_docs/RELEASE_PROCESS.md @@ -54,10 +54,11 @@ For more information on the HDF5 versioning and backward and forward compatibili ### 4. Freeze Code (Release Manager | Test Automation Team) 1. Transition from performing maintenance on software to preparing for its delivery. 2. A few days before the code freeze, announce (via a product's developer mailing list and during team meetings) the pending freeze of the code for the release. On the day of the code freeze, send a "no more commits" message for the software being released and any third party software we develop that it depends on, as well as a "no more upgrades" message for other third party software the release depends on. - - Recently we haven’t announced a code freeze since it doesn’t take long to create the release branch and the support branch doesn’t need to remain frozen once the release branch is created. There are a few things that can be done on the support branch before the release branch is created, in particular updating the .so numbers. -3. Move all unresolved Milestone issues to the next release version in GitHub. -4. Verify that frozen code branch satisfies all existing regression test cases, and give the 'OK' to the release coordinator once all daily test configurations are passing as expected after the date of the code freeze. If there are failing tests after the code freeze date, coordinate with maintainers responsible for the failures to ensure that either the changes causing the failures are corrected or reverted. -5. Verify release branches for third-party software used: SZIP, ZLIB, and Plugins; and announce release versions to hdf5lib@lists.hdfgroup.org. + - Recently we haven’t announced a code freeze since it doesn’t take long to create the release branch and the support branch doesn’t need to remain frozen once the release branch is created. There are a few things that can be done on the support branch before the release branch is created, in particular updating the .so numbers. +3. Be sure to complete all four steps to update so numbers for each deployed lib file in the process described in config/lt_vers.am and check that the .so numbers for lib files in binaries correctly indicate compatibility status with the previous release. +4. Move all unresolved Milestone issues to the next release version in GitHub. +5. Verify that frozen code branch satisfies all existing regression test cases, and give the 'OK' to the release coordinator once all daily test configurations are passing as expected after the date of the code freeze. If there are failing tests after the code freeze date, coordinate with maintainers responsible for the failures to ensure that either the changes causing the failures are corrected or reverted. +6. Verify release branches for third-party software used: SZIP, ZLIB, and Plugins; and announce release versions to hdf5lib@hdfgroup.org. ### 5. Update Interface Version (Release Manager | Product Manager) 1. Verify interface additions, changes, and removals, and update the shared library interface version number. From e2154c92e543517e48684e93a4e12b90bc150877 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:01:26 -0500 Subject: [PATCH 85/94] correct path for deb binary (#4835) --- .github/workflows/cmake-ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index f594b1388cb..b927b3ce403 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -273,7 +273,7 @@ jobs: id: publish-ctest-deb-binary run: | mkdir "${{ runner.workspace }}/builddeb" - cp ${{ runner.workspace }}/hdf5/build114/${{ inputs.preset_name }}-GNUC/*.deb ${{ runner.workspace }}/builddeb/hdf5 + cp ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-GNUC/*.deb ${{ runner.workspace }}/builddeb/${{ steps.set-file-base.outputs.FILE_BASE }}-ubuntu-2204_gcc.deb shell: bash - name: Publish rpm binary (Linux) From 405d1b91d98bc2105ce87cfbaaab19d2df7456a2 Mon Sep 17 00:00:00 2001 From: Larry Knox Date: Mon, 16 Sep 2024 12:53:33 -0500 Subject: [PATCH 86/94] Update h5fc.in missed line for libhdf5hl_fortran filename change to libhdf5_hl_fortran. (#4831) * Change name of libhdf5hl_fortran installed by autotools to libhdf5_hl_fortran to be consistent with CMake install and with other hl lib files. Switched corresponding symlink to libhdf5hl_fortran. Fixes issue #4684. * Update h5fc.in to use renamed libhdf5_hl_fortran. Fix typo in code to create link to libhdf5_hl_fortran.a. * Removed code to create symlink for previous name of renamed lib libhdf5hl_fortran. Add RELEASE.txt entry about changeing name libhdf5hl_fortran to libhdf5_hl_fortran. * Update missed line in h5fc.in for libhdf5hl_fortran name change to libhdf5_hl_fortran. Fixes check-install failure. --- fortran/src/h5fc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fortran/src/h5fc.in b/fortran/src/h5fc.in index 51440781459..e0e35f5a1b8 100644 --- a/fortran/src/h5fc.in +++ b/fortran/src/h5fc.in @@ -330,8 +330,8 @@ if test "x$do_link" = "xyes"; then -lhdf5_fortran) new_libraries="$new_libraries ${libdir}/libhdf5_fortran.a" ;; - -lhdf5hl_fortran) - new_libraries="$new_libraries ${libdir}/libhdf5hl_fortran.a" + -lhdf5_hl_fortran) + new_libraries="$new_libraries ${libdir}/libhdf5_hl_fortran.a" ;; *) new_libraries="$new_libraries $lib" From ca217e2c71fd2a260eaa75227b00a754facd73ec Mon Sep 17 00:00:00 2001 From: mattjala <124107509+mattjala@users.noreply.github.com> Date: Tue, 17 Sep 2024 11:06:03 -0500 Subject: [PATCH 87/94] Document usage for H5TSmutex_release/acquire() (#4836) --- src/H5TS.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/H5TS.c b/src/H5TS.c index 590e20b70ff..05d700c4652 100644 --- a/src/H5TS.c +++ b/src/H5TS.c @@ -67,10 +67,12 @@ H5TS_api_info_t H5TS_api_info_p; /*-------------------------------------------------------------------------- * Function: H5TSmutex_acquire * - * Purpose: Attempts to acquire the HDF5 library global lock + * Purpose: Attempts to acquire the HDF5 library global lock. Should be preceded by a call to + * H5TSmutex_release(). * - * Note: On success, the 'acquired' flag indicates if the HDF5 library - * global lock was acquired. + * Parameters: + * lock_count; IN: The lock count that was held on the mutex before its release + * acquired; OUT: Whether the HDF5 library global lock was acquired * * Return: Non-negative on success / Negative on failure * @@ -118,10 +120,17 @@ H5TSmutex_get_attempt_count(unsigned *count) /*-------------------------------------------------------------------------- * Function: H5TSmutex_release * - * Purpose: Releases the HDF5 library global lock + * Purpose: Releases the HDF5 library global lock. Should be followed by a call to H5TSmutex_acquire(). * - * Return: Non-negative on success / Negative on failure + * This should be used by applications to temporarily release the lock in order to either perform + * multi-threaded work of their own or yield control to another thread using HDF5. The value + * returned in lock_count should be provided to H5TSmutex_acquire() in order to resume a + * consistent library state. + * + * Parameters: + * lock_count; OUT: The current lock count for the calling thread. * + * Return: Non-negative on success / Negative on failure *-------------------------------------------------------------------------- */ herr_t From eeb94a8d5adcb0bd96ad2b408feeeeb8fbe64472 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Tue, 17 Sep 2024 12:21:54 -0500 Subject: [PATCH 88/94] Print error stream when cmake greptest fails to match error ref. (#4841) --- config/cmake/grepTest.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/cmake/grepTest.cmake b/config/cmake/grepTest.cmake index 529649e4e7c..44aa1975510 100644 --- a/config/cmake/grepTest.cmake +++ b/config/cmake/grepTest.cmake @@ -116,7 +116,7 @@ if (TEST_ERRREF) RESULT_VARIABLE TEST_ERRREF_RESULT ) endif () - message (FATAL_ERROR "Failed: The error output of ${TEST_PROGRAM} did not contain ${TEST_ERRREF}") + message (FATAL_ERROR "Failed: The error output of ${TEST_PROGRAM} did not contain '${TEST_ERRREF}'. Error output was: '${TEST_ERR_STREAM}'") endif () endif () endif () From 3b65223c21a161378813fa5d1368e62f3c094ba9 Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Tue, 17 Sep 2024 15:54:24 -0500 Subject: [PATCH 89/94] Fix issues with large external data files (#4843) --- src/H5Defl.c | 73 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/src/H5Defl.c b/src/H5Defl.c index 22348e33fcc..34d48e690b7 100644 --- a/src/H5Defl.c +++ b/src/H5Defl.c @@ -278,12 +278,12 @@ H5D__efl_read(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size { int fd = -1; size_t to_read; + size_t left_to_read; #ifndef NDEBUG hsize_t tempto_read; #endif /* NDEBUG */ hsize_t skip = 0; haddr_t cur; - ssize_t n; size_t u; /* Local index variable */ char *full_name = NULL; /* File name with prefix */ herr_t ret_value = SUCCEED; /* Return value */ @@ -325,15 +325,43 @@ H5D__efl_read(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t size #else /* NDEBUG */ to_read = MIN((size_t)(efl->slot[u].size - skip), (hsize_t)size); #endif /* NDEBUG */ - if ((n = HDread(fd, buf, to_read)) < 0) - HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "read error in external raw data file"); - else if ((size_t)n < to_read) - memset(buf + n, 0, to_read - (size_t)n); + + /* Inner loop - read to_read bytes from a single external file */ + left_to_read = to_read; + while (left_to_read > 0) { + h5_posix_io_t bytes_in = 0; /* # of bytes to read */ + h5_posix_io_ret_t bytes_read = -1; /* # of bytes actually read */ + + /* Trying to read more bytes than the return type can handle is + * undefined behavior in POSIX. + */ + if (left_to_read > H5_POSIX_MAX_IO_BYTES) + bytes_in = H5_POSIX_MAX_IO_BYTES; + else + bytes_in = (h5_posix_io_t)left_to_read; + + do { + bytes_read = HDread(fd, buf, bytes_in); + } while (-1 == bytes_read && EINTR == errno); + + if (bytes_read < 0) + HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "read error in external raw data file"); + + if (0 == bytes_read) { + /* End of file on disk, fill the remaining sectors to be read from this file with 0 */ + memset(buf, 0, left_to_read); + bytes_read = (h5_posix_io_ret_t)left_to_read; + } /* end if */ + + left_to_read -= (size_t)bytes_read; + buf += bytes_read; + } + + /* Prepare to advance to next external file */ full_name = (char *)H5MM_xfree(full_name); HDclose(fd); fd = -1; size -= to_read; - buf += to_read; skip = 0; u++; } /* end while */ @@ -364,6 +392,7 @@ H5D__efl_write(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t siz { int fd = -1; size_t to_write; + size_t left_to_write; #ifndef NDEBUG hsize_t tempto_write; #endif /* NDEBUG */ @@ -414,13 +443,39 @@ H5D__efl_write(const H5O_efl_t *efl, const H5D_t *dset, haddr_t addr, size_t siz #else /* NDEBUG */ to_write = MIN((size_t)(efl->slot[u].size - skip), size); #endif /* NDEBUG */ - if ((size_t)HDwrite(fd, buf, to_write) != to_write) - HGOTO_ERROR(H5E_EFL, H5E_READERROR, FAIL, "write error in external raw data file"); + + /* Inner loop - write to_write bytes to a single external file */ + left_to_write = to_write; + while (left_to_write > 0) { + h5_posix_io_t bytes_in = 0; /* # of bytes to write */ + h5_posix_io_ret_t bytes_wrote = -1; /* # of bytes actually written */ + + /* Trying to write more bytes than the return type can handle is + * undefined behavior in POSIX. + */ + if (left_to_write > H5_POSIX_MAX_IO_BYTES) + bytes_in = H5_POSIX_MAX_IO_BYTES; + else + bytes_in = (h5_posix_io_t)left_to_write; + + do { + bytes_wrote = HDwrite(fd, buf, bytes_in); + } while (-1 == bytes_wrote && EINTR == errno); + + if (bytes_wrote < 0) + HGOTO_ERROR(H5E_EFL, H5E_WRITEERROR, FAIL, "write error in external raw data file"); + if (bytes_wrote == 0) + HGOTO_ERROR(H5E_EFL, H5E_WRITEERROR, FAIL, "wrote 0 bytes to external raw data file"); + + left_to_write -= (size_t)bytes_wrote; + buf += bytes_wrote; + } + + /* Prepare to advance to next external file */ full_name = (char *)H5MM_xfree(full_name); HDclose(fd); fd = -1; size -= to_write; - buf += to_write; skip = 0; u++; } /* end while */ From d1cfe5295b1e8305f774b0a416078c5f674f0147 Mon Sep 17 00:00:00 2001 From: mattjala <124107509+mattjala@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:35:45 -0500 Subject: [PATCH 90/94] Fix memory leaks in ttsafe tests (#4842) --- test/ttsafe_acreate.c | 30 ++++++++++++++++++++++-------- test/ttsafe_attr_vlen.c | 12 ++++++++++++ test/ttsafe_cancel.c | 36 +++++++++++++++++++----------------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/test/ttsafe_acreate.c b/test/ttsafe_acreate.c index b3a83e5690c..6ee12d03987 100644 --- a/test/ttsafe_acreate.c +++ b/test/ttsafe_acreate.c @@ -63,7 +63,11 @@ tts_acreate(void) int buffer, i; herr_t status; - ttsafe_name_data_t *attrib_data; + ttsafe_name_data_t *attrib_data[NUM_THREADS]; + + char *attribute_name = NULL; + + memset(attrib_data, 0, sizeof(attrib_data)); /* * Create an HDF5 file using H5F_ACC_TRUNC access, default file @@ -97,12 +101,12 @@ tts_acreate(void) * with the dataset */ for (i = 0; i < NUM_THREADS; i++) { - attrib_data = (ttsafe_name_data_t *)malloc(sizeof(ttsafe_name_data_t)); - attrib_data->dataset = dataset; - attrib_data->datatype = datatype; - attrib_data->dataspace = dataspace; - attrib_data->current_index = i; - if (H5TS_thread_create(&threads[i], tts_acreate_thread, attrib_data) < 0) + attrib_data[i] = (ttsafe_name_data_t *)malloc(sizeof(ttsafe_name_data_t)); + attrib_data[i]->dataset = dataset; + attrib_data[i]->datatype = datatype; + attrib_data[i]->dataspace = dataspace; + attrib_data[i]->current_index = i; + if (H5TS_thread_create(&threads[i], tts_acreate_thread, attrib_data[i]) < 0) TestErrPrintf("thread # %d did not start", i); } @@ -112,7 +116,9 @@ tts_acreate(void) /* verify the correctness of the test */ for (i = 0; i < NUM_THREADS; i++) { - attribute = H5Aopen(dataset, gen_name(i), H5P_DEFAULT); + attribute_name = gen_name(i); + + attribute = H5Aopen(dataset, attribute_name, H5P_DEFAULT); CHECK(attribute, H5I_INVALID_HID, "H5Aopen"); if (attribute < 0) @@ -125,6 +131,8 @@ tts_acreate(void) status = H5Aclose(attribute); CHECK(status, FAIL, "H5Aclose"); } + + free(attribute_name); } /* close remaining resources */ @@ -136,6 +144,10 @@ tts_acreate(void) CHECK(status, FAIL, "H5Dclose"); status = H5Fclose(file); CHECK(status, FAIL, "H5Fclose"); + + for (i = 0; i < NUM_THREADS; i++) + if (attrib_data[i]) + free(attrib_data[i]); } /* end tts_acreate() */ H5TS_THREAD_RETURN_TYPE @@ -164,6 +176,8 @@ tts_acreate_thread(void *client_data) status = H5Aclose(attribute); CHECK(status, FAIL, "H5Aclose"); + free(attribute_data); + free(attribute_name); return (H5TS_thread_ret_t)0; } /* end tts_acreate_thread() */ diff --git a/test/ttsafe_attr_vlen.c b/test/ttsafe_attr_vlen.c index 913ad0011a9..10ce4c63d78 100644 --- a/test/ttsafe_attr_vlen.c +++ b/test/ttsafe_attr_vlen.c @@ -123,6 +123,7 @@ tts_attr_vlen_thread(void H5_ATTR_UNUSED *client_data) hid_t fid = H5I_INVALID_HID; /* File ID */ hid_t gid = H5I_INVALID_HID; /* Group ID */ hid_t aid = H5I_INVALID_HID; /* Attribute ID */ + hid_t asid = H5I_INVALID_HID; /* Dataspace ID for the attribute */ hid_t atid = H5I_INVALID_HID; /* Datatype ID for the attribute */ char *string_attr_check; /* The attribute data being read */ const char *string_attr = "2.0"; /* The expected attribute data */ @@ -144,6 +145,10 @@ tts_attr_vlen_thread(void H5_ATTR_UNUSED *client_data) atid = H5Aget_type(aid); CHECK(atid, H5I_INVALID_HID, "H5Aget_type"); + /* Get the dataspace for the attribute */ + asid = H5Aget_space(aid); + CHECK(asid, H5I_INVALID_HID, "H5Aget_space"); + /* Read the attribute */ ret = H5Aread(aid, atid, &string_attr_check); CHECK(ret, FAIL, "H5Aclose"); @@ -151,10 +156,17 @@ tts_attr_vlen_thread(void H5_ATTR_UNUSED *client_data) /* Verify the attribute data is as expected */ VERIFY_STR(string_attr_check, string_attr, "H5Aread"); + /* Free the attribute data */ + ret = H5Dvlen_reclaim(atid, asid, H5P_DEFAULT, &string_attr_check); + CHECK(ret, FAIL, "H5Dvlen_reclaim"); + /* Close IDs */ ret = H5Aclose(aid); CHECK(ret, FAIL, "H5Aclose"); + ret = H5Sclose(asid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Gclose(gid); CHECK(ret, FAIL, "H5Aclose"); diff --git a/test/ttsafe_cancel.c b/test/ttsafe_cancel.c index f2bb4c517a1..7aaf5aaaa6b 100644 --- a/test/ttsafe_cancel.c +++ b/test/ttsafe_cancel.c @@ -47,6 +47,10 @@ typedef struct cleanup_struct { hid_t dataspace; } cancel_cleanup_t; +/* Used by tts_cancel_thread. + * Global because the thread gets cancelled and can't clean up its allocations */ +cancel_cleanup_t cleanup_structure = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID}; + pthread_t childthread; static H5TS_barrier_t barrier; @@ -94,14 +98,13 @@ tts_cancel(void) void * tts_cancel_thread(void H5_ATTR_UNUSED *arg) { - hid_t dataspace = H5I_INVALID_HID; - hid_t datatype = H5I_INVALID_HID; - hid_t dataset = H5I_INVALID_HID; - int datavalue; - int buffer; - hsize_t dimsf[1]; /* dataset dimensions */ - cancel_cleanup_t *cleanup_structure; - herr_t status; + hid_t dataspace = H5I_INVALID_HID; + hid_t datatype = H5I_INVALID_HID; + hid_t dataset = H5I_INVALID_HID; + int datavalue; + int buffer; + hsize_t dimsf[1]; /* dataset dimensions */ + herr_t status; /* define dataspace for dataset */ dimsf[0] = 1; @@ -120,11 +123,10 @@ tts_cancel_thread(void H5_ATTR_UNUSED *arg) CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); /* If thread is cancelled, make cleanup call */ - cleanup_structure = (cancel_cleanup_t *)malloc(sizeof(cancel_cleanup_t)); - cleanup_structure->dataset = dataset; - cleanup_structure->datatype = datatype; - cleanup_structure->dataspace = dataspace; - pthread_cleanup_push(cancellation_cleanup, cleanup_structure); + cleanup_structure.dataset = dataset; + cleanup_structure.datatype = datatype; + cleanup_structure.dataspace = dataspace; + pthread_cleanup_push(cancellation_cleanup, &cleanup_structure); datavalue = 1; status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &datavalue); @@ -189,14 +191,14 @@ tts_cancel_callback(void *elem, hid_t H5_ATTR_UNUSED type_id, unsigned H5_ATTR_U void cancellation_cleanup(void *arg) { - cancel_cleanup_t *cleanup_structure = (cancel_cleanup_t *)arg; + cancel_cleanup_t *_cleanup_structure = (cancel_cleanup_t *)arg; herr_t status; - status = H5Dclose(cleanup_structure->dataset); + status = H5Dclose(_cleanup_structure->dataset); CHECK(status, FAIL, "H5Dclose"); - status = H5Tclose(cleanup_structure->datatype); + status = H5Tclose(_cleanup_structure->datatype); CHECK(status, FAIL, "H5Tclose"); - status = H5Sclose(cleanup_structure->dataspace); + status = H5Sclose(_cleanup_structure->dataspace); CHECK(status, FAIL, "H5Sclose"); } /* end cancellation_cleanup() */ From 52d42fdb935d7db3447e79841c8c19d19db51f75 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Thu, 19 Sep 2024 03:46:29 -0500 Subject: [PATCH 91/94] Reduce test iterations, etc. to keep time down on sower systems (#4853) Signed-off-by: Quincey Koziol --- test/ttsafe_rwlock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ttsafe_rwlock.c b/test/ttsafe_rwlock.c index e160788816e..d6fcad38bd1 100644 --- a/test/ttsafe_rwlock.c +++ b/test/ttsafe_rwlock.c @@ -23,8 +23,8 @@ #define NUM_THREADS 16 #define NUM_WRITERS 4 -#define NUM_ITERS 32 -#define COUNT_MAX 1024 +#define NUM_ITERS 12 +#define COUNT_MAX 512 typedef struct { H5TS_rwlock_t lock; From 3307ff154dfa1a98047b935ef16381508c66813d Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Thu, 19 Sep 2024 03:47:18 -0500 Subject: [PATCH 92/94] Add windows extra options (#4854) --- config/cmake/examples/HDF5_Examples.cmake.in | 8 ++++++++ release_docs/USING_CMake_Examples.txt | 11 ++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/config/cmake/examples/HDF5_Examples.cmake.in b/config/cmake/examples/HDF5_Examples.cmake.in index d5a6051d346..962bfea147a 100644 --- a/config/cmake/examples/HDF5_Examples.cmake.in +++ b/config/cmake/examples/HDF5_Examples.cmake.in @@ -42,6 +42,14 @@ if(DEFINED CTEST_SCRIPT_ARG) endforeach() endif() +if(${CTEST_VSVERS} STREQUAL "64_VS2022") # 64-bit Visual Studio 2022 + set(CTEST_CMAKE_GENERATOR "Visual Studio 17 2022") + set(CMAKE_GENERATOR_ARCHITECTURE "x64") +elseif(${VS_VERS} STREQUAL "64_VS2019") # 64-bit Visual Studio 2019 + set(CTEST_CMAKE_GENERATOR "Visual Studio 16 2019") + set(CMAKE_GENERATOR_ARCHITECTURE "x64") +endif() + ################################################################### ### Following Line is one of [Release, RelWithDebInfo, Debug] ##### set(CTEST_CONFIGURATION_TYPE "$ENV{CMAKE_CONFIG_TYPE}") diff --git a/release_docs/USING_CMake_Examples.txt b/release_docs/USING_CMake_Examples.txt index 276cc03de00..31bb4dc92c4 100644 --- a/release_docs/USING_CMake_Examples.txt +++ b/release_docs/USING_CMake_Examples.txt @@ -56,6 +56,11 @@ Default installation process: The default ctest configuration is defined as "Release". It can be changed with the CTEST_CONFIGURATION_TYPE script option. Note that this must be the same as the value used with the -C command line option. + On Windows, you can set the CTEST_VSVERS script option to either + 64_VS2022 or 64_VS2019. Alternately, you can set the script + CTEST_CMAKE_GENERATOR option to "Visual Studio 16 2019" or "Visual Studio 17 2022", + and the CMAKE_GENERATOR_ARCHITECTURE script option to "x64". + The default build configuration is defined to build and use static libraries. Shared libraries and other options can be changed by editing the @@ -69,15 +74,15 @@ Default installation process: When executed, the ctest script will save the results to the log file, test.log, as indicated by the ctest command. If you wish to see more build and test information, add "-VV" to the ctest command. The output should show; - 100% tests passed, 0 tests failed out of 156. + 100% tests passed, 0 tests failed out of 206. ======================================================================== III. Defaults in the HDF5_Examples_options.cmake file ======================================================================== -#### DEFAULT: ### -#### BUILD_SHARED_LIBS:BOOL=OFF ### +#### DEFAULT: ### +#### BUILD_SHARED_LIBS:BOOL=OFF ### #### H5EX_BUILD_C:BOOL=ON ### #### H5EX_BUILD_CXX:BOOL=OFF ### #### H5EX_BUILD_FORTRAN:BOOL=OFF ### From b382a8ef85acaedb63d05fc29305ac24d9b1805a Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Thu, 19 Sep 2024 14:02:18 -0500 Subject: [PATCH 93/94] RELEASE.txt entry for PR #4843 (#4860) --- release_docs/RELEASE.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index ac7a09ffb7a..8d5615fcc11 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -829,6 +829,19 @@ Bug Fixes since HDF5-1.14.0 release =================================== Library ------- + - Fixed a bug with large external datasets + + When performing a large I/O on an external dataset, the library would only + issue a single read or write system call. This could cause errors or cause + the data to be incorrect. These calls do not guarantee that they will + process the entire I/O request, and may need to be called multiple times + to complete the I/O, advancing the buffer and reducing the size by the + amount actually processed by read or write each time. Implemented this + algorithm for external datasets in both the read and write cases. + + Fixes GitHub #4216 + Fixes h5py GitHub #2394 + - Fixed a bug in the Subfiling VFD that could cause a buffer over-read and memory allocation failures From 417ae79f2c4718ccfbd1cc96974c939843234186 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:19:01 -0500 Subject: [PATCH 94/94] Add binary testing steps (#4851) --- release_docs/RELEASE_PROCESS.md | 41 +++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/release_docs/RELEASE_PROCESS.md b/release_docs/RELEASE_PROCESS.md index 2379de3b167..c3e106d267a 100644 --- a/release_docs/RELEASE_PROCESS.md +++ b/release_docs/RELEASE_PROCESS.md @@ -122,12 +122,43 @@ For more information on the HDF5 versioning and backward and forward compatibili 12. Once binaries are ready to be tested, send an e-mail notification or update the Confluence test dashboard page indicating source and binary test assignments and when results should be made available. 13. Use the pre-release source packages to build and test HDF5 on assigned platforms by hand. Build both shared and static libraries, Fortran, C++, and szip, and any additional configurations required on specific remote platforms based on customer support needs. 14. Use the pre-release binary packages found in /mnt/scr1/pre-release/hdf5/vXYZ/pre-\/binaries/{UNIX, Windows} to test according to the binary testing procedures for your assigned platforms. -15. Scripted Testing: - - UNIX: [Scripted Binary Testing of HDF5 on UNIX systems (this is missing)]() - - Windows: [Testing HDF5 Binaries(this is missing)]() +15. Initial Testing: + - Installation Using Installer Binary + - Execute the install package + - Follow prompts + - Uncompress Directory Image Binary + - Extract the package + - After Installation + - The examples folder, HDF5Examples, located in the HDF5 install folder, can be built and tested with CMake and the supplied + HDF5_Examples.cmake file. The HDF5_Examples.cmake expects HDF5 to have been installed in the default location with same compilers (see the + libhdf5.settings file in the lib install folder). Also, the CMake utility should be installed. + + - To test the installation with the examples; + - Create a directory to run the examples. + - Copy HDF5Examples folder to this directory. + - Copy CTestScript.cmake to this directory. + - Copy HDF5_Examples.cmake to this directory. + - Copy HDF5_Examples_options.cmake to this directory. + - The default source folder is defined as "HDF5Examples". It can be changed with the CTEST_SOURCE_NAME script option. + - The default installation folder should be visible in the script. It can be changed with the INSTALLDIR script option. + - The default ctest configuration is defined as "Release". It can be changed + with the CTEST_CONFIGURATION_TYPE script option. Note that this must + be the same as the value used with the -C command line option. + - The default build configuration is defined to build and use static libraries. + Shared libraries can be used with the STATICONLYLIBRARIES script option set to "NO". + - Other options can be changed by editing the HDF5_Examples_options.cmake file. + - If the defaults are okay, execute from this directory: + - ctest -S HDF5_Examples.cmake -C Release -V -O test.log + - If the defaults need change, execute from this directory: + - ctest -S HDF5_Examples.cmake,CTEST_SOURCE_NAME=MyExamples,INSTALLDIR=MyLocation -C Release -V -O test.log + - When executed, the ctest script will save the results to the log file, test.log, as + indicated by the ctest command. If you wish to see more build and test information, + add "-VV" to the ctest command. The output should show; + 100% tests passed, 0 tests failed out of 206 (all options). + - For more information see USING_CMake_Examples.txt in the install folder. 16. Manual Testing (i.e. verifying correct test outcomes via visual inspection): - - Use this if UNIX test script is not reporting correct results, yet binaries look OK. - - UNIX: [Manual Binary Testing of HDF5 on Unix systems (this is missing)]() + - Inspect text documents for correct versions and names. + - Inspect the doxygen files in the share/html directory open index.html . 17. Update the test results Confluence page with status/outcome of all test assignments. 18. If any test source (hdf-forum, clients, internal testers, automated regression suite) identifies any issues: - a) Enter the issue in JIRA summarizing the failure if it is not already there.