diff --git a/.github/workflows/abi-report.yml b/.github/workflows/abi-report.yml index 9abbd2fd54c..5faa1f297b2 100644 --- a/.github/workflows/abi-report.yml +++ b/.github/workflows/abi-report.yml @@ -49,7 +49,7 @@ jobs: - uses: actions/checkout@v4.1.7 - name: Get published binary (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-ubuntu-2204_gcc-binary path: ${{ github.workspace }} diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index f0d89558baa..c4d68a8f004 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.13 + uses: DoozyX/clang-format-lint-action@v0.17 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 882e0b64a9f..2ce9f6e9dad 100644 --- a/.github/workflows/clang-format-fix.yml +++ b/.github/workflows/clang-format-fix.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Fix C and Java formatting issues detected by clang-format - uses: DoozyX/clang-format-lint-action@9ea72631b74e61ce337d0839a90e76180e997283 # v0.13 + uses: DoozyX/clang-format-lint-action@d3c7f85989e3b6416265a0d12f8b4a8aa8b0c4ff # v0.13 with: source: '.' extensions: 'c,h,cpp,hpp,java' diff --git a/.github/workflows/cmake-bintest.yml b/.github/workflows/cmake-bintest.yml index bbe0172acbf..104818920b5 100644 --- a/.github/workflows/cmake-bintest.yml +++ b/.github/workflows/cmake-bintest.yml @@ -33,7 +33,7 @@ jobs: # Get files created by cmake-ctest script - name: Get published binary (Windows) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-vs2022_cl-${{ inputs.build_mode }}-binary path: ${{ github.workspace }}/hdf5 @@ -107,7 +107,7 @@ jobs: distribution: 'temurin' - name: Get published binary (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-ubuntu-2204_gcc-${{ inputs.build_mode }}-binary path: ${{ github.workspace }} @@ -147,7 +147,7 @@ jobs: # MacOS w/ Clang + CMake # name: "MacOS Clang Binary Test" - runs-on: macos-latest + runs-on: macos-13 steps: - name: Install Dependencies (MacOS) run: brew install ninja doxygen @@ -159,9 +159,9 @@ jobs: distribution: 'temurin' - name: Get published binary (MacOS) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - name: tgz-osx-${{ inputs.build_mode }}-binary + name: tgz-osx13-${{ inputs.build_mode }}-binary path: ${{ github.workspace }} - name: Uncompress hdf5 binary (MacOS) @@ -204,3 +204,64 @@ jobs: cmake --workflow --preset=ci-StdShar-OSX-Clang --fresh shell: bash + test_binary_mac_latest: + # MacOS w/ Clang + CMake + # + name: "MacOS Clang Binary Test" + runs-on: macos-latest + steps: + - name: Install Dependencies (MacOS_latest) + run: brew install ninja doxygen + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Get published binary (MacOS_latest) + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: tgz-osx-${{ inputs.build_mode }}-binary + path: ${{ github.workspace }} + + - name: Uncompress hdf5 binary (MacOS_latest) + run: | + cd "${{ github.workspace }}" + tar -zxvf ${{ github.workspace }}/HDF5-*-Darwin.tar.gz --strip-components 1 + + - name: set hdf5lib name + id: set-hdf5lib-name + run: | + HDF5DIR=${{ github.workspace }}/HDF_Group/HDF5/ + FILE_NAME_HDF5=$(ls ${{ github.workspace }}/HDF_Group/HDF5) + echo "HDF5_ROOT=$HDF5DIR$FILE_NAME_HDF5" >> $GITHUB_OUTPUT + echo "HDF5_PLUGIN_PATH=$HDF5_ROOT/lib/plugin" >> $GITHUB_OUTPUT + + - name: List files for the binaries (MacOS_latest) + run: | + ls -l ${{ github.workspace }}/HDF_Group/HDF5 + + - name: List files for the space (MacOS_latest) + run: | + ls ${{ github.workspace }} + ls ${{ runner.workspace }} + + # symlinks the compiler executables to a common location + - name: Setup GNU Fortran + uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: gcc + version: 12 + + - name: Run ctest (MacOS_latest) + id: run-ctest + env: + HDF5_ROOT: ${{ steps.set-hdf5lib-name.outputs.HDF5_ROOT }} + 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 + shell: bash + diff --git a/.github/workflows/cmake-ctest.yml b/.github/workflows/cmake-ctest.yml index 70baea28baa..162519831d7 100644 --- a/.github/workflows/cmake-ctest.yml +++ b/.github/workflows/cmake-ctest.yml @@ -60,7 +60,7 @@ jobs: # Get files created by release script - name: Get zip-tarball (Windows) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-tarball path: ${{ github.workspace }} @@ -86,11 +86,15 @@ jobs: cmake --workflow --preset=${{ inputs.preset_name }}-MSVC --fresh shell: bash - - name: Publish binary (Windows) - id: publish-ctest-binary + - name: Create build folders (Windows) run: | mkdir "${{ runner.workspace }}/build" mkdir "${{ runner.workspace }}/build/hdf5" + shell: bash + + - name: Publish binary (Windows) + id: publish-ctest-binary + run: | Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-MSVC/README.md -Destination ${{ runner.workspace }}/build/hdf5/ @@ -102,8 +106,6 @@ jobs: - name: Publish msi binary (Windows) id: publish-ctest-msi-binary run: | - mkdir "${{ runner.workspace }}/build" - mkdir "${{ runner.workspace }}/build/hdf5" Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-MSVC/README.md -Destination ${{ runner.workspace }}/build/hdf5/ @@ -164,7 +166,7 @@ jobs: # Get files created by release script - name: Get tgz-tarball (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-tarball path: ${{ github.workspace }} @@ -273,6 +275,12 @@ jobs: with: version: "1.9.7" + - name: Set up JDK 19 + uses: actions/setup-java@v4 + with: + java-version: '19' + distribution: 'temurin' + - name: Set file base name (MacOS) id: set-file-base run: | @@ -288,7 +296,7 @@ jobs: # Get files created by release script - name: Get tgz-tarball (MacOS) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-tarball path: ${{ github.workspace }} @@ -326,7 +334,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 }}-osx13.tar.gz hdf5 shell: bash - name: List files in the space (MacOS) @@ -336,6 +344,95 @@ jobs: # Save files created by ctest script - name: Save published binary (MacOS) + uses: actions/upload-artifact@v4 + with: + name: tgz-osx13-binary + path: ${{ runner.workspace }}/build/${{ steps.set-file-base.outputs.FILE_BASE }}-osx13.tar.gz + if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn` + + build_and_test_mac_latest: + # MacOS w/ Clang + CMake + # + name: "MacOS Clang CMake" + runs-on: macos-latest + steps: + - name: Install Dependencies (MacOS_latest) + run: brew install ninja + + - name: Install Dependencies + uses: ssciwr/doxygen-install@v1 + with: + version: "1.9.7" + + - name: Set up JDK 19 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Set file base name (MacOS_latest) + id: set-file-base + run: | + FILE_NAME_BASE=$(echo "${{ inputs.file_base }}") + echo "FILE_BASE=$FILE_NAME_BASE" >> $GITHUB_OUTPUT + if [[ '${{ inputs.use_environ }}' == 'release' ]] + then + SOURCE_NAME_BASE=$(echo "${{ inputs.snap_name }}") + else + SOURCE_NAME_BASE=$(echo "hdfsrc") + fi + echo "SOURCE_BASE=$SOURCE_NAME_BASE" >> $GITHUB_OUTPUT + + # Get files created by release script + - name: Get tgz-tarball (MacOS_latest) + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: tgz-tarball + path: ${{ github.workspace }} + + - name: List files for the space (MacOS_latest) + run: | + ls ${{ github.workspace }} + ls ${{ runner.workspace }} + + - name: Uncompress source (MacOS_latest) + run: tar -zxvf ${{ github.workspace }}/${{ steps.set-file-base.outputs.FILE_BASE }}.tar.gz + + # symlinks the compiler executables to a common location + - name: Setup GNU Fortran + uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: gcc + version: 12 + + - name: Run ctest (MacOS_latest) + id: run-ctest + run: | + cd "${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}" + cmake --workflow --preset=${{ inputs.preset_name }}-OSX-Clang --fresh + shell: bash + + - name: Publish binary (MacOS_latest) + id: publish-ctest-binary + run: | + mkdir "${{ runner.workspace }}/build" + 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 + cd "${{ runner.workspace }}/build" + tar -zcvf ${{ steps.set-file-base.outputs.FILE_BASE }}-osx.tar.gz hdf5 + shell: bash + + - name: List files in the space (MacOS_latest) + run: | + ls ${{ github.workspace }} + ls -l ${{ runner.workspace }} + + # Save files created by ctest script + - name: Save published binary (MacOS_latest) uses: actions/upload-artifact@v4 with: name: tgz-osx-binary @@ -369,7 +466,7 @@ jobs: # Get files created by release script - name: Get tgz-tarball (Linux S3) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-tarball path: ${{ github.workspace }} @@ -447,7 +544,7 @@ jobs: # Get files created by release script - name: Get zip-tarball (Windows_intel) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-tarball path: ${{ github.workspace }} @@ -477,11 +574,15 @@ jobs: cmake --workflow --preset=${{ inputs.preset_name }}-win-Intel --fresh shell: pwsh - - name: Publish binary (Windows_intel) - id: publish-ctest-binary + - name: Create build folders (Windows_intel) run: | mkdir "${{ runner.workspace }}/build" mkdir "${{ runner.workspace }}/build/hdf5" + shell: bash + + - name: Publish binary (Windows_intel) + id: publish-ctest-binary + run: | Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Intel/README.md -Destination ${{ runner.workspace }}/build/hdf5/ @@ -493,8 +594,6 @@ jobs: - name: Publish msi binary (Windows_intel) id: publish-ctest-msi-binary run: | - mkdir "${{ runner.workspace }}/build" - mkdir "${{ runner.workspace }}/build/hdf5" Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/${{ steps.set-file-base.outputs.SOURCE_BASE }}/COPYING_LBNL_HDF5 -Destination ${{ runner.workspace }}/build/hdf5/ Copy-Item -Path ${{ runner.workspace }}/hdf5/build/${{ inputs.preset_name }}-Intel/README.md -Destination ${{ runner.workspace }}/build/hdf5/ @@ -557,7 +656,7 @@ jobs: # Get files created by release script - name: Get tgz-tarball (Linux_intel) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-tarball path: ${{ github.workspace }} diff --git a/.github/workflows/main-cmake.yml b/.github/workflows/main-cmake.yml index 8c939ae23b1..8dc5fa1176d 100644 --- a/.github/workflows/main-cmake.yml +++ b/.github/workflows/main-cmake.yml @@ -312,6 +312,14 @@ jobs: if: ${{ (matrix.os == 'ubuntu-latest') && (inputs.thread_safety != 'TS') && (inputs.concurrent != 'CC') }} - name: Save published binary (Mac) + uses: actions/upload-artifact@v4 + with: + name: tgz-osx13-${{ 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-13') && (inputs.thread_safety != 'TS') }} + + - name: Save published binary (Mac_latest) uses: actions/upload-artifact@v4 with: name: tgz-osx-${{ inputs.build_mode }}-binary diff --git a/.github/workflows/publish-branch.yml b/.github/workflows/publish-branch.yml index 1ee8ee22bea..1e5b99bd0b0 100644 --- a/.github/workflows/publish-branch.yml +++ b/.github/workflows/publish-branch.yml @@ -12,8 +12,9 @@ on: description: 'hdf5 target bucket directory' type: string required: true - permissions: - contents: read + +permissions: + contents: read jobs: publish-tag: diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index d7c7fd091d1..c153d217d87 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -8,12 +8,17 @@ on: description: 'HDF5 Release version tag' type: string required: true + file_name: + description: 'HDF5 Release file name base' + type: string + required: true target_dir: description: 'HDF5 target bucket directory' type: string required: true - permissions: - contents: read + +permissions: + contents: read jobs: publish-tag: @@ -47,9 +52,9 @@ jobs: aws s3 sync ./HDF5 s3://${{ secrets.AWS_S3_BUCKET }}/${{ vars.TARGET_PATH }}/${{ inputs.target_dir }}/downloads --delete - name: Uncompress source (Linux) - run: tar -zxvf ${{ github.workspace }}/HDF5/${{ inputs.use_hdf }}.doxygen.tar.gz + run: unzip ${{ github.workspace }}/HDF5/${{ inputs.file_name }}.doxygen.zip - name: Sync userguide to S3 bucket run: | - aws s3 sync ./HDF5/doxygen s3://${{ secrets.AWS_S3_BUCKET }}/${{ vars.TARGET_PATH }}/${{ inputs.target_dir }}/documentation/doxygen --delete + aws s3 sync ./${{ inputs.file_name }}.doxygen s3://${{ secrets.AWS_S3_BUCKET }}/${{ vars.TARGET_PATH }}/${{ inputs.target_dir }}/documentation/doxygen --delete diff --git a/.github/workflows/release-files.yml b/.github/workflows/release-files.yml index 24c40786aec..b438e2dfc09 100644 --- a/.github/workflows/release-files.yml +++ b/.github/workflows/release-files.yml @@ -73,7 +73,7 @@ jobs: # Get files created by tarball script - name: Get doxygen (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: docs-doxygen path: ${{ github.workspace }}/${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen @@ -82,94 +82,94 @@ jobs: run: zip -r ${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen.zip ./${{ steps.get-file-base.outputs.FILE_BASE }}.doxygen - name: Get tgz-tarball (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-tarball path: ${{ github.workspace }} - name: Get zip-tarball (Windows) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-tarball path: ${{ github.workspace }} # Get files created by cmake-ctest script - name: Get published binary (Windows) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-vs2022_cl-binary path: ${{ github.workspace }} - name: Get published msi binary (Windows) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: msi-vs2022_cl-binary path: ${{ github.workspace }} - name: Get published binary (MacOS) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-osx-binary path: ${{ github.workspace }} - name: Get published binary (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-ubuntu-2204_gcc-binary path: ${{ github.workspace }} - name: Get published deb binary (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: deb-ubuntu-2204_gcc-binary path: ${{ github.workspace }} - name: Get published rpm binary (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: rpm-ubuntu-2204_gcc-binary path: ${{ github.workspace }} - name: Get published binary (Linux S3) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-ubuntu-2204_gcc_s3-binary path: ${{ github.workspace }} - name: Get published binary (Windows_intel) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-vs2022_intel-binary path: ${{ github.workspace }} - name: Get published msi binary (Windows_intel) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: msi-vs2022_intel-binary path: ${{ github.workspace }} - name: Get published binary (Linux_intel) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-ubuntu-2204_intel-binary path: ${{ github.workspace }} - name: Get published abi reports (Linux) - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: abi-reports path: ${{ github.workspace }} - name: Get published nonversioned source (tgz) if: ${{ (inputs.use_environ == 'release') }} - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: tgz-tarball-nover path: ${{ github.workspace }} - name: Get published nonversioned source (zip) if: ${{ (inputs.use_environ == 'release') }} - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: zip-tarball-nover path: ${{ github.workspace }} @@ -202,7 +202,7 @@ jobs: echo "${{ steps.get-file-base.outputs.FILE_BASE }}" > ./last-file.txt - name: Get NEWSLETTER - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: NEWSLETTER path: ${{ github.workspace }} @@ -214,7 +214,7 @@ jobs: - name: PreRelease tag id: create_prerelease if: ${{ (inputs.use_environ == 'snapshots') }} - uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6 + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 with: tag_name: "${{ inputs.use_tag }}" prerelease: true @@ -241,7 +241,7 @@ jobs: - name: Release tag id: create_release if: ${{ (inputs.use_environ == 'release') }} - uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6 + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 with: tag_name: "${{ inputs.use_tag }}" prerelease: false diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b826ee51164..e67627fd885 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif @@ -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@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 + uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 with: sarif_file: results.sarif diff --git a/HDF5Examples/C/H5G/test-pc.sh b/HDF5Examples/C/H5G/test-pc.sh index 4c996a45a58..4cff7780fe7 100755 --- a/HDF5Examples/C/H5G/test-pc.sh +++ b/HDF5Examples/C/H5G/test-pc.sh @@ -1,7 +1,6 @@ #! /bin/sh # # Copyright by The HDF Group. -# Copyright by the Board of Trustees of the University of Illinois. # All rights reserved. # # This file is part of HDF5. The full HDF5 copyright notice, including diff --git a/HDF5Examples/C/H5T/test-pc.sh b/HDF5Examples/C/H5T/test-pc.sh index 5a773f6097b..69c948759d2 100755 --- a/HDF5Examples/C/H5T/test-pc.sh +++ b/HDF5Examples/C/H5T/test-pc.sh @@ -1,7 +1,6 @@ #! /bin/sh # # Copyright by The HDF Group. -# Copyright by the Board of Trustees of the University of Illinois. # All rights reserved. # # This file is part of HDF5. The full HDF5 copyright notice, including diff --git a/HDF5Examples/CMakePresets.json b/HDF5Examples/CMakePresets.json index d9fdd04201a..1dc335ea715 100644 --- a/HDF5Examples/CMakePresets.json +++ b/HDF5Examples/CMakePresets.json @@ -49,6 +49,8 @@ "description": "MSVC Standard Config for x64 (Release)", "inherits": [ "ci-x64-Release-MSVC", + "ci-StdJava", + "ci-StdFortran", "ci-StdShar" ] }, @@ -57,6 +59,8 @@ "description": "Clang Standard Config for x64 (Release)", "inherits": [ "ci-x64-Release-Clang", + "ci-StdJava", + "ci-StdFortran", "ci-StdShar" ] }, @@ -65,6 +69,8 @@ "description": "GNUC Standard Config for x64 (Release)", "inherits": [ "ci-x64-Release-GNUC", + "ci-StdJava", + "ci-StdFortran", "ci-StdShar" ] }, @@ -73,6 +79,8 @@ "description": "Intel Standard Config for x64 (Release)", "inherits": [ "ci-x64-Release-Intel", + "ci-StdJava", + "ci-StdFortran", "ci-StdShar" ] } @@ -98,7 +106,7 @@ "name": "ci-StdShar-GNUC", "description": "GNUC Standard Build for x64 (Release)", "configurePreset": "ci-StdShar-GNUC", - "verbose": false, + "verbose": true, "inherits": [ "ci-x64-Release-GNUC" ] @@ -107,7 +115,7 @@ "name": "ci-StdShar-Intel", "description": "Intel Standard Build for x64 (Release)", "configurePreset": "ci-StdShar-Intel", - "verbose": false, + "verbose": true, "inherits": [ "ci-x64-Release-Intel" ] diff --git a/HDF5Examples/FORTRAN/H5G/test-pc.sh b/HDF5Examples/FORTRAN/H5G/test-pc.sh index 90b02f117dd..29781f3565d 100755 --- a/HDF5Examples/FORTRAN/H5G/test-pc.sh +++ b/HDF5Examples/FORTRAN/H5G/test-pc.sh @@ -1,7 +1,6 @@ #! /bin/sh # # Copyright by The HDF Group. -# Copyright by the Board of Trustees of the University of Illinois. # All rights reserved. # # This file is part of HDF5. The full HDF5 copyright notice, including diff --git a/HDF5Examples/FORTRAN/H5T/test-pc.sh b/HDF5Examples/FORTRAN/H5T/test-pc.sh index c11fa1d8297..12163a6f1f4 100755 --- a/HDF5Examples/FORTRAN/H5T/test-pc.sh +++ b/HDF5Examples/FORTRAN/H5T/test-pc.sh @@ -1,7 +1,6 @@ #! /bin/sh # # Copyright by The HDF Group. -# Copyright by the Board of Trustees of the University of Illinois. # All rights reserved. # # This file is part of HDF5. The full HDF5 copyright notice, including diff --git a/HDF5Examples/config/cmake/HDFExampleMacros.cmake b/HDF5Examples/config/cmake/HDFExampleMacros.cmake index c5e7b70c6bb..9888c06d36a 100644 --- a/HDF5Examples/config/cmake/HDFExampleMacros.cmake +++ b/HDF5Examples/config/cmake/HDFExampleMacros.cmake @@ -191,9 +191,17 @@ macro (HDF5_SUPPORT) endif () set (H5EX_HDF5_DUMP_EXECUTABLE $) else () + if (HDF5_BUILD_MODE) + string (TOUPPER "_${HDF5_BUILD_MODE}" UPPER_BUILD_TYPE) + elseif (HDF_CFG_NAME) + string (TOUPPER "_${HDF_CFG_NAME}" UPPER_BUILD_TYPE) + else () + set (UPPER_BUILD_TYPE "") + endif () + get_filename_component (_LIBRARY_PATH ${HDF5_INCLUDE_DIR} DIRECTORY) + set (HDF5_LIBRARY_PATH "${_LIBRARY_PATH}/lib") if (USE_SHARED_LIBS AND HDF5_shared_C_FOUND) set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_C_SHARED_LIBRARY}) - set (HDF5_LIBRARY_PATH ${PACKAGE_PREFIX_DIR}/lib) else () set (H5EX_HDF5_LINK_LIBS ${H5EX_HDF5_LINK_LIBS} ${HDF5_C_STATIC_LIBRARY}) endif () @@ -227,20 +235,11 @@ macro (HDF5_SUPPORT) if (HDF_BUILD_JAVA AND HDF5_Java_FOUND) if (${HDF5_BUILD_JAVA}) set (CMAKE_JAVA_INCLUDE_PATH "${CMAKE_JAVA_INCLUDE_PATH};${HDF5_JAVA_INCLUDE_DIRS}") - if (HDF5_BUILD_MODE) - string(TOUPPER "${HDF5_BUILD_MODE}" UPPER_BUILD_TYPE) - get_target_property(libsoname ${HDF5_JAVA_LIBRARY} IMPORTED_SONAME_${UPPER_BUILD_TYPE}) - elseif (HDF_CFG_NAME) - string(TOUPPER "${HDF_CFG_NAME}" UPPER_BUILD_TYPE) - get_target_property(libsoname ${HDF5_JAVA_LIBRARY} IMPORTED_SONAME_${UPPER_BUILD_TYPE}) - else() - get_target_property(libsoname ${HDF5_JAVA_LIBRARY} IMPORTED_SONAME) - endif() + get_target_property (libsoname ${HDF5_JAVA_LIBRARY} IMPORTED_SONAME${UPPER_BUILD_TYPE}) get_filename_component (libname ${libsoname} NAME_WE) string (REGEX REPLACE "^lib" "" libname ${libname}) message (STATUS "HDF5 lib:${HDF5_JAVA_LIBRARY} OR ${libsoname} OR ${libname}") set (H5EX_JAVA_LIBRARY ${libname}) -# set (H5EX_JAVA_LIBRARY $) set (H5EX_JAVA_LIBRARIES ${HDF5_JAVA_LIBRARY}) message (STATUS "HDF5 lib:${H5EX_JAVA_LIBRARY} jars:${HDF5_JAVA_INCLUDE_DIRS}}") else () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4499fa67292..58a0eccb840 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1137,8 +1137,7 @@ if (BUILD_SHARED_LIBS) TARGET_C_PROPERTIES (${HDF5_LIBSH_TARGET} SHARED) target_link_libraries (${HDF5_LIBSH_TARGET} PRIVATE ${LINK_LIBS} ${LINK_COMP_LIBS} - "$<$,$>:Threads::Threads>" - PUBLIC "$<$>:${CMAKE_DL_LIBS}>" "$<$:MPI::MPI_C>" + PUBLIC "$<$>:${CMAKE_DL_LIBS}>" "$<$:MPI::MPI_C>" "$<$,$>:Threads::Threads>" ) set_global_variable (HDF5_LIBRARIES_TO_EXPORT "${HDF5_LIBRARIES_TO_EXPORT};${HDF5_LIBSH_TARGET}") H5_SET_LIB_OPTIONS (${HDF5_LIBSH_TARGET} ${HDF5_LIB_NAME} SHARED "LIB") diff --git a/src/H5TSatomic.h b/src/H5TSatomic.h index 1d8011c577b..478760e8c4d 100644 --- a/src/H5TSatomic.h +++ b/src/H5TSatomic.h @@ -344,4 +344,4 @@ H5TS_atomic_compare_exchange_strong_voidp(H5TS_atomic_voidp_t *obj, void **expec return ret_value; } /* end H5TS_atomic_compare_exchange_strong_voidp() */ -#endif /* H5_HAVE_THREADS */ +#endif /* H5_HAVE_STDATOMIC_H */ diff --git a/src/H5Tcommit.c b/src/H5Tcommit.c index 56b22042d66..d64c4e82439 100644 --- a/src/H5Tcommit.c +++ b/src/H5Tcommit.c @@ -59,6 +59,7 @@ static herr_t H5T__commit_api_common(hid_t loc_id, const char *name, hid_t type_ static hid_t H5T__open_api_common(hid_t loc_id, const char *name, hid_t tapl_id, void **token_ptr, H5VL_object_t **_vol_obj_ptr); static H5T_t *H5T__open_oid(const H5G_loc_t *loc); +static herr_t H5T_destruct_datatype(void *datatype, H5VL_t *vol_connector); /*********************/ /* Public Variables */ @@ -662,7 +663,7 @@ H5T__open_api_common(hid_t loc_id, const char *name, hid_t tapl_id, void **token done: /* Cleanup on error */ if (H5I_INVALID_HID == ret_value) - if (dt && H5VL_datatype_close(*vol_obj_ptr, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) + if (dt && H5T_destruct_datatype(dt, (*vol_obj_ptr)->connector) < 0) HDONE_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, H5I_INVALID_HID, "unable to release datatype"); FUNC_LEAVE_NOAPI(ret_value) @@ -1260,6 +1261,41 @@ H5T_construct_datatype(H5VL_object_t *vol_obj) FUNC_LEAVE_NOAPI(ret_value) } /* end H5T_construct_datatype() */ +/*------------------------------------------------------------------------- + * Function: H5T_destruct_datatype + * + * Purpose: Helper function to free a committed datatype object that + * hasn't yet been wrapped within a VOL object. This usually + * happens when a failure occurs during opening a committed + * datatype. When this happens, the datatype must be wrapped + * inside a temporary VOL object in order to route the close + * operation through the stack of VOL connectors. + * + * Return: Non-negative on success/Negative on failure + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_destruct_datatype(void *datatype, H5VL_t *vol_connector) +{ + H5VL_object_t *vol_obj = NULL; + herr_t ret_value = FAIL; + + FUNC_ENTER_NOAPI(FAIL) + + if (NULL == (vol_obj = H5VL_create_object(datatype, vol_connector))) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "can't create VOL object for committed datatype"); + + if (H5VL_datatype_close(vol_obj, H5P_DATASET_XFER_DEFAULT, H5_REQUEST_NULL) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, "unable to release datatype"); + +done: + if (vol_obj && H5VL_free_object(vol_obj) < 0) + HDONE_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "can't free VOL object"); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_destruct_datatype() */ + /*------------------------------------------------------------------------- * Function: H5T_get_named_type * diff --git a/src/H5VLint.c b/src/H5VLint.c index f3648b14a87..295b71e2854 100644 --- a/src/H5VLint.c +++ b/src/H5VLint.c @@ -586,6 +586,12 @@ H5VL__new_vol_obj(H5I_type_t type, void *object, H5VL_t *vol_connector, bool wra if (NULL == ret_value) { if (conn_rc_incr && H5VL_conn_dec_rc(vol_connector) < 0) HDONE_ERROR(H5E_VOL, H5E_CANTDEC, NULL, "unable to decrement ref count on VOL connector"); + + if (new_vol_obj) { + if (wrap_obj && new_vol_obj->data) + (void)H5VL_object_unwrap(new_vol_obj); + (void)H5FL_FREE(H5VL_object_t, new_vol_obj); + } } /* end if */ FUNC_LEAVE_NOAPI(ret_value) @@ -706,7 +712,7 @@ H5VL_register(H5I_type_t type, void *object, H5VL_t *vol_connector, bool app_ref /* Set up VOL object for the passed-in data */ /* (Does not wrap object, since it's from a VOL callback) */ if (NULL == (vol_obj = H5VL__new_vol_obj(type, object, vol_connector, false))) - HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, FAIL, "can't create VOL object"); + HGOTO_ERROR(H5E_VOL, H5E_CANTCREATE, H5I_INVALID_HID, "can't create VOL object"); /* Register VOL object as _object_ type, for future object API calls */ if ((ret_value = H5I_register(type, vol_obj, app_ref)) < 0) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c6e063a3ddd..9c3f28a01d1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -575,12 +575,9 @@ target_include_directories (ttsafe PRIVATE "${HDF5_SRC_INCLUDE_DIRS};${HDF5_SRC_ if (NOT BUILD_SHARED_LIBS) TARGET_C_PROPERTIES (ttsafe STATIC) target_link_libraries (ttsafe PRIVATE ${HDF5_TEST_LIB_TARGET}) - if (NOT WIN32) - target_link_libraries (ttsafe PRIVATE "$<$:Threads::Threads>") - endif () else () TARGET_C_PROPERTIES (ttsafe SHARED) - target_link_libraries (ttsafe PRIVATE ${HDF5_TEST_LIBSH_TARGET} "$<$:Threads::Threads>") + target_link_libraries (ttsafe PRIVATE ${HDF5_TEST_LIBSH_TARGET}) endif () set_target_properties (ttsafe PROPERTIES FOLDER test) diff --git a/test/testframe.c b/test/testframe.c index ff12413a62e..50daede8eea 100644 --- a/test/testframe.c +++ b/test/testframe.c @@ -590,7 +590,7 @@ TestErrPrintf(const char *format, ...) * Set (control) which test will be tested. * SKIPTEST: skip this test * ONLYTEST: do only this test - * BEGINETEST: skip all tests before this test + * BEGINTEST: skip all tests before this test * */ void diff --git a/test/ttsafe_rec_rw_lock.c b/test/ttsafe_rec_rw_lock.c new file mode 100644 index 00000000000..f7230af3d9d --- /dev/null +++ b/test/ttsafe_rec_rw_lock.c @@ -0,0 +1,1137 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/******************************************************************** + * + * Test the correctness of the recursive R/W lock in the HDF5 library + * ------------------------------------------------------------- + * + * Test the recursive R/W lock in isolation, using a combination of + * error return values and statistics collected by the recursive + * R/W lock to detect any failures. + * + * No file is created. + * + * Multiple threads are created, and allowed to compete for the lock. + * The number of threads, and the number of times they obtain the + * lock depends on the express test level. + * + ********************************************************************/ + +#include "ttsafe.h" + +#ifdef H5_HAVE_THREADS +#ifndef H5_HAVE_WIN_THREADS + +#define MAX_NUM_THREADS 32 +#define MAX_LOCK_CYCLES (1000 * 1000) + +/* structure used to configure test threads in the recursive + * R/W/ lock tests. + */ +/*********************************************************************** + * + * Structure rec_rw_lock_test_udata_t + * + * Arrays of instances of rec_rw_lock_test_udata_t are used to configure + * the threads used to test the recursive R/W lock, and to collect + * statistics on their behaviour. These statistics are aggregated and + * used to cross-check the statistics collected by the recursive R/W + * lock proper. + * + * The fields of the structure are discussed below: + * + * rw_lock: Pointer to the recursive R/W under test. + * + * target_rd_lock_cycles: The number of times the test thread is + * required to obtain and drop the read lock. Note + * that this value restricts the number of initial + * read locks only. Additional recursive locks are + * possible -- see max_recursive_lock_depth below. + * + * target_wr_lock_cycles: The number of times the test thread is + * required to obtain and drop the write lock. Note + * that this value restricts the number of initial + * write locks only. Additional recursive locks are + * possible -- see max_recursive_lock_depth below. + * + * max_recursive_lock_depth: Once a test thread gains a lock, it does + * random recursive leocks and unlocks until it happens + * to drop the lock. The max_recursive_lock_depth + * places an upper bound on the net number of locks. + * Any attempt exceed this limit is converted into + * an unlock. + * + * The remaining fields are used for statistics collection. They are + * thread specific versions of the fields of the same name in + * H5TS_rw_lock_stats_t. See the header comment for that + * structure (in H5TSprivate.h) for further details. + * + ***********************************************************************/ +typedef struct rec_rw_lock_test_udata_t { + + /* thread control fields */ + H5TS_rw_lock_t *rw_lock; + int32_t target_rd_lock_cycles; + int32_t target_wr_lock_cycles; + int32_t max_recursive_lock_depth; + + /* thread stats fields */ + int64_t read_locks_granted; + int64_t read_locks_released; + int64_t real_read_locks_granted; + int64_t real_read_locks_released; + int64_t write_locks_granted; + int64_t write_locks_released; + int64_t real_write_locks_granted; + int64_t real_write_locks_released; + +} rec_rw_lock_test_udata_t; + +/* + ********************************************************************** + * tts_rw_lock_smoke_check_test_thread + * + * Perform a sequence of recursive read and/or write locks on the + * target recursive R/W lock as directed by the supplied user data. + * Record all operations in the user data for later cross-checking + * with the statistics maintained by the recursive R/W lock. + * + * Note: while the number of read and/or write locks is fixed, the + * number of _recursive_ lock and unlock calls is random, as is the + * order of the read and write locks, if both are enabled. + * + ********************************************************************** + */ +static H5TS_THREAD_RETURN_TYPE +tts_rw_lock_smoke_check_test_thread(void *_udata) +{ + hbool_t read; + int32_t rec_lock_depth = 0; + int32_t max_rec_lock_depth; + int32_t rd_locks_remaining; + int32_t wr_locks_remaining; + herr_t result; + H5TS_rw_lock_t *rw_lock; + rec_rw_lock_test_udata_t *udata = (rec_rw_lock_test_udata_t *)_udata; + + assert(_udata); + rd_locks_remaining = udata->target_rd_lock_cycles; + wr_locks_remaining = udata->target_wr_lock_cycles; + max_rec_lock_depth = udata->max_recursive_lock_depth; + rw_lock = udata->rw_lock; + + while (rd_locks_remaining > 0 || wr_locks_remaining > 0) { + if (wr_locks_remaining == 0) + read = TRUE; + else if (rd_locks_remaining == 0) + read = FALSE; + else { + if ((rand() % 2) == 0) + read = TRUE; + else + read = FALSE; + } + + if (read) { + result = H5TS__rw_rdlock(rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + udata->read_locks_granted++; + udata->real_read_locks_granted++; + rd_locks_remaining--; + rec_lock_depth = 1; + + while (rec_lock_depth > 0) { + if (rec_lock_depth >= max_rec_lock_depth || (rand() % 2) == 0) { + result = H5TS__rw_unlock(rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + rec_lock_depth--; + udata->read_locks_released++; + } + else { + result = H5TS__rw_rdlock(rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + rec_lock_depth++; + udata->read_locks_granted++; + } + } + + udata->real_read_locks_released++; + } + else { + result = H5TS__rw_wrlock(rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + udata->write_locks_granted++; + udata->real_write_locks_granted++; + wr_locks_remaining--; + rec_lock_depth = 1; + + while (rec_lock_depth > 0) { + if (rec_lock_depth >= max_rec_lock_depth || (rand() % 2) == 0) { + result = H5TS__rw_unlock(rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + rec_lock_depth--; + udata->write_locks_released++; + } + else { + result = H5TS__rw_wrlock(rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + rec_lock_depth++; + udata->write_locks_granted++; + } + } + + udata->real_write_locks_released++; + } + } + + return (H5TS_thread_ret_t)0; +} /* end tts_rw_lock_smoke_check_test_thread() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_1 + * + * Single thread test to verify basic functionality and error + * rejection of the recursive R/W lock. + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Obtain a read lock. + * + * 3) Drop the read lock. + * + * 4) Verify the expected stats, and then reset them. + * + * 5) Obtain a read lock. + * + * 6) Obtain the read lock a second time. + * + * 7) Drop the read lock. + * + * 8) Drop the read lock a second time. + * + * 9) Verify the expected stats, and then reset them. + * + * 10) Obtain a write lock. + * + * 11) Drop the write lock. + * + * 12) Verify the expected stats, and then reset them. + * + * 13) Obtain a write lock. + * + * 14) Obtain the write lock a second time. + * + * 15) Drop the write lock. + * + * 16) Drop the write lock a second time. + * + * 17) Verify the expected stats, and then reset them. + * + * 18) Obtain a write lock. + * + * 19) Attempt to obtain a read lock -- should fail. + * + * 20) Drop the write lock. + * + * 21) Obtain a read lock. + * + * 22) Attempt to obtain a write lock -- should fail. + * + * 23) Drop the read lock. + * + * 24) Verify the expected stats, and then reset them. + * + * 25) Shut down the recursive R/W lock. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_1(void) +{ + herr_t result; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + H5TS_rw_lock_stats_t stats; +#endif + H5TS_rw_lock_t rec_rw_lock; + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Obtain a read lock. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 3) Drop the read lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 4) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 1 || + stats.read_locks_released != 1 || + stats.real_read_locks_granted != 1 || + stats.real_read_locks_released != 1 || + stats.max_read_locks != 1 || + stats.max_read_lock_recursion_depth != 1 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 0 || + stats.write_locks_released != 0 || + stats.real_write_locks_granted != 0 || + stats.real_write_locks_released != 0 || + stats.max_write_locks != 0 || + stats.max_write_lock_recursion_depth != 0 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 1"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 5) Obtain a read lock. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 6) Obtain the read lock a second time. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 7) Drop the read lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + /* 8) Drop the read lock a second time. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 9) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 2 || + stats.read_locks_released != 2 || + stats.real_read_locks_granted != 1 || + stats.real_read_locks_released != 1 || + stats.max_read_locks != 1 || + stats.max_read_lock_recursion_depth != 2 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 0 || + stats.write_locks_released != 0 || + stats.real_write_locks_granted != 0 || + stats.real_write_locks_released != 0 || + stats.max_write_locks != 0 || + stats.max_write_lock_recursion_depth != 0 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 2"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 10) Obtain a write lock. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 11) Drop the write lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 12) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 0 || + stats.read_locks_released != 0 || + stats.real_read_locks_granted != 0 || + stats.real_read_locks_released != 0 || + stats.max_read_locks != 0 || + stats.max_read_lock_recursion_depth != 0 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 1 || + stats.write_locks_released != 1 || + stats.real_write_locks_granted != 1 || + stats.real_write_locks_released != 1 || + stats.max_write_locks != 1 || + stats.max_write_lock_recursion_depth != 1 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 3"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 13) Obtain a write lock. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 14) Obtain the write lock a second time. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 15) Drop the write lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + /* 16) Drop the write lock a second time. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 17) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 0 || + stats.read_locks_released != 0 || + stats.real_read_locks_granted != 0 || + stats.real_read_locks_released != 0 || + stats.max_read_locks != 0 || + stats.max_read_lock_recursion_depth != 0 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 2 || + stats.write_locks_released != 2 || + stats.real_write_locks_granted != 1 || + stats.real_write_locks_released != 1 || + stats.max_write_locks != 1 || + stats.max_write_lock_recursion_depth != 2 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats -- 4"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 18) Obtain a write lock. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_wrlock"); + + /* 19) Attempt to obtain a read lock -- should fail. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + VERIFY(result, FAIL, "H5TS__rw_rdlock"); + + /* 20) Drop the write lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + + /* 21) Obtain a read lock. */ + result = H5TS__rw_rdlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_rdlock"); + + /* 22) Attempt to obtain a write lock -- should fail. */ + result = H5TS__rw_wrlock(&rec_rw_lock); + VERIFY(result, FAIL, "H5TS__rw_wrlock"); + + /* 23) Drop the read lock. */ + result = H5TS__rw_unlock(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_unlock"); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* 24) Verify the expected stats, and then reset them. */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + result = H5TS__rw_lock_reset_stats(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_reset_stats"); + + /* clang-format makes this conditional unreadable, so turn it off. */ + /* clang-format off */ + if (stats.read_locks_granted != 1 || + stats.read_locks_released != 1 || + stats.real_read_locks_granted != 1 || + stats.real_read_locks_released != 1 || + stats.max_read_locks != 1 || + stats.max_read_lock_recursion_depth != 1 || + stats.read_locks_delayed != 0 || + stats.write_locks_granted != 1 || + stats.write_locks_released != 1 || + stats.real_write_locks_granted != 1 || + stats.real_write_locks_released != 1 || + stats.max_write_locks != 1 || + stats.max_write_lock_recursion_depth != 1 || + stats.write_locks_delayed != 0 || + stats.max_write_locks_pending != 0 ) { + + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + } + /* clang-format on */ +#endif + + /* 25) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); +} /* end tts_rec_rw_lock_smoke_check_1() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_2 -- mob of readers + * + * Multi-threaded test to check management of multiple readers ONLY by + * the recursive R/W lock. Test proceeds as follows: + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Setup the user data to be passed to each reader test thread. + * + * 3) Create the reader threads, each with its own user data. + * Activities of the reader threads is discussed in the header + * comment to tts_rw_lock_smoke_check_test_thread(). + * + * 4) Wait for all threads to complete. + * + * 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlocks. + * + * 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + * + * 7) Shut down the recursive R/W lock. + * + * The reader threads obtain and drop the read lock a specified + * number of times. Once a reader has a read lock, it does random + * recursive read locks / unlocks until drops the read lock, and then + * repeats the process until the specified number of read locks have + * been acquired and dropped. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_2(void) +{ + herr_t result; + int express_test; + int i; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rw_lock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; +#endif + H5TS_rw_lock_t rec_rw_lock; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Reset expected stats fields to zero -- we will construct the expected + * stats from the thread udata after completion. + */ + memset(&expected, 0, sizeof(expected)); +#endif + + /* Allocate the udata */ + udata = malloc(sizeof(*udata) * MAX_NUM_THREADS); + if (NULL == udata) { + TestErrPrintf("thread udata allocation failed.\n"); + + /* We can't do anything without the udata, so just return */ + return; + } + + /* Reduce # of threads and test cycles for higher levels of express testing */ + express_test = GetTestExpress(); + if (express_test >= 1) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 2) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 3) { + num_threads /= 2; + lock_cycles /= 10; + } + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Setup the user data to be passed to each reader test thread. */ + for (i = 0; i < MAX_NUM_THREADS; i++) { + memset(&udata[i], 0, sizeof(udata[i])); + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_rd_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; + } + +#if H5TS_ENABLE_REC_RW_LOCK_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) + 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 + uint64_t end_time = H5_now_usec(); + uint64_t elap_time = (unsigned long long)(end_time - start_time); + if (verbose) + fprintf(stdout, "elapsed usec: %" PRIu64 ", usec per lock_cycle = %" PRIu64 "\n", elap_time, + (elap_time / (uint64_t)lock_cycles)); +#endif + + /* 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlocks. + * + * First, tally up the lock entries and exits from the test threads, + * and store this data in the expected recursive R/W/ lock stats.. + * In passing, verify that each thread has done the expected number + * of locks and unlocks. Do these as asserts -- will run checks on + * aggregate data shortly. + */ + + for (i = 0; i < num_threads; i++) { + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_granted); + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_released); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; + total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; + + expected.read_locks_granted += udata[i].read_locks_granted; + expected.read_locks_released += udata[i].read_locks_released; + expected.real_read_locks_granted += udata[i].real_read_locks_granted; + expected.real_read_locks_released += udata[i].real_read_locks_released; + expected.write_locks_granted += udata[i].write_locks_granted; + expected.write_locks_released += udata[i].write_locks_released; + expected.real_write_locks_granted += udata[i].real_write_locks_granted; + expected.real_write_locks_released += udata[i].real_write_locks_released; +#endif + } + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Verify that the threads executed the expected number of read and write + * lock cycles. If they didn't, some thread probably encountered an error + * and exited early. + */ + if (total_target_rd_lock_cycles != expected.real_read_locks_granted || + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) + TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); + + /* initialize remaining non-zero fields in the expected stats */ + expected.max_read_locks = num_threads; + expected.max_read_lock_recursion_depth = 10; + + /* 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + */ + + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + /* turn off clang-format for readability */ + /* clang-format off */ + if (stats.read_locks_granted != expected.read_locks_granted || + stats.read_locks_released != expected.read_locks_released || + stats.real_read_locks_granted != expected.real_read_locks_granted || + stats.real_read_locks_released != expected.real_read_locks_released || + stats.max_read_locks > expected.max_read_locks || + stats.max_read_locks < 1 || + stats.max_read_lock_recursion_depth > expected.max_read_lock_recursion_depth || + stats.max_read_lock_recursion_depth < 1 || + stats.read_locks_delayed != expected.read_locks_delayed || + stats.write_locks_granted != expected.write_locks_granted || + stats.write_locks_released != expected.write_locks_released || + stats.real_write_locks_granted != expected.real_write_locks_granted || + stats.real_write_locks_released != expected.real_write_locks_released || + stats.max_write_locks != expected.max_write_locks || + stats.max_write_lock_recursion_depth != expected.max_write_lock_recursion_depth || + stats.write_locks_delayed != expected.write_locks_delayed || + stats.max_write_locks_pending != expected.max_write_locks_pending) { + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rw_lock_print_stats("Expected stats", &expected); + } + /* clang-format on */ + + if (verbose) + H5TS__rw_lock_print_stats("mob of readers stats", &stats); +#endif + + /* 7) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); + + /* discard the udata if it exists */ + if (udata) + free(udata); +} /* end tts_rec_rw_lock_smoke_check_2() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_3 -- mob of writers + * + * Multi-thread test to check management of multiple writers ONLY by + * the recursive R/W lock. Test proceeds as follows: + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Setup the user data to be passed to each writer test thread. + * + * 3) Create the writer threads, each with its own user data. + * Activities of the writer threads is discussed in the header + * comment to tts_rw_lock_smoke_check_test_thread(). + * + * 4) Wait for all threads to complete. + * + * 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlock. + * + * 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + * + * 7) Shut down the recursive R/W lock. + * + * The writer threads obtain and drop the read lock a specified + * number of times. Once a writeer has a write lock, it does random + * recursive write locks / unlocks until drops the write lock, and then + * repeats the process until the specified number of write locks have + * been acquired and dropped. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_3(void) +{ + herr_t result; + int i; + int express_test; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rw_lock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; +#endif + H5TS_rw_lock_t rec_rw_lock; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Reset expected stats fields to zero -- we will construct the expected + * stats from the thread udata after completion. + */ + memset(&expected, 0, sizeof(expected)); +#endif + + /* Allocate the udata */ + udata = malloc(sizeof(*udata) * MAX_NUM_THREADS); + if (udata == NULL) { + TestErrPrintf("thread udata allocation failed.\n"); + + /* We can't do anything without the udata, so just return */ + return; + } + + /* Reduce # of threads and test cycles for higher levels of express testing */ + express_test = GetTestExpress(); + if (express_test >= 1) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 2) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 3) { + num_threads /= 2; + lock_cycles /= 10; + } + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Setup the user data to be passed to each writer test thread. */ + for (i = 0; i < MAX_NUM_THREADS; i++) { + memset(&udata[i], 0, sizeof(udata[i])); + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_wr_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; + } + +#if H5TS_ENABLE_REC_RW_LOCK_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) + 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 + uint64_t end_time = H5_now_usec(); + uint64_t elap_time = (unsigned long long)(end_time - start_time); + if (verbose) + fprintf(stdout, "elapsed usec: %" PRIu64 ", usec per lock_cycle = %" PRIu64 "\n", elap_time, + (elap_time / (uint64_t)lock_cycles)); +#endif + + /* 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlock. + * + * First, tally up the lock entries and exits from the test threads, + * and store this data in the expected recursive R/W/ lock stats.. + * In passing, verify that each thread has done the expected number + * of locks and unlocks. Do these as asserts -- will run checks on + * aggregate data shortly. + */ + + for (i = 0; i < num_threads; i++) { + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_granted); + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_released); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; + total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; + + expected.read_locks_granted += udata[i].read_locks_granted; + expected.read_locks_released += udata[i].read_locks_released; + expected.real_read_locks_granted += udata[i].real_read_locks_granted; + expected.real_read_locks_released += udata[i].real_read_locks_released; + expected.write_locks_granted += udata[i].write_locks_granted; + expected.write_locks_released += udata[i].write_locks_released; + expected.real_write_locks_granted += udata[i].real_write_locks_granted; + expected.real_write_locks_released += udata[i].real_write_locks_released; +#endif + } + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Verify that the threads executed the expected number of read and write + * lock cycles. If they didn't, some thread probably encountered an error + * and exited early. + */ + if (total_target_rd_lock_cycles != expected.real_read_locks_granted || + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) + TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); + + /* initialize remaining non-zero fields in the expected stats */ + expected.max_write_locks = 1; + expected.max_write_lock_recursion_depth = 10; + expected.max_write_locks_pending = num_threads - 1; + + /* 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + /* turn off clang-format for readability */ + /* clang-format off */ + if (stats.read_locks_granted != expected.read_locks_granted || + stats.read_locks_released != expected.read_locks_released || + stats.real_read_locks_granted != expected.real_read_locks_granted || + stats.real_read_locks_released != expected.real_read_locks_released || + stats.max_read_locks != expected.max_read_locks || + stats.max_read_lock_recursion_depth != expected.max_read_lock_recursion_depth || + stats.read_locks_delayed != expected.read_locks_delayed || + stats.write_locks_granted != expected.write_locks_granted || + stats.write_locks_released != expected.write_locks_released || + stats.real_write_locks_granted != expected.real_write_locks_granted || + stats.real_write_locks_released != expected.real_write_locks_released || + stats.max_write_locks != expected.max_write_locks || + stats.max_write_lock_recursion_depth > expected.max_write_lock_recursion_depth || + stats.max_write_lock_recursion_depth < 1 || + stats.write_locks_delayed < expected.write_locks_delayed || + stats.max_write_locks_pending > expected.max_write_locks_pending) { + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rw_lock_print_stats("Expected stats", &expected); + } + /* clang-format on */ + + if (verbose) + H5TS__rw_lock_print_stats("Actual stats", &stats); +#endif + + /* 7) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); + + /* discard the udata if it exists */ + if (udata) + free(udata); +} /* end tts_rec_rw_lock_smoke_check_3() */ + +/* + ********************************************************************** + * tts_rec_rw_lock_smoke_check_4 -- mixed mob + * + * Multi-thread test to check management of multiple readers and + * writers by the recursive R/W lock. Test proceeds as follows: + * + * 1) Initialize an instance of the recursive R/W lock. + * + * 2) Setup the user data to be passed to each writer test thread. + * + * 3) Create the reader / writer threads, each with its own user data. + * Activities of the reader / writer threads is discussed in the + * header comment to tts_rw_lock_smoke_check_test_thread(). + * + * 4) Wait for all threads to complete. + * + * 5) Examine the user data from the threads, to determine the + * total number of real and recursive read & write locks and + * unlock. + * + * 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + * + * 7) Shut down the recursive R/W lock. + * + * The reader / writer threads obtain and drop the read or write + * locks a specified number of times. Once a thread has a lock, it + * does random recursive locks / unlocks until drops the lock, and then + * repeats the process until the specified number of locks have + * been acquired and dropped. + * + ********************************************************************** + */ +void +tts_rec_rw_lock_smoke_check_4(void) +{ + herr_t result; + int i; + int express_test; + int num_threads = MAX_NUM_THREADS; + int lock_cycles = MAX_LOCK_CYCLES; + H5TS_thread_t threads[MAX_NUM_THREADS]; + rec_rw_lock_test_udata_t *udata = NULL; +#if H5TS_ENABLE_REC_RW_LOCK_STATS + hbool_t verbose = FALSE; + int32_t total_target_rd_lock_cycles = 0; + int32_t total_target_wr_lock_cycles = 0; + H5TS_rw_lock_stats_t stats; + H5TS_rw_lock_stats_t expected; +#endif + H5TS_rw_lock_t rec_rw_lock; + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Reset expected stats fields to zero -- we will construct the expected + * stats from the thread udata after completion. + */ + memset(&expected, 0, sizeof(expected)); +#endif + + /* Allocate the udata */ + udata = malloc(sizeof(*udata) * MAX_NUM_THREADS); + if (udata == NULL) { + TestErrPrintf("thread udata allocation failed.\n"); + + /* We can't do anything without the udata, so just return */ + return; + } + + /* Reduce # of threads and test cycles for higher levels of express testing */ + express_test = GetTestExpress(); + if (express_test >= 1) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 2) { + num_threads /= 2; + lock_cycles /= 10; + } + if (express_test >= 3) { + num_threads /= 2; + lock_cycles /= 10; + } + + /* 1) Initialize an instance of the recursive R/W lock. */ + result = H5TS__rw_lock_init(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_init"); + + /* 2) Setup the user data to be passed to each writer test thread. */ + for (i = 0; i < MAX_NUM_THREADS; i++) { + memset(&udata[i], 0, sizeof(udata[i])); + udata[i].rw_lock = &rec_rw_lock; + udata[i].target_rd_lock_cycles = lock_cycles; + udata[i].target_wr_lock_cycles = lock_cycles; + udata[i].max_recursive_lock_depth = 10; + } + +#if H5TS_ENABLE_REC_RW_LOCK_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) + 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 + uint64_t end_time = H5_now_usec(); + uint64_t elap_time = (unsigned long long)(end_time - start_time); + if (verbose) + fprintf(stdout, "elapsed usec: %" PRIu64 ", usec per lock_cycle = %" PRIu64 "\n", elap_time, + (elap_time / (uint64_t)lock_cycles)); +#endif + + /* 5) Examine the user data from the threads, to determine the + * total number of real and recursive read locks and unlock. + * + * First, tally up the lock entries and exits from the test threads, + * and store this data in the expected recursive R/W/ lock stats.. + * In passing, verify that each thread has done the expected number + * of locks and unlocks. Do these as asserts -- will run checks on + * aggregate data shortly. + */ + + for (i = 0; i < num_threads; i++) { + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_granted); + assert(udata[i].target_rd_lock_cycles == udata[i].real_read_locks_released); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_granted); + assert(udata[i].target_wr_lock_cycles == udata[i].real_write_locks_released); + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + total_target_rd_lock_cycles += udata[i].target_rd_lock_cycles; + total_target_wr_lock_cycles += udata[i].target_wr_lock_cycles; + + expected.read_locks_granted += udata[i].read_locks_granted; + expected.read_locks_released += udata[i].read_locks_released; + expected.real_read_locks_granted += udata[i].real_read_locks_granted; + expected.real_read_locks_released += udata[i].real_read_locks_released; + expected.write_locks_granted += udata[i].write_locks_granted; + expected.write_locks_released += udata[i].write_locks_released; + expected.real_write_locks_granted += udata[i].real_write_locks_granted; + expected.real_write_locks_released += udata[i].real_write_locks_released; +#endif + } + +#if H5TS_ENABLE_REC_RW_LOCK_STATS + /* Verify that the threads executed the expected number of read and write + * lock cycles. If they didn't, some thread probably encountered an error + * and exited early. + */ + if (total_target_rd_lock_cycles != expected.real_read_locks_granted || + total_target_rd_lock_cycles != expected.real_read_locks_released || + total_target_wr_lock_cycles != expected.real_write_locks_granted || + total_target_wr_lock_cycles != expected.real_write_locks_released) + TestErrPrintf("Threads reported unexpected number of locks/unlocks.\n"); + + /* initialize remaining non-zero fields in the expected stats */ + expected.max_read_locks = num_threads; + expected.max_read_lock_recursion_depth = 10; + expected.max_write_locks = 1; + expected.max_write_lock_recursion_depth = 10; + expected.max_write_locks_pending = num_threads - 1; + + /* 6) Obtain the stats from the recursive R/W lock, and compare + * with the data gathered above. + */ + result = H5TS__rw_lock_get_stats(&rec_rw_lock, &stats); + CHECK_I(result, "H5TS__rw_lock_get_stats"); + + /* turn off clang-format for readability */ + /* clang-format off */ + if (stats.read_locks_granted != expected.read_locks_granted || + stats.read_locks_released != expected.read_locks_released || + stats.real_read_locks_granted != expected.real_read_locks_granted || + stats.real_read_locks_released != expected.real_read_locks_released || + stats.max_read_locks > expected.max_read_locks || + stats.max_read_locks < 1 || + stats.max_read_lock_recursion_depth > expected.max_read_lock_recursion_depth || + stats.read_locks_delayed < expected.read_locks_delayed || + stats.write_locks_granted != expected.write_locks_granted || + stats.write_locks_released != expected.write_locks_released || + stats.real_write_locks_granted != expected.real_write_locks_granted || + stats.real_write_locks_released != expected.real_write_locks_released || + stats.max_write_locks != expected.max_write_locks || + stats.max_write_lock_recursion_depth > expected.max_write_lock_recursion_depth || + stats.max_write_lock_recursion_depth < 1 || + stats.write_locks_delayed < expected.write_locks_delayed || + stats.max_write_locks_pending > expected.max_write_locks_pending) { + TestErrPrintf("Unexpected recursive R/W lock stats"); + H5TS__rw_lock_print_stats("Actual stats", &stats); + H5TS__rw_lock_print_stats("Expected stats", &expected); + } + /* clang-format on */ + + if (verbose) + H5TS__rw_lock_print_stats("Actual stats", &stats); +#endif + + /* 7) Shut down the recursive R/W lock. */ + result = H5TS__rw_lock_destroy(&rec_rw_lock); + CHECK_I(result, "H5TS__rw_lock_destroy"); + + /* discard the udata if it exists */ + if (udata) + free(udata); +} /* end tts_rec_rw_lock_smoke_check_4() */ + +#endif /* H5_HAVE_WIN_THREADS */ +#endif /* H5_HAVE_THREADS */ diff --git a/tools/lib/h5diff.c b/tools/lib/h5diff.c index bd8112f2c65..60dc5595aef 100644 --- a/tools/lib/h5diff.c +++ b/tools/lib/h5diff.c @@ -1746,7 +1746,7 @@ handle_worker_request(char *worker_tasks, int *n_busy_tasks, diff_opt_t *opts, h MPI_Status status; int task_idx = 0; int source = 0; - herr_t ret_value = H5DIFF_NO_ERR; + diff_err_t ret_value = H5DIFF_NO_ERR; /* Must have at least one busy worker task */ assert(*n_busy_tasks > 0);