summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--config/cmake/H5pubconf.h.in3
-rw-r--r--config/cmake_ext_mod/ConfigureChecks.cmake1
-rw-r--r--configure.ac134
-rw-r--r--src/H5FD.c40
-rw-r--r--src/H5FDpublic.h16
-rw-r--r--src/H5FDvfd_swmr.h7
-rw-r--r--src/H5FDvfd_swmr_private.h6
-rw-r--r--src/H5Fpkg.h3
-rw-r--r--src/H5private.h7
-rw-r--r--src/H5queue.h369
-rw-r--r--test/CMakeLists.txt8
-rw-r--r--test/vfd_swmr_common.c87
-rw-r--r--test/vfd_swmr_common.h6
14 files changed, 320 insertions, 372 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac291fa..b6e0044 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -816,8 +816,13 @@ if (HDF5_ENABLE_THREADSAFE)
if (Threads_FOUND)
set (H5_HAVE_THREADSAFE 1)
endif ()
+else()
+ # Always check for pthreads for VFD SWMR (for now)
+ set (THREADS_PREFER_PTHREAD_FLAG ON)
+ find_package (Threads REQUIRED)
endif ()
+
#-----------------------------------------------------------------------------
# Option to build the map API
#-----------------------------------------------------------------------------
diff --git a/config/cmake/H5pubconf.h.in b/config/cmake/H5pubconf.h.in
index 56cc264..24adb1a 100644
--- a/config/cmake/H5pubconf.h.in
+++ b/config/cmake/H5pubconf.h.in
@@ -355,6 +355,9 @@
/* Define to 1 if you have the `sigsetjmp' function. */
#cmakedefine H5_HAVE_SIGSETJMP @H5_HAVE_SIGSETJMP@
+/* Define to 1 if you have the `sigtimedwait' function. */
+#cmakedefine H5_HAVE_SIGTIMEDWAIT @H5_HAVE_SIGTIMEDWAIT@
+
/* Define to 1 if you have the `snprintf' function. */
#cmakedefine H5_HAVE_SNPRINTF @H5_HAVE_SNPRINTF@
diff --git a/config/cmake_ext_mod/ConfigureChecks.cmake b/config/cmake_ext_mod/ConfigureChecks.cmake
index 3a4f711..18aed24 100644
--- a/config/cmake_ext_mod/ConfigureChecks.cmake
+++ b/config/cmake_ext_mod/ConfigureChecks.cmake
@@ -519,6 +519,7 @@ CHECK_FUNCTION_EXISTS (setjmp ${HDF_PREFIX}_HAVE_SETJMP)
CHECK_FUNCTION_EXISTS (siglongjmp ${HDF_PREFIX}_HAVE_SIGLONGJMP)
CHECK_FUNCTION_EXISTS (sigsetjmp ${HDF_PREFIX}_HAVE_SIGSETJMP)
CHECK_FUNCTION_EXISTS (sigprocmask ${HDF_PREFIX}_HAVE_SIGPROCMASK)
+CHECK_FUNCTION_EXISTS (sigtimedwait ${HDF_PREFIX}_HAVE_SIGTIMEDWAIT)
CHECK_FUNCTION_EXISTS (snprintf ${HDF_PREFIX}_HAVE_SNPRINTF)
CHECK_FUNCTION_EXISTS (srandom ${HDF_PREFIX}_HAVE_SRANDOM)
diff --git a/configure.ac b/configure.ac
index bb5561e..9e241a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1750,84 +1750,78 @@ esac
if test "X$THREADSAFE" = "Xyes"; then
AC_DEFINE([HAVE_THREADSAFE], [1], [Define if we have thread safe support])
+fi
- ## ----------------------------------------------------------------------
- ## Is the Pthreads library present? It has a header file `pthread.h' and
- ## a library `-lpthread' and their locations might be specified with the
- ## `--with-pthread' command-line switch. The value is an include path
- ## and/or a library path. If the library path is specified then it must
- ## be preceded by a comma.
- ##
- ## Thread-safety in HDF5 only uses Pthreads via configure, so the
- ## default is "check", though this only has an effect when
- ## --enable-threadsafe is specified.
- AC_SUBST([HAVE_PTHREAD]) HAVE_PTHREAD=yes
- AC_ARG_WITH([pthread],
- [AS_HELP_STRING([--with-pthread=DIR],
- [Specify alternative path to Pthreads library when
- thread-safe capability is built.])],,
- [withval=check])
+## ----------------------------------------------------------------------
+## Is the Pthreads library present? It has a header file `pthread.h' and
+## a library `-lpthread' and their locations might be specified with the
+## `--with-pthread' command-line switch. The value is an include path
+## and/or a library path. If the library path is specified then it must
+## be preceded by a comma.
+AC_SUBST([HAVE_PTHREAD])
+
+AC_ARG_WITH([pthread],
+ [AS_HELP_STRING([--with-pthread=DIR],
+ [Specify alternative path to Pthreads library when
+ thread-safe capability is built.])],,
+ [withval=check])
+case "$withval" in
+ check | yes)
+ AC_CHECK_HEADERS([pthread.h],,)
+ AC_CHECK_LIB([pthread], [pthread_self])
+ ;;
+ no)
+ AC_MSG_RESULT([suppressed])
+ ;;
+ *)
case "$withval" in
- check | yes)
- AC_CHECK_HEADERS([pthread.h],, [unset HAVE_PTHREAD])
- if test "x$HAVE_PTHREAD" = "xyes"; then
- AC_CHECK_LIB([pthread], [pthread_self],, [unset HAVE_PTHREAD])
- fi
- ;;
- no)
- AC_MSG_ERROR([Must use Pthreads with thread safety])
+ *,*)
+ pthread_inc="`echo $withval | cut -f1 -d,`"
+ pthread_lib="`echo $withval | cut -f2 -d, -s`"
;;
*)
- case "$withval" in
- *,*)
- pthread_inc="`echo $withval | cut -f1 -d,`"
- pthread_lib="`echo $withval | cut -f2 -d, -s`"
- ;;
- *)
- if test -n "$withval"; then
- pthread_inc="$withval/include"
- pthread_lib="$withval/lib"
- fi
- ;;
- esac
-
- if test -n "$pthread_inc"; then
- saved_CPPFLAGS="$CPPFLAGS"
- saved_AM_CPPFLAGS="$AM_CPPFLAGS"
- CPPFLAGS="$CPPFLAGS -I$pthread_inc"
- AM_CPPFLAGS="$AM_CPPFLAGS -I$pthread_inc"
- AC_CHECK_HEADERS([pthread.h],, [CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"; unset HAVE_PTHREAD])
- else
- AC_CHECK_HEADERS([pthread.h],, [unset HAVE_PTHREAD])
- fi
-
- if test "x$HAVE_PTHREAD" = "xyes"; then
- if test -n "$pthread_lib"; then
- saved_LDFLAGS="$LDFLAGS"
- saved_AM_LDFLAGS="$AM_LDFLAGS"
- LDFLAGS="$LDFLAGS -L$pthread_lib"
- AM_LDFLAGS="$AM_LDFLAGS -L$pthread_lib"
- AC_CHECK_LIB([pthread], [pthread_self],,
- [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset HAVE_PTHREAD])
- else
- AC_CHECK_LIB([pthread], [pthread_self],, [unset HAVE_PTHREAD])
- fi
+ if test -n "$withval"; then
+ pthread_inc="$withval/include"
+ pthread_lib="$withval/lib"
fi
;;
esac
- ## ----------------------------------------------------------------------
- ## Check if pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM)
- ## is supported on this system
- ##
- ## Unfortunately, this probably needs to be an AC_RUN_IFELSE since
- ## it's impossible to determine if PTHREAD_SCOPE_SYSTEM is
- ## supported a priori. POSIX.1-2001 requires that a conformant
- ## system need only support one of SYSTEM or PROCESS scopes.
- ##
- ## For cross-compiling, we've added a pessimistic 'no'. You can
- ## hand-hack the config file if you know otherwise.
+ if test -n "$pthread_inc"; then
+ saved_CPPFLAGS="$CPPFLAGS"
+ saved_AM_CPPFLAGS="$AM_CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -I$pthread_inc"
+ AM_CPPFLAGS="$AM_CPPFLAGS -I$pthread_inc"
+ AC_CHECK_HEADERS([pthread.h],,[CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS";])
+ else
+ AC_CHECK_HEADERS([pthread.h])
+ fi
+
+ if test -n "$pthread_lib"; then
+ saved_LDFLAGS="$LDFLAGS"
+ saved_AM_LDFLAGS="$AM_LDFLAGS"
+ LDFLAGS="$LDFLAGS -L$pthread_lib"
+ AM_LDFLAGS="$AM_LDFLAGS -L$pthread_lib"
+ AC_CHECK_LIB([pthread], [pthread_self],,[LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS";])
+ else
+ AC_CHECK_LIB([pthread], [pthread_self])
+ fi
+ ;;
+esac
+
+## ----------------------------------------------------------------------
+## Check if pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM)
+## is supported on this system
+##
+## Unfortunately, this probably needs to be an AC_RUN_IFELSE since
+## it's impossible to determine if PTHREAD_SCOPE_SYSTEM is
+## supported a priori. POSIX.1-2001 requires that a conformant
+## system need only support one of SYSTEM or PROCESS scopes.
+##
+## For cross-compiling, we've added a pessimistic 'no'. You can
+## hand-hack the config file if you know otherwise.
+if test "x$HAVE_PTHREAD" = "xyes"; then
AC_MSG_CHECKING([Pthreads supports system scope])
AC_CACHE_VAL([hdf5_cv_system_scope_threads],
[AC_RUN_IFELSE(
@@ -1964,7 +1958,7 @@ AC_CHECK_FUNCS([alarm clock_gettime difftime fcntl flock fork frexpf])
AC_CHECK_FUNCS([frexpl gethostname getrusage gettimeofday])
AC_CHECK_FUNCS([lstat rand_r random setsysinfo])
AC_CHECK_FUNCS([signal longjmp setjmp siglongjmp sigsetjmp sigprocmask])
-AC_CHECK_FUNCS([snprintf srandom strdup symlink system])
+AC_CHECK_FUNCS([sigtimedwait snprintf srandom strdup symlink system])
AC_CHECK_FUNCS([strtoll strtoull])
AC_CHECK_FUNCS([tmpfile asprintf vasprintf vsnprintf waitpid])
AC_CHECK_FUNCS([roundf lroundf llroundf round lround llround])
diff --git a/src/H5FD.c b/src/H5FD.c
index 602b198..f34a2ec 100644
--- a/src/H5FD.c
+++ b/src/H5FD.c
@@ -54,6 +54,11 @@
/* Package Typedefs */
/********************/
+/* H5FD wrapper for VFD SWMR. Allows use as a BSD TAILQ element. */
+typedef struct H5FD_wrap_t {
+ TAILQ_ENTRY(H5FD_wrap_t) link; /* Linkage for list of all VFDs. */
+ H5FD_t *file; /* Pointer to wrapped VFD struct */
+} H5FD_wrap_t;
/********************/
/* Local Prototypes */
@@ -92,7 +97,7 @@ hbool_t H5_PKG_INIT_VAR = FALSE;
*/
static unsigned long H5FD_file_serial_no_g;
-static TAILQ_HEAD(_all_vfds, H5FD_t) all_vfds = TAILQ_HEAD_INITIALIZER(all_vfds);
+static TAILQ_HEAD(_all_vfds, H5FD_wrap_t) all_vfds = TAILQ_HEAD_INITIALIZER(all_vfds);
/* File driver ID class */
static const H5I_class_t H5I_VFL_CLS[1] = {{
@@ -726,18 +731,19 @@ H5FD_dedup(H5FD_t *self, H5FD_t *other, hid_t fapl)
H5FD_t *
H5FD_deduplicate(H5FD_t *file, hid_t fapl)
{
- H5FD_t *deduped = file, *item;
+ H5FD_t *deduped = file;
+ H5FD_wrap_t *item;
TAILQ_FOREACH(item, &all_vfds, link) {
/* skip "self" */
- if (item == file)
+ if (item->file == file)
continue;
/* skip files with exclusive owners, for now */
- if (item->exc_owner != NULL)
+ if (item->file->exc_owner != NULL)
continue;
- if ((deduped = H5FD_dedup(item, file, fapl)) != file)
+ if ((deduped = H5FD_dedup(item->file, file, fapl)) != file)
goto finish;
}
@@ -746,10 +752,10 @@ H5FD_deduplicate(H5FD_t *file, hid_t fapl)
* return NULL to indicate the conflict.
*/
TAILQ_FOREACH(item, &all_vfds, link) {
- if (item == file || item->exc_owner == NULL)
+ if (item->file == file || item->file->exc_owner == NULL)
continue;
- if (H5FDcmp(file, item) == 0) {
+ if (H5FDcmp(file, item->file) == 0) {
deduped = NULL;
break;
}
@@ -784,6 +790,7 @@ H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
H5P_genplist_t *plist; /* Property list pointer */
unsigned long driver_flags = 0; /* File-inspecific driver feature flags */
H5FD_file_image_info_t file_image_info; /* Initial file image */
+ H5FD_wrap_t *swmr_wrapper = NULL; /* H5FD wrapper for SWMR queue */
H5FD_t *ret_value = NULL; /* Return value */
FUNC_ENTER_NOAPI(NULL)
@@ -862,7 +869,11 @@ H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr)
/* (This will be changed later, when the superblock is located) */
file->base_addr = 0;
- TAILQ_INSERT_TAIL(&all_vfds, file, link);
+ /* Create and insert a SWMR wrapper for the file */
+ if(NULL == (swmr_wrapper = H5MM_calloc(sizeof(H5FD_wrap_t))))
+ HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, NULL, "unable to allocate file wrap struct")
+ swmr_wrapper->file = file;
+ TAILQ_INSERT_TAIL(&all_vfds, swmr_wrapper, link);
/* Set return value */
ret_value = file;
@@ -923,7 +934,8 @@ herr_t
H5FD_close(H5FD_t *file)
{
const H5FD_class_t *driver;
- H5FD_t *item;
+ H5FD_wrap_t *item;
+ H5FD_wrap_t *delete_me = NULL;
herr_t ret_value = SUCCEED;
FUNC_ENTER_NOAPI(FAIL)
@@ -938,10 +950,14 @@ H5FD_close(H5FD_t *file)
HGOTO_ERROR(H5E_VFL, H5E_CANTDEC, FAIL, "can't close driver ID")
TAILQ_FOREACH(item, &all_vfds, link) {
- if (item->exc_owner == file)
- item->exc_owner = NULL;
+ if (item->file->exc_owner == file)
+ item->file->exc_owner = NULL;
+ if (item->file == file)
+ delete_me = item;
}
- TAILQ_REMOVE(&all_vfds, file, link);
+ HDassert(delete_me);
+ TAILQ_REMOVE(&all_vfds, delete_me, link);
+ H5MM_xfree(delete_me);
/* Dispatch to the driver for actual close. If the driver fails to
* close the file then the file will be in an unusable state.
diff --git a/src/H5FDpublic.h b/src/H5FDpublic.h
index a921c29..520668b 100644
--- a/src/H5FDpublic.h
+++ b/src/H5FDpublic.h
@@ -18,7 +18,6 @@
#ifndef _H5FDpublic_H
#define _H5FDpublic_H
-#include "H5queue.h"
#include "H5public.h"
#include "H5Fpublic.h" /*for H5F_close_degree_t */
@@ -319,19 +318,18 @@ typedef struct H5FD_free_t {
* are declared here and the driver appends private fields in memory.
*/
struct H5FD_t {
- hid_t driver_id; /*driver ID for this file */
- const H5FD_class_t *cls; /*constant class info */
-
- TAILQ_ENTRY(H5FD_t) link; /* Linkage for list of all VFs. */
- H5FD_t *exc_owner; /* Pointer to an exclusive owner
- * or NULL if none.
- */
- unsigned long fileno; /* File 'serial' number */
+ hid_t driver_id; /* Driver ID for this file */
+ const H5FD_class_t *cls; /* Constant class info */
+ unsigned long fileno; /* File 'serial' number */
unsigned access_flags; /* File access flags (from create or open) */
unsigned long feature_flags; /* VFL Driver feature Flags */
haddr_t maxaddr; /* For this file, overrides class */
haddr_t base_addr; /* Base address for HDF5 data w/in file */
+ H5FD_t *exc_owner; /* Pointer to an exclusive owner
+ * or NULL if none.
+ */
+
/* Space allocation management fields */
hsize_t threshold; /* Threshold for alignment */
hsize_t alignment; /* Allocation alignment */
diff --git a/src/H5FDvfd_swmr.h b/src/H5FDvfd_swmr.h
index 86e9d0f..7d3b966 100644
--- a/src/H5FDvfd_swmr.h
+++ b/src/H5FDvfd_swmr.h
@@ -14,8 +14,8 @@
/*
* The public header file for the VFD SWMR driver.
*/
-#ifndef H5FDswmr_H
-#define H5FDswmr_H
+#ifndef H5FDvfd_swmr_H
+#define H5FDvfd_swmr_H
#include "H5api_adpt.h" /* H5_DLL */
#include "H5public.h" /* uint64_t *ahem* */
@@ -34,5 +34,4 @@ H5_DLL herr_t H5Pset_fapl_vfd_swmr(hid_t fapl_id);
}
#endif
-#endif
-
+#endif /* H5FDvfd_swmr_H */
diff --git a/src/H5FDvfd_swmr_private.h b/src/H5FDvfd_swmr_private.h
index 551adaa..e2270b9 100644
--- a/src/H5FDvfd_swmr_private.h
+++ b/src/H5FDvfd_swmr_private.h
@@ -9,8 +9,8 @@
* help@hdfgroup.org.
*/
-#ifndef _H5FDvfd_swmr_private_H
-#define _H5FDvfd_swmr_private_H
+#ifndef H5FDvfd_swmr_private_H
+#define H5FDvfd_swmr_private_H
#include "H5queue.h" /* for TAILQ_* */
@@ -84,4 +84,4 @@ H5_DLL herr_t H5F_vfd_swmr_insert_entry_eot(struct H5F_t *f);
H5_DLL void H5F_vfd_swmr_update_entry_eot(eot_queue_entry_t *);
H5_DLL herr_t H5F_dump_eot_queue(void);
-#endif /* _H5FDvfd_swmr_private_H */
+#endif /* H5FDvfd_swmr_private_H */
diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h
index 71d0ce4..260a25c 100644
--- a/src/H5Fpkg.h
+++ b/src/H5Fpkg.h
@@ -26,9 +26,6 @@
#ifndef _H5Fpkg_H
#define _H5Fpkg_H
-/* BSD queue macros */
-#include "H5queue.h"
-
/* Get package's private header */
#include "H5Fprivate.h"
diff --git a/src/H5private.h b/src/H5private.h
index 6479032..66763b2 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -171,6 +171,13 @@
#include <dirent.h>
#endif
+/* BSD-style queues
+ *
+ * We use a private copy of netBSD's queues instead of including sys/queue.h
+ * due to irreconcilable differences between different queue implementations.
+ */
+#include "H5queue.h"
+
/* Define the default VFD for this platform.
* Since the removal of the Windows VFD, this is sec2 for all platforms.
*/
diff --git a/src/H5queue.h b/src/H5queue.h
index 816acca..bef7ef7 100644
--- a/src/H5queue.h
+++ b/src/H5queue.h
@@ -31,8 +31,29 @@
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
-#ifndef _SYS_QUEUE_H_
-#define _SYS_QUEUE_H_
+#ifndef H5queue_H_
+#define H5queue_H_
+
+/* This is a copy of netBSD's sys/queue.h header for use in HDF5. We've copied
+ * it here instead of using the system's version to avoid incompatibilities.
+ * The exception is MacOS, where other system headers make use of sys/queue.h
+ * (this may also be an issue on FreeBSD, et al.).
+ *
+ * The deprecated and unwise circular queue macros have been removed from
+ * this file to discourage their use.
+ */
+
+
+/* On MacOS, sys/file.h (needed for flock(3)) includes sys.queue.h, so we
+ * can't just use an alternative BSD queue implementation without running
+ * into symbol redefinition errors.
+ *
+ * Unfortunately, MacOS is missing SIMPLEQ, so we have to handle that
+ * separately later in the file.
+ */
+#if defined(__APPLE__)
+#include <sys/queue.h>
+#else
/*
* This file defines five types of data structures: singly-linked lists,
@@ -296,106 +317,6 @@ struct { \
} while (/*CONSTCOND*/0)
/*
- * Simple queue definitions.
- */
-#define SIMPLEQ_HEAD(name, type) \
-struct name { \
- struct type *sqh_first; /* first element */ \
- struct type **sqh_last; /* addr of last next element */ \
-}
-
-#define SIMPLEQ_HEAD_INITIALIZER(head) \
- { NULL, &(head).sqh_first }
-
-#define SIMPLEQ_ENTRY(type) \
-struct { \
- struct type *sqe_next; /* next element */ \
-}
-
-/*
- * Simple queue access methods.
- */
-#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
-#define SIMPLEQ_END(head) NULL
-#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
-#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
-
-#define SIMPLEQ_FOREACH(var, head, field) \
- for ((var) = ((head)->sqh_first); \
- (var) != SIMPLEQ_END(head); \
- (var) = ((var)->field.sqe_next))
-
-#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
- for ((var) = ((head)->sqh_first); \
- (var) != SIMPLEQ_END(head) && \
- ((next = ((var)->field.sqe_next)), 1); \
- (var) = (next))
-
-/*
- * Simple queue functions.
- */
-#define SIMPLEQ_INIT(head) do { \
- (head)->sqh_first = NULL; \
- (head)->sqh_last = &(head)->sqh_first; \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
- if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
- (head)->sqh_last = &(elm)->field.sqe_next; \
- (head)->sqh_first = (elm); \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
- (elm)->field.sqe_next = NULL; \
- *(head)->sqh_last = (elm); \
- (head)->sqh_last = &(elm)->field.sqe_next; \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
- if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
- (head)->sqh_last = &(elm)->field.sqe_next; \
- (listelm)->field.sqe_next = (elm); \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
- if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
- (head)->sqh_last = &(head)->sqh_first; \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
- if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
- == NULL) \
- (head)->sqh_last = &(elm)->field.sqe_next; \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
- if ((head)->sqh_first == (elm)) { \
- SIMPLEQ_REMOVE_HEAD((head), field); \
- } else { \
- struct type *curelm = (head)->sqh_first; \
- while (curelm->field.sqe_next != (elm)) \
- curelm = curelm->field.sqe_next; \
- if ((curelm->field.sqe_next = \
- curelm->field.sqe_next->field.sqe_next) == NULL) \
- (head)->sqh_last = &(curelm)->field.sqe_next; \
- } \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_CONCAT(head1, head2) do { \
- if (!SIMPLEQ_EMPTY((head2))) { \
- *(head1)->sqh_last = (head2)->sqh_first; \
- (head1)->sqh_last = (head2)->sqh_last; \
- SIMPLEQ_INIT((head2)); \
- } \
-} while (/*CONSTCOND*/0)
-
-#define SIMPLEQ_LAST(head, type, field) \
- (SIMPLEQ_EMPTY((head)) ? \
- NULL : \
- ((struct type *)(void *) \
- ((char *)((head)->sqh_last) - offsetof(struct type, field))))
-
-/*
* Tail queue definitions.
*/
#define _TAILQ_HEAD(name, type, qual) \
@@ -656,192 +577,106 @@ struct { \
((struct type *)(void *) \
((char *)((head)->stqh_last) - offsetof(struct type, field))))
-
-#ifndef _KERNEL
-/*
- * Circular queue definitions. Do not use. We still keep the macros
- * for compatibility but because of pointer aliasing issues their use
- * is discouraged!
- */
+#endif /* defined(__APPLE__) */
/*
- * __launder_type(): We use this ugly hack to work around the the compiler
- * noticing that two types may not alias each other and elide tests in code.
- * We hit this in the CIRCLEQ macros when comparing 'struct name *' and
- * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC
- * 4.8) declare these comparisons as always false, causing the code to
- * not run as designed.
- *
- * This hack is only to be used for comparisons and thus can be fully const.
- * Do not use for assignment.
- *
- * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
- * this by changing the head/tail sentinal values, but see the note above
- * this one.
+ * Simple queue definitions.
*/
-static __inline const void * __launder_type(const void *);
-static __inline const void *
-__launder_type(const void *__x)
-{
- __asm __volatile("" : "+r" (__x));
- return __x;
-}
-
-#if defined(QUEUEDEBUG)
-#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \
- if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \
- (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \
- QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \
- __FILE__, __LINE__); \
- if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \
- (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \
- QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \
- __FILE__, __LINE__);
-#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \
- if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \
- if ((head)->cqh_last != (elm)) \
- QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \
- (elm), __FILE__, __LINE__); \
- } else { \
- if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \
- QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \
- (elm), __FILE__, __LINE__); \
- } \
- if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \
- if ((head)->cqh_first != (elm)) \
- QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \
- (elm), __FILE__, __LINE__); \
- } else { \
- if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \
- QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \
- (elm), __FILE__, __LINE__); \
- }
-#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \
- (elm)->field.cqe_next = (void *)1L; \
- (elm)->field.cqe_prev = (void *)1L;
-#else
-#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field)
-#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field)
-#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field)
-#endif
-
-#define CIRCLEQ_HEAD(name, type) \
+#define SIMPLEQ_HEAD(name, type) \
struct name { \
- struct type *cqh_first; /* first element */ \
- struct type *cqh_last; /* last element */ \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
}
-#define CIRCLEQ_HEAD_INITIALIZER(head) \
- { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
-#define CIRCLEQ_ENTRY(type) \
+#define SIMPLEQ_ENTRY(type) \
struct { \
- struct type *cqe_next; /* next element */ \
- struct type *cqe_prev; /* previous element */ \
+ struct type *sqe_next; /* next element */ \
}
/*
- * Circular queue functions.
+ * Simple queue access methods.
*/
-#define CIRCLEQ_INIT(head) do { \
- (head)->cqh_first = CIRCLEQ_END(head); \
- (head)->cqh_last = CIRCLEQ_END(head); \
-} while (/*CONSTCOND*/0)
-
-#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
- QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
- QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
- (elm)->field.cqe_next = (listelm)->field.cqe_next; \
- (elm)->field.cqe_prev = (listelm); \
- if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
- (head)->cqh_last = (elm); \
- else \
- (listelm)->field.cqe_next->field.cqe_prev = (elm); \
- (listelm)->field.cqe_next = (elm); \
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = ((var)->field.sqe_next))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head) && \
+ ((next = ((var)->field.sqe_next)), 1); \
+ (var) = (next))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
-#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
- QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
- QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \
- (elm)->field.cqe_next = (listelm); \
- (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
- if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
- (head)->cqh_first = (elm); \
- else \
- (listelm)->field.cqe_prev->field.cqe_next = (elm); \
- (listelm)->field.cqe_prev = (elm); \
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
} while (/*CONSTCOND*/0)
-#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
- QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
- (elm)->field.cqe_next = (head)->cqh_first; \
- (elm)->field.cqe_prev = CIRCLEQ_END(head); \
- if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \
- (head)->cqh_last = (elm); \
- else \
- (head)->cqh_first->field.cqe_prev = (elm); \
- (head)->cqh_first = (elm); \
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
} while (/*CONSTCOND*/0)
-#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
- QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
- (elm)->field.cqe_next = CIRCLEQ_END(head); \
- (elm)->field.cqe_prev = (head)->cqh_last; \
- if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \
- (head)->cqh_first = (elm); \
- else \
- (head)->cqh_last->field.cqe_next = (elm); \
- (head)->cqh_last = (elm); \
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
} while (/*CONSTCOND*/0)
-#define CIRCLEQ_REMOVE(head, elm, field) do { \
- QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \
- QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \
- if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
- (head)->cqh_last = (elm)->field.cqe_prev; \
- else \
- (elm)->field.cqe_next->field.cqe_prev = \
- (elm)->field.cqe_prev; \
- if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
- (head)->cqh_first = (elm)->field.cqe_next; \
- else \
- (elm)->field.cqe_prev->field.cqe_next = \
- (elm)->field.cqe_next; \
- QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
-#define CIRCLEQ_FOREACH(var, head, field) \
- for ((var) = ((head)->cqh_first); \
- (var) != CIRCLEQ_ENDC(head); \
- (var) = ((var)->field.cqe_next))
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (/*CONSTCOND*/0)
-#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
- for ((var) = ((head)->cqh_last); \
- (var) != CIRCLEQ_ENDC(head); \
- (var) = ((var)->field.cqe_prev))
+#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
+ if ((head)->sqh_first == (elm)) { \
+ SIMPLEQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->sqh_first; \
+ while (curelm->field.sqe_next != (elm)) \
+ curelm = curelm->field.sqe_next; \
+ if ((curelm->field.sqe_next = \
+ curelm->field.sqe_next->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(curelm)->field.sqe_next; \
+ } \
+} while (/*CONSTCOND*/0)
-/*
- * Circular queue access methods.
- */
-#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
-#define CIRCLEQ_LAST(head) ((head)->cqh_last)
-/* For comparisons */
-#define CIRCLEQ_ENDC(head) (__launder_type(head))
-/* For assignments */
-#define CIRCLEQ_END(head) ((void *)(head))
-#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
-#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
-#define CIRCLEQ_EMPTY(head) \
- (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head))
-
-#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
- (((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \
- ? ((head)->cqh_first) \
- : (elm->field.cqe_next))
-#define CIRCLEQ_LOOP_PREV(head, elm, field) \
- (((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \
- ? ((head)->cqh_last) \
- : (elm->field.cqe_prev))
-#endif /* !_KERNEL */
-
-#endif /* !_SYS_QUEUE_H_ */
+#define SIMPLEQ_CONCAT(head1, head2) do { \
+ if (!SIMPLEQ_EMPTY((head2))) { \
+ *(head1)->sqh_last = (head2)->sqh_first; \
+ (head1)->sqh_last = (head2)->sqh_last; \
+ SIMPLEQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_LAST(head, type, field) \
+ (SIMPLEQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->sqh_last) - offsetof(struct type, field))))
+
+#endif /* H5queue_H_ */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 023c07e..ad6b258 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -46,6 +46,11 @@ if (NOT ONLY_SHARED_LIBS)
endif ()
H5_SET_LIB_OPTIONS (${HDF5_TEST_LIB_TARGET} ${HDF5_TEST_LIB_NAME} STATIC 0)
set_target_properties (${HDF5_TEST_LIB_TARGET} PROPERTIES FOLDER libraries/test)
+
+ # Always link to pthreads for VFD SWMR tests
+ if (NOT WIN32)
+ target_link_libraries (${HDF5_TEST_LIB_TARGET} PRIVATE Threads::Threads)
+ endif ()
endif ()
if (BUILD_SHARED_LIBS)
@@ -66,6 +71,9 @@ if (BUILD_SHARED_LIBS)
endif ()
H5_SET_LIB_OPTIONS (${HDF5_TEST_LIBSH_TARGET} ${HDF5_TEST_LIB_NAME} SHARED "LIB")
set_target_properties (${HDF5_TEST_LIBSH_TARGET} PROPERTIES FOLDER libraries/test)
+
+ # Always link to pthreads for VFD SWMR tests
+ target_link_libraries (${HDF5_TEST_LIBSH_TARGET} PRIVATE Threads::Threads)
endif ()
#################################################################################
diff --git a/test/vfd_swmr_common.c b/test/vfd_swmr_common.c
index 043b7ed..3f03ce7 100644
--- a/test/vfd_swmr_common.c
+++ b/test/vfd_swmr_common.c
@@ -21,6 +21,11 @@
#include <err.h> /* for err(3) */
+/* Only need the pthread solution if sigtimedwai(2) isn't available */
+#ifndef H5_HAVE_SIGTIMEDWAIT
+#include <pthread.h>
+#endif
+
#include "h5test.h"
#include "vfd_swmr_common.h"
#include "swmr_common.h"
@@ -178,6 +183,55 @@ strsignal(int signum)
}
#endif
+#ifndef H5_HAVE_SIGTIMEDWAIT
+
+typedef struct timer_params_t {
+ struct timespec *tick;
+ hid_t fid;
+} timer_params_t;
+
+pthread_mutex_t timer_mutex;
+hbool_t timer_stop = FALSE;
+
+static void *
+timer_function(void *arg)
+{
+ timer_params_t *params = (timer_params_t *)arg;
+ sigset_t sleepset;
+ hbool_t done = FALSE;
+
+ /* Ignore any signals */
+ sigfillset(&sleepset);
+ pthread_sigmask(SIG_SETMASK, &sleepset, NULL);
+
+ for (;;) {
+ estack_state_t es;
+
+ nanosleep(params->tick, NULL);
+
+ /* Check the mutex */
+ pthread_mutex_lock(&timer_mutex);
+ done = timer_stop;
+ pthread_mutex_unlock(&timer_mutex);
+ if (done)
+ break;
+
+ /* Avoid deadlock with peer: periodically enter the API so that
+ * tick processing occurs and data is flushed so that the peer
+ * can see it.
+ *
+ * The call we make will fail, but that's ok,
+ * so squelch errors.
+ */
+ es = disable_estack();
+ (void)H5Aexists_by_name(params->fid, "nonexistent", "nonexistent", H5P_DEFAULT);
+ restore_estack(es);
+ }
+
+ return NULL;
+}
+#endif /* H5_HAVE_SIGTIMEDWAIT */
+
/* Wait for any signal to occur and then return. Wake periodically
* during the wait to perform API calls: in this way, the
* VFD SWMR tick number advances and recent changes do not languish
@@ -186,8 +240,8 @@ strsignal(int signum)
void
await_signal(hid_t fid)
{
- sigset_t sleepset;
struct timespec tick = {.tv_sec = 0, .tv_nsec = 1000000000 / 100};
+ sigset_t sleepset;
if (sigfillset(&sleepset) == -1) {
err(EXIT_FAILURE, "%s.%d: could not initialize signal mask",
@@ -202,7 +256,37 @@ await_signal(hid_t fid)
dbgf(1, "waiting for signal\n");
+#ifndef H5_HAVE_SIGTIMEDWAIT
+ {
+ /* Use an alternative scheme for platforms like MacOS that do not have
+ * sigtimedwait(2)
+ */
+ timer_params_t params;
+ int rc;
+ pthread_t timer;
+
+ params.tick = &tick;
+ params.fid = fid;
+
+ pthread_mutex_init(&timer_mutex, NULL);
+
+ pthread_create(&timer, NULL, timer_function, &params);
+
+ rc = sigwait(&sleepset, NULL);
+
+ if (rc != -1) {
+ fprintf(stderr, "Received signal, wrapping things up.\n");
+ pthread_mutex_lock(&timer_mutex);
+ timer_stop = TRUE;
+ pthread_mutex_unlock(&timer_mutex);
+ pthread_join(timer, NULL);
+ }
+ else
+ err(EXIT_FAILURE, "%s: sigtimedwait", __func__);
+ }
+#else
for (;;) {
+ /* Linux and other systems */
const int rc = sigtimedwait(&sleepset, NULL, &tick);
if (rc != -1) {
@@ -226,6 +310,7 @@ await_signal(hid_t fid)
} else if (rc == -1)
err(EXIT_FAILURE, "%s: sigtimedwait", __func__);
}
+#endif /* H5_HAVE_SIGTIMEDWAIT */
}
/* Revised support routines that can be used for all VFD SWMR integration tests
diff --git a/test/vfd_swmr_common.h b/test/vfd_swmr_common.h
index 761a706..d96983a 100644
--- a/test/vfd_swmr_common.h
+++ b/test/vfd_swmr_common.h
@@ -11,8 +11,8 @@
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-#ifndef _VFD_SWMR_COMMON_H
-#define _VFD_SWMR_COMMON_H
+#ifndef VFD_SWMR_COMMON_H
+#define VFD_SWMR_COMMON_H
/***********/
/* Headers */
@@ -93,4 +93,4 @@ H5TEST_DLL int fetch_env_ulong(const char *, unsigned long, unsigned long *);
extern int verbosity;
-#endif /* _SWMR_COMMON_H */
+#endif /* SWMR_COMMON_H */