Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .github/workflows/freebsd.yml
Original file line number Diff line number Diff line change
@@ -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 ""
94 changes: 94 additions & 0 deletions .github/workflows/openbsd.yml
Original file line number Diff line number Diff line change
@@ -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 ""
7 changes: 7 additions & 0 deletions config/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
#-----------------------------------------------------------------------------
Expand Down
9 changes: 8 additions & 1 deletion src/H5RT.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -459,6 +461,11 @@ H5RT__bulk_load(H5RT_node_t *node, int rank, H5RT_leaf_t *leaves, size_t count,
* 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
*
*-------------------------------------------------------------------------
Expand Down
20 changes: 16 additions & 4 deletions src/H5private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the near future we should probably move this into something we try to check at configure time. I imagine there are other platforms that use this signature and checking at configure time should get rid of platform-specific #ifdefs and also avoid needing the (probably minor) overhead of a fallback function. Maybe something like https://gitlab.gnome.org/GNOME/glib/-/blob/2.30.0/configure.ac?ref_type=tags#L589-627.

/* 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
Expand Down
3 changes: 3 additions & 0 deletions src/H5pubconf.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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@
Expand Down
50 changes: 49 additions & 1 deletion src/H5system.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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 */
Loading