diff options
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | config/cmake/H5pubconf.h.in | 3 | ||||
-rw-r--r-- | config/cmake_ext_mod/ConfigureChecks.cmake | 1 | ||||
-rw-r--r-- | configure.ac | 134 | ||||
-rw-r--r-- | src/H5FD.c | 40 | ||||
-rw-r--r-- | src/H5FDpublic.h | 16 | ||||
-rw-r--r-- | src/H5FDvfd_swmr.h | 7 | ||||
-rw-r--r-- | src/H5FDvfd_swmr_private.h | 6 | ||||
-rw-r--r-- | src/H5Fpkg.h | 3 | ||||
-rw-r--r-- | src/H5private.h | 7 | ||||
-rw-r--r-- | src/H5queue.h | 369 | ||||
-rw-r--r-- | test/CMakeLists.txt | 8 | ||||
-rw-r--r-- | test/vfd_swmr_common.c | 87 | ||||
-rw-r--r-- | test/vfd_swmr_common.h | 6 |
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]) @@ -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, ¶ms); + + 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 */ |