mirror of
https://github.com/HDFGroup/hdf5.git
synced 2026-09-25 04:09:44 +03:00
Implement fallback for systems without qsort_r (#5931)
Also includes a new workflow to test FreeBSD, which has a different qsort signature and was previously untested Resolves #5896
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
name: FreeBSD CI
|
||||
|
||||
# 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'
|
||||
- 'LICENSE**'
|
||||
- '**.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:
|
||||
freebsd-build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
name: FreeBSD ${{ matrix.freebsd-version }} Build and Test
|
||||
|
||||
# Don't run the action if the commit message says to skip CI
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci')"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
freebsd-version: ['13.5', '14.3', '15.0']
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Build and test on FreeBSD
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
release: ${{ matrix.freebsd-version }}
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install -y cmake ninja pkgconf bash curl
|
||||
run: |
|
||||
set -e
|
||||
|
||||
# Configure the build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -C ../config/cmake/cacheinit.cmake \
|
||||
-G Ninja \
|
||||
--log-level=VERBOSE \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS:BOOL=ON \
|
||||
-DHDF5_ENABLE_ALL_WARNINGS:BOOL=ON \
|
||||
-DHDF5_ENABLE_PARALLEL:BOOL=OFF \
|
||||
-DHDF5_BUILD_CPP_LIB:BOOL=ON \
|
||||
-DHDF5_BUILD_FORTRAN:BOOL=OFF \
|
||||
-DHDF5_BUILD_JAVA:BOOL=OFF \
|
||||
-DHDF5_BUILD_DOC:BOOL=OFF \
|
||||
-DHDF5_ENABLE_ZLIB_SUPPORT:BOOL=ON \
|
||||
-DHDF5_ENABLE_SZIP_SUPPORT:BOOL=ON \
|
||||
-DLIBAEC_USE_LOCALCONTENT:BOOL=OFF \
|
||||
-DZLIB_USE_LOCALCONTENT:BOOL=OFF \
|
||||
-DHDF5_TEST_API:BOOL=ON \
|
||||
-DHDF5_TEST_SHELL_SCRIPTS:BOOL=OFF \
|
||||
-DENABLE_EXTENDED_TESTS:BOOL=OFF \
|
||||
..
|
||||
echo ""
|
||||
|
||||
# Build
|
||||
cmake --build . --parallel 3 --config Release
|
||||
echo ""
|
||||
|
||||
# Run tests
|
||||
ctest . --parallel 2 -C Release -V
|
||||
echo ""
|
||||
@@ -0,0 +1,94 @@
|
||||
name: OpenBSD CI
|
||||
|
||||
# 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'
|
||||
- 'LICENSE**'
|
||||
- '**.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:
|
||||
openbsd-build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
name: OpenBSD ${{ matrix.openbsd-version }} Build and Test
|
||||
|
||||
# Don't run the action if the commit message says to skip CI
|
||||
if: "!contains(github.event.head_commit.message, 'skip-ci')"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
openbsd-version: ['7.5']
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Build and test on OpenBSD
|
||||
uses: vmactions/openbsd-vm@v1
|
||||
with:
|
||||
release: ${{ matrix.openbsd-version }}
|
||||
usesh: true
|
||||
prepare: |
|
||||
echo "https://ftp.openbsd.org/pub/OpenBSD" > /etc/installurl
|
||||
pkg_add cmake gmake pkgconf curl gcc-11.2.0p11
|
||||
run: |
|
||||
set -e
|
||||
|
||||
# Set up library path for gcc
|
||||
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
|
||||
|
||||
# Get number of processors (OpenBSD uses sysctl in /sbin)
|
||||
NPROC=$(/sbin/sysctl -n hw.ncpu)
|
||||
echo "Number of processors: $NPROC"
|
||||
|
||||
# Configure the build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -C ../config/cmake/cacheinit.cmake \
|
||||
--log-level=VERBOSE \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=egcc \
|
||||
-DCMAKE_CXX_COMPILER=eg++ \
|
||||
-DCMAKE_MAKE_PROGRAM=gmake \
|
||||
-DBUILD_SHARED_LIBS:BOOL=ON \
|
||||
-DHDF5_ENABLE_ALL_WARNINGS:BOOL=ON \
|
||||
-DHDF5_ENABLE_PARALLEL:BOOL=OFF \
|
||||
-DHDF5_BUILD_CPP_LIB:BOOL=OFF \
|
||||
-DHDF5_BUILD_FORTRAN:BOOL=OFF \
|
||||
-DHDF5_BUILD_JAVA:BOOL=OFF \
|
||||
-DHDF5_BUILD_DOC:BOOL=OFF \
|
||||
-DHDF5_BUILD_HL_LIB:BOOL=OFF \
|
||||
-DHDF5_ENABLE_ZLIB_SUPPORT:BOOL=ON \
|
||||
-DHDF5_ENABLE_SZIP_SUPPORT:BOOL=ON \
|
||||
-DLIBAEC_USE_LOCALCONTENT:BOOL=OFF \
|
||||
-DZLIB_USE_LOCALCONTENT:BOOL=OFF \
|
||||
-DHDF5_TEST_API:BOOL=ON \
|
||||
-DHDF5_TEST_SHELL_SCRIPTS:BOOL=OFF \
|
||||
-DENABLE_EXTENDED_TESTS:BOOL=OFF \
|
||||
..
|
||||
echo ""
|
||||
|
||||
# Build
|
||||
cmake --build . --parallel $NPROC
|
||||
echo ""
|
||||
|
||||
# Run tests
|
||||
ctest . --parallel $NPROC
|
||||
echo ""
|
||||
@@ -443,6 +443,13 @@ CHECK_FUNCTION_EXISTS (asprintf ${HDF_PREFIX}_HAVE_ASPRINTF)
|
||||
CHECK_FUNCTION_EXISTS (vasprintf ${HDF_PREFIX}_HAVE_VASPRINTF)
|
||||
CHECK_FUNCTION_EXISTS (waitpid ${HDF_PREFIX}_HAVE_WAITPID)
|
||||
|
||||
# Check for reentrant qsort variants (qsort_r on Unix/BSD, qsort_s on Windows)
|
||||
CHECK_FUNCTION_EXISTS (qsort_r _HAVE_QSORT_R_TMP)
|
||||
CHECK_FUNCTION_EXISTS (qsort_s _HAVE_QSORT_S_TMP)
|
||||
if (_HAVE_QSORT_R_TMP OR _HAVE_QSORT_S_TMP)
|
||||
set (${HDF_PREFIX}_HAVE_QSORT_REENTRANT 1)
|
||||
endif ()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# sigsetjmp is special; may actually be a macro
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
+8
-1
@@ -394,7 +394,9 @@ H5RT__bulk_load(H5RT_node_t *node, int rank, H5RT_leaf_t *leaves, size_t count,
|
||||
if (prev_sort_dim != rank - 1) {
|
||||
assert(prev_sort_dim < rank - 1);
|
||||
sort_dim = prev_sort_dim + 1;
|
||||
HDqsort_r((void *)leaves, count, sizeof(H5RT_leaf_t), H5RT__leaf_compare, (void *)&sort_dim);
|
||||
if (H5_UNLIKELY(HDqsort_r((void *)leaves, count, sizeof(H5RT_leaf_t), H5RT__leaf_compare,
|
||||
(void *)&sort_dim) < 0))
|
||||
HGOTO_ERROR(H5E_INTERNAL, H5E_CANTSORT, FAIL, "failed to sort R-tree leaves");
|
||||
}
|
||||
else {
|
||||
sort_dim = prev_sort_dim;
|
||||
@@ -459,6 +461,11 @@ done:
|
||||
* On success, the R-tree takes ownership of the caller-allocated
|
||||
* leaves array.
|
||||
*
|
||||
* NOTE: This routine uses a global variable internally, and
|
||||
* is therefore not thread-safe. See the 'qsort_r_threadsafe'
|
||||
* branch of the HDF5 GitHub repository for a beta
|
||||
* implementation that is threadsafe.
|
||||
*
|
||||
* Return: A valid pointer to the new R-tree on success/NULL on failure
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
|
||||
+16
-4
@@ -650,8 +650,13 @@ H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation);
|
||||
#endif /* HDflock */
|
||||
|
||||
#if defined(H5_HAVE_WIN32_API) || defined(H5_HAVE_DARWIN) || (defined(__FreeBSD__) && __FreeBSD__ < 14)
|
||||
H5_DLL void HDqsort_context(void *base, size_t nel, size_t size,
|
||||
int (*compar)(const void *, const void *, void *), void *arg);
|
||||
H5_DLL herr_t HDqsort_context(void *base, size_t nel, size_t size,
|
||||
int (*compar)(const void *, const void *, void *), void *arg);
|
||||
#endif
|
||||
|
||||
#ifndef H5_HAVE_QSORT_REENTRANT
|
||||
H5_DLL herr_t HDqsort_fallback(void *base, size_t nel, size_t size,
|
||||
int (*compar)(const void *, const void *, void *), void *arg);
|
||||
#endif
|
||||
|
||||
#ifndef HDfseek
|
||||
@@ -770,10 +775,17 @@ H5_DLL void HDqsort_context(void *base, size_t nel, size_t size,
|
||||
#define HDunsetenv(S) unsetenv(S)
|
||||
#endif
|
||||
#ifndef HDqsort_r
|
||||
#ifdef H5_HAVE_DARWIN
|
||||
#ifdef H5_HAVE_QSORT_REENTRANT
|
||||
#if defined(H5_HAVE_DARWIN) || (defined(__FreeBSD__) && __FreeBSD__ < 14)
|
||||
/* Darwin and FreeBSD < 14 use BSD-style qsort_r with different signature/argument order */
|
||||
#define HDqsort_r(B, N, S, C, A) HDqsort_context(B, N, S, C, A)
|
||||
#else
|
||||
#define HDqsort_r(B, N, S, C, A) qsort_r(B, N, S, C, A)
|
||||
/* Wrap native GNU qsort_r to vacuously return success */
|
||||
#define HDqsort_r(B, N, S, C, A) (qsort_r(B, N, S, C, A), SUCCEED)
|
||||
#endif
|
||||
#else
|
||||
/* No native qsort_r/qsort_s available - use fallback implementation */
|
||||
#define HDqsort_r(B, N, S, C, A) HDqsort_fallback(B, N, S, C, A)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef HDvasprintf
|
||||
|
||||
@@ -258,6 +258,9 @@
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#cmakedefine H5_HAVE_PWD_H @H5_HAVE_PWD_H@
|
||||
|
||||
/* Define to 1 if you have a reentrant qsort function (qsort_r or qsort_s). */
|
||||
#cmakedefine H5_HAVE_QSORT_REENTRANT @H5_HAVE_QSORT_REENTRANT@
|
||||
|
||||
/* Define whether the Read-Only S3 virtual file driver (VFD) should be
|
||||
compiled */
|
||||
#cmakedefine H5_HAVE_ROS3_VFD @H5_HAVE_ROS3_VFD@
|
||||
|
||||
+49
-1
@@ -1441,7 +1441,7 @@ HDqsort_context_wrapper_func(void *wrapper_arg, const void *a, const void *b)
|
||||
return w->gnu_compar(a, b, w->gnu_arg);
|
||||
}
|
||||
|
||||
void
|
||||
herr_t
|
||||
HDqsort_context(void *base, size_t nel, size_t size, int (*compar)(const void *, const void *, void *),
|
||||
void *arg)
|
||||
{
|
||||
@@ -1454,5 +1454,53 @@ HDqsort_context(void *base, size_t nel, size_t size, int (*compar)(const void *,
|
||||
/* Old BSD-style: context parameter comes before comparator function */
|
||||
qsort_r(base, nel, size, &wrapper, HDqsort_context_wrapper_func);
|
||||
#endif
|
||||
return SUCCEED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* HDqsort_fallback - Fallback qsort implementation for platforms without qsort_r/qsort_s
|
||||
*
|
||||
* This implementation is not threadsafe, since it uses a global variable to store the
|
||||
* comparator context, then uses standard qsort(). A beta branch of a threadsafe implementation
|
||||
* of these routines may be found in the 'qsort_r_threadsafe' branch of the HDF5 GitHub repository.
|
||||
*
|
||||
*/
|
||||
#ifndef H5_HAVE_QSORT_REENTRANT
|
||||
|
||||
typedef struct HDqsort_fallback_context_t {
|
||||
int (*gnu_compar)(const void *, const void *, void *);
|
||||
void *gnu_arg;
|
||||
} HDqsort_fallback_context_t;
|
||||
|
||||
/* Non-threadsafe: use global variable */
|
||||
static HDqsort_fallback_context_t *HDqsort_fallback_global_ctx = NULL;
|
||||
|
||||
static int
|
||||
HDqsort_fallback_wrapper(const void *a, const void *b)
|
||||
{
|
||||
/* Call the original GNU-style comparator with context from global */
|
||||
return HDqsort_fallback_global_ctx->gnu_compar(a, b, HDqsort_fallback_global_ctx->gnu_arg);
|
||||
}
|
||||
|
||||
herr_t
|
||||
HDqsort_fallback(void *base, size_t nel, size_t size, int (*compar)(const void *, const void *, void *),
|
||||
void *arg)
|
||||
{
|
||||
HDqsort_fallback_context_t ctx;
|
||||
|
||||
ctx.gnu_compar = compar;
|
||||
ctx.gnu_arg = arg;
|
||||
|
||||
/* Store context in global variable */
|
||||
HDqsort_fallback_global_ctx = &ctx;
|
||||
|
||||
qsort(base, nel, size, HDqsort_fallback_wrapper);
|
||||
|
||||
/* Clear the global pointer */
|
||||
HDqsort_fallback_global_ctx = NULL;
|
||||
|
||||
return SUCCEED;
|
||||
}
|
||||
|
||||
#endif /* !H5_HAVE_QSORT_REENTRANT */
|
||||
|
||||
Reference in New Issue
Block a user