summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt14
-rw-r--r--config/cmake/FindMERCURY.cmake129
-rw-r--r--configure.ac49
-rw-r--r--src/CMakeLists.txt48
-rw-r--r--src/H5FDioc.c31
-rw-r--r--src/H5FDioc.h2
-rw-r--r--src/H5FDioc_threads.c143
-rw-r--r--src/H5FDsubfile_int.c96
-rw-r--r--src/H5FDsubfile_mpi.c168
-rw-r--r--src/H5FDsubfiling.c176
-rw-r--r--src/H5FDsubfiling_priv.h22
-rw-r--r--src/Makefile.am23
-rw-r--r--src/mercury/COPYING39
-rw-r--r--src/mercury/README.md221
-rw-r--r--src/mercury/include/mercury.h1060
-rw-r--r--src/mercury/include/mercury_atomic.h625
-rw-r--r--src/mercury/include/mercury_atomic_queue.h266
-rw-r--r--src/mercury/include/mercury_bulk.h336
-rw-r--r--src/mercury/include/mercury_config.h113
-rw-r--r--src/mercury/include/mercury_core.h1074
-rw-r--r--src/mercury/include/mercury_core_header.h224
-rw-r--r--src/mercury/include/mercury_core_types.h156
-rw-r--r--src/mercury/include/mercury_dlog.h273
-rw-r--r--src/mercury/include/mercury_event.h179
-rw-r--r--src/mercury/include/mercury_hash_string.h48
-rw-r--r--src/mercury/include/mercury_hash_table.h242
-rw-r--r--src/mercury/include/mercury_header.h138
-rw-r--r--src/mercury/include/mercury_hl.h135
-rw-r--r--src/mercury/include/mercury_hl_macros.h384
-rw-r--r--src/mercury/include/mercury_list.h117
-rw-r--r--src/mercury/include/mercury_log.h393
-rw-r--r--src/mercury/include/mercury_macros.h108
-rw-r--r--src/mercury/include/mercury_mem.h114
-rw-r--r--src/mercury/include/mercury_mem_pool.h121
-rw-r--r--src/mercury/include/mercury_poll.h119
-rw-r--r--src/mercury/include/mercury_proc.h769
-rw-r--r--src/mercury/include/mercury_proc_bulk.h46
-rw-r--r--src/mercury/include/mercury_proc_string.h148
-rw-r--r--src/mercury/include/mercury_queue.h119
-rw-r--r--src/mercury/include/mercury_request.h204
-rw-r--r--src/mercury/include/mercury_string_object.h102
-rw-r--r--src/mercury/include/mercury_thread.h228
-rw-r--r--src/mercury/include/mercury_thread_annotation.h39
-rw-r--r--src/mercury/include/mercury_thread_condition.h176
-rw-r--r--src/mercury/include/mercury_thread_mutex.h124
-rw-r--r--src/mercury/include/mercury_thread_pool.h118
-rw-r--r--src/mercury/include/mercury_thread_rwlock.h215
-rw-r--r--src/mercury/include/mercury_thread_spin.h132
-rw-r--r--src/mercury/include/mercury_time.h503
-rw-r--r--src/mercury/include/mercury_types.h96
-rw-r--r--src/mercury/include/mercury_util.h44
-rw-r--r--src/mercury/include/mercury_util_config.h154
-rw-r--r--src/mercury/include/na.h1064
-rw-r--r--src/mercury/include/na_config.h134
-rw-r--r--src/mercury/include/na_sm.h96
-rw-r--r--src/mercury/include/na_types.h185
-rw-r--r--src/mercury/src/util/.deps/.dirstamp0
-rw-r--r--src/mercury/src/util/.deps/mercury_atomic_queue.Plo357
-rw-r--r--src/mercury/src/util/.deps/mercury_dlog.Plo214
-rw-r--r--src/mercury/src/util/.deps/mercury_event.Plo219
-rw-r--r--src/mercury/src/util/.deps/mercury_hash_table.Plo125
-rw-r--r--src/mercury/src/util/.deps/mercury_log.Plo204
-rw-r--r--src/mercury/src/util/.deps/mercury_mem.Plo276
-rw-r--r--src/mercury/src/util/.deps/mercury_mem_pool.Plo228
-rw-r--r--src/mercury/src/util/.deps/mercury_poll.Plo262
-rw-r--r--src/mercury/src/util/.deps/mercury_request.Plo220
-rw-r--r--src/mercury/src/util/.deps/mercury_thread.Plo113
-rw-r--r--src/mercury/src/util/.deps/mercury_thread_condition.Plo153
-rw-r--r--src/mercury/src/util/.deps/mercury_thread_mutex.Plo183
-rw-r--r--src/mercury/src/util/.deps/mercury_thread_pool.Plo220
-rw-r--r--src/mercury/src/util/.deps/mercury_thread_rwlock.Plo186
-rw-r--r--src/mercury/src/util/.deps/mercury_thread_spin.Plo186
-rw-r--r--src/mercury/src/util/.deps/mercury_util.Plo214
-rw-r--r--src/mercury/src/util/.dirstamp0
-rw-r--r--src/mercury/src/util/CMake/FindOPA.cmake31
-rw-r--r--src/mercury/src/util/CMakeLists.txt274
-rw-r--r--src/mercury/src/util/mercury_atomic.h625
-rw-r--r--src/mercury/src/util/mercury_atomic_queue.c81
-rw-r--r--src/mercury/src/util/mercury_atomic_queue.h266
-rw-r--r--src/mercury/src/util/mercury_dlog.c262
-rw-r--r--src/mercury/src/util/mercury_dlog.h273
-rw-r--r--src/mercury/src/util/mercury_event.c71
-rw-r--r--src/mercury/src/util/mercury_event.h179
-rw-r--r--src/mercury/src/util/mercury_hash_string.h48
-rw-r--r--src/mercury/src/util/mercury_hash_table.c435
-rw-r--r--src/mercury/src/util/mercury_hash_table.h242
-rw-r--r--src/mercury/src/util/mercury_list.h117
-rw-r--r--src/mercury/src/util/mercury_log.c487
-rw-r--r--src/mercury/src/util/mercury_log.h393
-rw-r--r--src/mercury/src/util/mercury_mem.c191
-rw-r--r--src/mercury/src/util/mercury_mem.h114
-rw-r--r--src/mercury/src/util/mercury_mem_pool.c337
-rw-r--r--src/mercury/src/util/mercury_mem_pool.h121
-rw-r--r--src/mercury/src/util/mercury_poll.c493
-rw-r--r--src/mercury/src/util/mercury_poll.h119
-rw-r--r--src/mercury/src/util/mercury_queue.h119
-rw-r--r--src/mercury/src/util/mercury_request.c159
-rw-r--r--src/mercury/src/util/mercury_request.h204
-rw-r--r--src/mercury/src/util/mercury_thread.c162
-rw-r--r--src/mercury/src/util/mercury_thread.h228
-rw-r--r--src/mercury/src/util/mercury_thread_annotation.h39
-rw-r--r--src/mercury/src/util/mercury_thread_condition.c46
-rw-r--r--src/mercury/src/util/mercury_thread_condition.h176
-rw-r--r--src/mercury/src/util/mercury_thread_mutex.c94
-rw-r--r--src/mercury/src/util/mercury_thread_mutex.h124
-rw-r--r--src/mercury/src/util/mercury_thread_pool.c179
-rw-r--r--src/mercury/src/util/mercury_thread_pool.h118
-rw-r--r--src/mercury/src/util/mercury_thread_rwlock.c90
-rw-r--r--src/mercury/src/util/mercury_thread_rwlock.h215
-rw-r--r--src/mercury/src/util/mercury_thread_spin.c55
-rw-r--r--src/mercury/src/util/mercury_thread_spin.h132
-rw-r--r--src/mercury/src/util/mercury_time.h503
-rw-r--r--src/mercury/src/util/mercury_util.c39
-rw-r--r--src/mercury/src/util/mercury_util.h44
-rw-r--r--src/mercury/src/util/mercury_util_config.h154
-rw-r--r--src/mercury/src/util/mercury_util_config.h.in155
-rw-r--r--src/mercury/src/util/mercury_util_error.h83
-rw-r--r--src/mercury/version.txt1
118 files changed, 23348 insertions, 372 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d142e0e..c29c1f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -734,15 +734,11 @@ endif ()
# see other find_package examples in /usr/share/cmake/Modules
option (HDF5_BUILD_SUBFILING "Build Parallel HDF5 Subfiling" OFF)
if (HDF5_BUILD_SUBFILING AND HDF5_ENABLE_PARALLEL)
- find_package(MERCURY REQUIRED)
- if (MERCURY_FOUND)
- message("Mercury include dir: ${MERCURY_INCLUDE_DIR}")
- include_directories(${MERCURY_INCLUDE_DIR})
- set (H5_HAVE_LIBMERCURY 1)
- set (H5_HAVE_MERCURY_H 1)
- set (CMAKE_REQUIRED_INCLUDES "${MERCURY_INCLUDE_DIR}")
- set (LINK_LIBS ${LINK_LIBS} ${MERCURY_LIBRARIES})
- endif()
+ message (STATUS "Setting up to use Mercury components")
+ include_directories(${HDF5_SRC_DIR}/mercury/include)
+ set (WITH_SUBFILING 1)
+ set (H5_HAVE_MERCURY_H 1)
+ set (CMAKE_REQUIRED_INCLUDES "${HDF5_SRC_DIR}/mercury/include")
endif()
#option (DEFAULT_API_VERSION "Enable v1.14 API (v16, v18, v110, v112, v114)" "v114")
diff --git a/config/cmake/FindMERCURY.cmake b/config/cmake/FindMERCURY.cmake
deleted file mode 100644
index 14a1a45..0000000
--- a/config/cmake/FindMERCURY.cmake
+++ /dev/null
@@ -1,129 +0,0 @@
-#
-# 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://www.hdfgroup.org/licenses.
-# If you do not have access to either file, you may request a copy from
-# help@hdfgroup.org.
-#
-#########################################################################
-
-# - Derived from the FindTiff.cmake and FindJPEG.cmake that is included with cmake
-# FindMERCURY
-
-# Find the native MERCURY includes and library
-
-# Imported targets
-##################
-
-# This module defines the following :prop_tgt:`IMPORTED` targets:
-#
-# MERCURY::MERCURY
-# The MERCURY library, if found.
-#
-# Result variables
-###################
-
-# This module will set the following variables in your project:
-
-# MERCURY_FOUND, true if the MERCURY headers and libraries were found.
-# MERCURY_INCLUDE_DIR, the directory containing the MERCURY headers.
-# MERCURY_INCLUDE_DIRS, the directory containing the MERCURY headers.
-# MERCURY_LIBRARIES, libraries to link against to use MERCURY.
-
-# Cache variables
-#################
-
-# The following variables may also be set:
-
-# MERCURY_LIBRARY, where to find the MERCURY library.
-# MERCURY_LIBRARY_DEBUG - Debug version of MERCURY library
-# MERCURY_LIBRARY_RELEASE - Release Version of MERCURY library
-
-# message (STATUS "Finding MERCURY library and headers..." )
-#########################################################################
-
-
-find_path(MERCURY_INCLUDE_DIR mercury.h)
-
-set(mercury_names ${MERCURY_NAMES} mercury libmercury_util libmercury)
-foreach(name ${mercury_names})
- list (APPEND mercury_names_debug "${name}_debug")
-endforeach()
-
-if(NOT MERCURY_LIBRARY)
- find_library(MERCURY_LIBRARY_RELEASE NAMES ${mercury_names})
- find_library(MERCURY_LIBRARY_DEBUG NAMES ${mercury_names_debug})
- include(SelectLibraryConfigurations)
- select_library_configurations(MERCURY)
- mark_as_advanced(MERCURY_LIBRARY_RELEASE MERCURY_LIBRARY_DEBUG)
-endif()
-unset(mercury_names)
-unset(mercury_names_debug)
-
-if(MERCURY_INCLUDE_DIR AND EXISTS "${MERCURY_INCLUDE_DIR}/mercury_config.h")
- file(STRINGS "${MERCURY_INCLUDE_DIR}/mercury_proc.h" mercury_version_str
- REGEX "^#define[\t ]+HG_VERSION[\t ]+.*")
-
- string(REGEX REPLACE "^#define[\t ]+MERCURY_PACKAGE_VERSION[\t ]+([0-9]+).*"
- "\\1" HG_VERSION "${mercury_version_str}")
- unset(mercury_version_str)
-endif()
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MERCURY
- REQUIRED_VARS MERCURY_LIBRARY MERCURY_INCLUDE_DIR
- VERSION_VAR MERCURY_VERSION)
-
-if(MERCURY_FOUND)
- set(MERCURY_LIBRARIES ${MERCURY_LIBRARY})
- set(MERCURY_INCLUDE_DIRS "${MERCURY_INCLUDE_DIR}")
-
- if(NOT TARGET MERCURY::MERCURY)
- add_library(MERCURY::MERCURY UNKNOWN IMPORTED)
- if(MERCURY_INCLUDE_DIRS)
- set_target_properties(MERCURY::MERCURY PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${MERCURY_INCLUDE_DIRS}")
- endif()
- if(EXISTS "${MERCURY_LIBRARY}")
- set_target_properties(MERCURY::MERCURY PROPERTIES
- IMPORTED_LINK_INTERFACE_LANGUAGES "C"
- IMPORTED_LOCATION "${MERCURY_LIBRARY}")
- endif()
- if(EXISTS "${MERCURY_LIBRARY_RELEASE}")
- set_property(TARGET MERCURY::MERCURY APPEND PROPERTY
- IMPORTED_CONFIGURATIONS RELEASE)
- set_target_properties(MERCURY::MERCURY PROPERTIES
- IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
- IMPORTED_LOCATION_RELEASE "${MERCURY_LIBRARY_RELEASE}")
- endif()
- if(EXISTS "${MERCURY_LIBRARY_DEBUG}")
- set_property(TARGET MERCURY::MERCURY APPEND PROPERTY
- IMPORTED_CONFIGURATIONS DEBUG)
- set_target_properties(MERCURY::MERCURY PROPERTIES
- IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
- IMPORTED_LOCATION_DEBUG "${MERCURY_LIBRARY_DEBUG}")
- endif()
- endif()
-endif()
-
-mark_as_advanced(MERCURY_LIBRARY MERCURY_INCLUDE_DIR)
-
-# Report the results.
-if (NOT MERCURY_FOUND)
- set (MERCURY_DIR_MESSAGE
- "Mercury was not found. Make sure MERCURY_LIBRARY and MERCURY_INCLUDE_DIR are set or set the MERCURY_INSTALL environment variable."
- )
- if (NOT MERCURY_FIND_QUIETLY)
- if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15.0")
- message (VERBOSE "${MERCURY_DIR_MESSAGE}")
- endif ()
- else ()
- if (MERCURY_FIND_REQUIRED)
- message (FATAL_ERROR "Mercury was NOT found and is Required by this project")
- endif ()
- endif ()
-endif ()
diff --git a/configure.ac b/configure.ac
index d67450e..d98416d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1545,13 +1545,10 @@ AC_ARG_WITH([mercury],
case "X-$withval" in
X-yes)
HAVE_MERCURY="yes"
- AC_CHECK_HEADERS([mercury.h],[HAVE_MERCURY_H="yes"], [unset HAVE_MERCURY])
- if test "x$HAVE_MERCURY" = "xyes"; then
- AC_CHECK_LIB([mercury_util], [hg_thread_mutex_init],, [unset HAVE_MERCURY])
- fi
if test -z "$HAVE_MERCURY" -a -n "$HDF5_CONFIG_ABORT"; then
AC_MSG_ERROR([couldn't find mercury library])
fi
+ echo "HAVE_MERCURY flag = $HAVE_MERCURY"
;;
X-|X-no|X-none)
HAVE_MERCURY="no"
@@ -1573,6 +1570,7 @@ case "X-$withval" in
;;
esac
+ echo "checking include path: $mercury_inc"
saved_CPPFLAGS="$CPPFLAGS"
saved_AM_CPPFLAGS="$AM_CPPFLAGS"
saved_LDFLAGS="$LDFLAGS"
@@ -1584,22 +1582,11 @@ case "X-$withval" in
fi
AC_CHECK_HEADERS([mercury.h],,[CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"] [unset HAVE_MERCURY])
-
- if test "x$HAVE_MERCURY" = "xyes"; then
- if test -n "$mercury_lib"; then
- LDFLAGS="$LDFLAGS -L$mercury_lib"
- AM_LDFLAGS="$AM_LDFLAGS -L$mercury_lib"
- fi
-
- AC_CHECK_LIB([mercury_util], [hg_thread_mutex_init],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset HAVE_MERCURY])
- fi
-
- if test -z "$HAVE_MERCURY" -a -n "$HDF5_CONFIG_ABORT"; then
- AC_MSG_ERROR([couldn't find mercury library])
- fi
;;
esac
+AM_CONDITIONAL([HAVE_MERCURY_CONDITIONAL], [test "X$HAVE_MERCURY" = "Xyes"])
+
## ----------------------------------------------------------------------
## Make the external filters list available to *.in files
## At this point it's unset (no external filters by default) but it
@@ -3154,6 +3141,34 @@ else
fi
## ----------------------------------------------------------------------
+## Check if Subfiling I/O driver is enabled by --enable-subfiling-vfd
+##
+AC_SUBST([SUBFILING_VFD])
+
+## Default is no direct VFD
+SUBFILING_VFD=no
+
+AC_MSG_CHECKING([if the subfiling I/O virtual file driver (VFD) is enabled])
+
+AC_ARG_ENABLE([subfiling-vfd],
+ [AS_HELP_STRING([--enable-subfiling-vfd],
+ [Build the subfiling I/O virtual file driver (VFD).
+ [default=no]])],
+ [SUBFILING_VFD=$enableval], [SUBFILING_VFD=no])
+
+if test "X$SUBFILING_VFD" = "Xyes"; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_SUBFILING], [1],
+ [Define if the subfiling I/O virtual file driver (VFD) should be compiled])
+else
+ AC_MSG_RESULT([no])
+fi
+
+## Subfiling VFD files are not built if not required.
+AM_CONDITIONAL([SUBFILING_VFD_CONDITIONAL], [test "X$SUBFILING_VFD" = "Xyes"])
+
+
+## ----------------------------------------------------------------------
## Check if Direct I/O driver is enabled by --enable-direct-vfd
##
AC_SUBST([DIRECT_VFD])
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f848a8e..96acac7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -226,6 +226,39 @@ set (H5FA_HDRS
)
IDE_GENERATED_PROPERTIES ("H5FA" "${H5FA_HDRS}" "${H5FA_SOURCES}" )
+set (MERCURY_UTIL_SOURCES
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_atomic_queue.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_dlog.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_event.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_hash_table.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_log.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_mem.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_mem_pool.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_poll.c
+ ${HDF5_SRC_DIR}/ mercury/src/util/mercury_request.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_thread.c
+ ${HDF5_SRC_DIR}/ mercury/src/util/mercury_thread_condition.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_thread_pool.c
+ ${HDF5_SRC_DIR}/ mercury/src/util/mercury_thread_mutex.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_thread_rwlock.c
+ ${HDF5_SRC_DIR}/ mercury/src/util/mercury_thread_spin.c
+ ${HDF5_SRC_DIR}/mercury/src/util/mercury_util.c
+)
+
+set (H5FD_SUBFILING_SOURCES
+ ${HDF5_SRC_DIR}/H5FDioc.c
+ ${HDF5_SRC_DIR}/H5FDioc_threads.c
+ ${HDF5_SRC_DIR}/H5FDsubfiling.c
+ ${HDF5_SRC_DIR}/H5FDsubfile_int.c
+ ${HDF5_SRC_DIR}/H5FDsubfile_mpi.c
+ ${MERCURY_UTIL_SOURCES}
+)
+
+set (H5FD_SUBFILING_HDRS
+ ${HDF5_SRC_DIR}/H5FDioc.h
+ ${HDF5_SRC_DIR}/H5FDsubfiling.h
+ ${HDF5_SRC_DIR}/H5FDsubfile_int.h
+)
set (H5FD_SOURCES
${HDF5_SRC_DIR}/H5FD.c
@@ -234,8 +267,6 @@ set (H5FD_SOURCES
${HDF5_SRC_DIR}/H5FDfamily.c
${HDF5_SRC_DIR}/H5FDhdfs.c
${HDF5_SRC_DIR}/H5FDint.c
- ${HDF5_SRC_DIR}/H5FDioc.c
- ${HDF5_SRC_DIR}/H5FDioc_threads.c
${HDF5_SRC_DIR}/H5FDlog.c
${HDF5_SRC_DIR}/H5FDmirror.c
${HDF5_SRC_DIR}/H5FDmpi.c
@@ -247,9 +278,6 @@ set (H5FD_SOURCES
${HDF5_SRC_DIR}/H5FDspace.c
${HDF5_SRC_DIR}/H5FDsplitter.c
${HDF5_SRC_DIR}/H5FDstdio.c
- ${HDF5_SRC_DIR}/H5FDsubfiling.c
- ${HDF5_SRC_DIR}/H5FDsubfile_int.c
- ${HDF5_SRC_DIR}/H5FDsubfile_mpi.c
${HDF5_SRC_DIR}/H5FDtest.c
${HDF5_SRC_DIR}/H5FDwindows.c
)
@@ -767,6 +795,12 @@ set (H5_MODULE_HEADERS
${HDF5_SRC_DIR}/H5Zmodule.h
)
+set (subfile_SOURCES )
+if (WITH_SUBFILING)
+ message (STATUS "Appending to common_SRCS ${H5FD_SUBFILING_SOURCES}")
+ list(APPEND subfile_SOURCES ${H5FD_SUBFILING_SOURCES})
+endif(WITH_SUBFILING)
+
set (common_SRCS
${H5_SOURCES}
${H5A_SOURCES}
@@ -814,8 +848,11 @@ set (common_SRCS
${H5VM_SOURCES}
${H5WB_SOURCES}
${H5Z_SOURCES}
+ ${subfile_SOURCES}
)
+
+
set (H5_PUBLIC_HEADERS
${H5_HDRS}
${H5A_HDRS}
@@ -852,6 +889,7 @@ set (H5_PUBLIC_HEADERS
${H5TS_HDRS}
${H5VL_HDRS}
${H5Z_HDRS}
+ ${subfile_HDRS}
)
set (H5_PRIVATE_HEADERS
diff --git a/src/H5FDioc.c b/src/H5FDioc.c
index b514448..b00fb51 100644
--- a/src/H5FDioc.c
+++ b/src/H5FDioc.c
@@ -740,9 +740,9 @@ H5FD__ioc_open(const char *name, unsigned flags, hid_t ioc_fapl_id, haddr_t maxa
const H5FD_ioc_config_t *fapl_ptr = NULL; /* Driver-specific property list */
H5FD_class_t * driver = NULL; /* VFD for file */
H5FD_driver_prop_t driver_prop; /* Property for driver ID & info */
- H5P_genplist_t * plist_ptr = NULL;
- H5FD_t * ret_value = NULL;
- int mpi_enabled = 0;
+ H5P_genplist_t * plist_ptr = NULL;
+ H5FD_t * ret_value = NULL;
+ int l_error = 0, g_error = 0, mpi_enabled = 0;
FUNC_ENTER_STATIC
H5FD_IOC_LOG_CALL(FUNC);
@@ -833,10 +833,20 @@ H5FD__ioc_open(const char *name, unsigned flags, hid_t ioc_fapl_id, haddr_t maxa
* as an alternative to opening a new subfiling file, e.g. nnn_0_of_N.h5
*/
file_ptr->inode = inode_id = sb.st_ino;
- // file_ptr->hdf_fd_dup = HDdup(hdf_file->fd);
}
- else
- goto done;
+ else {
+ /* The two-step file opening approach may be
+ * the root cause for the sec2 open to return a NULL.
+ * It is prudent then, to collectively fail (early) in this case.
+ */
+ l_error = 1;
+ }
+ MPI_Allreduce(&l_error, &g_error, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
+ if (g_error) {
+ if (file_ptr->ioc_file)
+ H5FD_close(file_ptr->ioc_file);
+ HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "unable to open file = %s\n", name)
+ }
/* See: H5FDsubfile_int.c: returns error count! */
if (H5FD__open_subfiles((void *)&file_ptr->fa, inode_id, ioc_flags) > 0)
@@ -844,11 +854,7 @@ H5FD__ioc_open(const char *name, unsigned flags, hid_t ioc_fapl_id, haddr_t maxa
else if (file_ptr->inode > 0) { /* No errors opening the subfiles */
subfiling_context_t *sf_context = get__subfiling_object(file_ptr->fa.common.context_id);
-#if 0 /* JRM */ /* original */
- if (sf_context) {
-#else /* JRM */ /* Richard's fix */
- if (sf_context && sf_context->topology->rank_is_ioc) {
-#endif
+ if (sf_context && sf_context->topology->rank_is_ioc) {
if (initialize_ioc_threads(sf_context) < 0) {
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Unable to initialize IOC threads")
}
@@ -863,8 +869,7 @@ else
ret_value = (H5FD_t *)file_ptr;
-done : if (NULL == ret_value)
-{
+done : if (NULL == ret_value) {
if (file_ptr) {
if (file_ptr->ioc_file)
H5FD_close(file_ptr->ioc_file);
diff --git a/src/H5FDioc.h b/src/H5FDioc.h
index 119e004..3e04c80 100644
--- a/src/H5FDioc.h
+++ b/src/H5FDioc.h
@@ -132,6 +132,8 @@ H5_DLL int initialize_ioc_threads(void *_sf_context);
H5_DLL int tpool_add_work(void *work);
H5_DLL void begin_thread_exclusive(void);
H5_DLL void end_thread_exclusive(void);
+H5_DLL void ioc__wait_for_serialize(void *msg);
+H5_DLL void ioc__release_dependency(int qid);
#ifdef __cplusplus
}
diff --git a/src/H5FDioc_threads.c b/src/H5FDioc_threads.c
index 1db8c62..3a7ee84 100644
--- a/src/H5FDioc_threads.c
+++ b/src/H5FDioc_threads.c
@@ -26,9 +26,10 @@
* use mercury for that purpose...
*/
-static hg_thread_mutex_t ioc_mutex = PTHREAD_MUTEX_INITIALIZER;
-static hg_thread_mutex_t ioc_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
-static hg_thread_pool_t *ioc_thread_pool = NULL;
+static hg_thread_mutex_t ioc_mutex = PTHREAD_MUTEX_INITIALIZER;
+static hg_thread_mutex_t ioc_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
+static hg_thread_mutex_t ioc_serialize_mutex = PTHREAD_MUTEX_INITIALIZER;
+static hg_thread_pool_t *ioc_thread_pool = NULL;
static hg_thread_t ioc_thread;
#ifndef HG_TEST_NUM_THREADS_DEFAULT
@@ -40,6 +41,11 @@ extern int ioc_main(int64_t context_id);
static int pool_concurrent_max = 0;
static struct hg_thread_work *pool_request = NULL;
+/* Prototypes */
+void __attribute__((destructor)) finalize_ioc_threads(void);
+int wait_for_thread_main(void);
+bool tpool_is_empty(void);
+
/*-------------------------------------------------------------------------
* Function: local ioc_thread_main
*
@@ -61,14 +67,13 @@ static struct hg_thread_work *pool_request = NULL;
static HG_THREAD_RETURN_TYPE
ioc_thread_main(void *arg)
{
- int64_t * context_id = (int64_t *)arg;
+ int64_t context_id = *(int64_t *)arg;
hg_thread_ret_t thread_ret = (hg_thread_ret_t)0;
/* Pass along the subfiling_context_t */
- ioc_main(context_id[0]);
+ ioc_main(context_id);
- /* Upon exit, we can free the input arg */
- free(arg);
+ HDfree(arg);
return thread_ret;
}
@@ -99,7 +104,7 @@ initialize_ioc_threads(void *_sf_context)
int file_open_count;
subfiling_context_t *sf_context = _sf_context;
unsigned int thread_pool_count = HG_TEST_NUM_THREADS_DEFAULT;
- int64_t * context_id = (int64_t *)malloc(sizeof(int64_t));
+ int64_t * context_id = (int64_t *)HDmalloc(sizeof(int64_t));
int world_size = sf_context->topology->app_layout->world_size;
size_t alloc_size = ((size_t)world_size * sizeof(struct hg_thread_work));
char * envValue;
@@ -170,7 +175,7 @@ initialize_ioc_threads(void *_sf_context)
* 3. Pointer to the input argument that gets passed along to the user
* function.
*/
- status = hg_thread_create(&ioc_thread, ioc_thread_main, context_id);
+ status = hg_thread_create(&ioc_thread, ioc_thread_main, (void *)context_id);
if (status) {
puts("hg_thread_create failed");
goto err_exit;
@@ -275,11 +280,14 @@ handle_work_request(void *arg)
assert(sf_context != NULL);
atomic_fetch_add(&sf_work_pending, 1); // atomic
+ msg->in_progress = 1;
switch (msg->tag) {
case WRITE_INDEP:
status = queue_write_indep(msg, msg->subfile_rank, msg->source, sf_context->sf_data_comm);
break;
case READ_INDEP:
+ if (msg->serialize)
+ ioc__wait_for_serialize(arg); // wait for dependency
status = queue_read_indep(msg, msg->subfile_rank, msg->source, sf_context->sf_data_comm);
break;
default:
@@ -291,6 +299,11 @@ handle_work_request(void *arg)
fflush(stdout);
atomic_fetch_sub(&sf_work_pending, 1); // atomic
+ msg->in_progress = 0;
+ if (msg->dependents) {
+ ioc__release_dependency(msg->depend_id);
+ msg->dependents = 0;
+ }
if (status < 0) {
HDprintf("[ioc(%d) %s]: request(%s) filename=%s from "
"rank(%d), size=%ld, offset=%ld FAILED\n",
@@ -302,6 +315,97 @@ handle_work_request(void *arg)
return ret;
}
+void
+ioc__wait_for_serialize(void *_work)
+{
+ sf_work_request_t *work = (sf_work_request_t *)_work;
+ volatile int waiting = 1;
+ while (waiting) {
+ usleep(5);
+ hg_thread_mutex_lock(&ioc_serialize_mutex);
+ waiting = work->serialize;
+ hg_thread_mutex_unlock(&ioc_serialize_mutex);
+ }
+}
+
+void
+ioc__release_dependency(int qid)
+{
+ sf_work_request_t *work = (sf_work_request_t *)pool_request[qid].args;
+ hg_thread_mutex_lock(&ioc_serialize_mutex);
+ work->serialize = 0;
+ hg_thread_mutex_unlock(&ioc_serialize_mutex);
+}
+
+static int
+check__overlap(void *_work, int current_index, int *conflict_id)
+{
+ sf_work_request_t *work = (sf_work_request_t *)_work;
+ sf_work_request_t *next = NULL;
+ int index, count = 0;
+ /* Search backward thru the queue of work requests */
+
+ for (index = current_index; count < pool_concurrent_max; count++, index--) {
+ if (index == 0) {
+ index = pool_concurrent_max - 1;
+ }
+ if (index == current_index)
+ return 0;
+ if ((next = (sf_work_request_t *)(pool_request[index].args)) == NULL)
+ continue;
+ /* The queued operation need NOT be running at present... */
+ else /* if (next->in_progress) */ {
+ if (work->tag == WRITE_INDEP) {
+ /* a WRITE should not overlap with anything else */
+ int64_t n_data_size = next->header[0];
+ int64_t n_offset = next->header[1];
+ int64_t n_max_offset = (n_offset + n_data_size) - 1;
+ int64_t w_data_size = work->header[0];
+ int64_t w_offset = work->header[1];
+ int64_t w_max_offset = (w_offset + w_data_size) - 1;
+ if ((w_max_offset >= n_offset) && (w_max_offset < n_max_offset)) {
+ next->dependents = 1;
+ next->depend_id = current_index;
+ work->serialize = true;
+ *conflict_id = index;
+ return 1;
+ }
+ else if ((w_offset <= n_max_offset) && (w_offset > n_offset)) {
+ next->dependents = 1;
+ next->depend_id = current_index;
+ work->serialize = true;
+ *conflict_id = index;
+ return 1;
+ }
+ }
+ /* The work->tag indicates READ, so only check for a conflicting WRITE */
+ else if (next->tag == WRITE_INDEP) {
+ int64_t n_data_size = next->header[0];
+ int64_t n_offset = next->header[1];
+ int64_t n_max_offset = (n_offset + n_data_size) - 1;
+ int64_t w_data_size = work->header[0];
+ int64_t w_offset = work->header[1];
+ int64_t w_max_offset = (w_offset + w_data_size) - 1;
+ if ((w_max_offset >= n_offset) && (w_max_offset < n_max_offset)) {
+ next->dependents = 1;
+ next->depend_id = current_index;
+ work->serialize = true;
+ *conflict_id = index;
+ return 1;
+ }
+ else if ((w_offset <= n_max_offset) && (w_offset > n_offset)) {
+ next->dependents = 1;
+ next->depend_id = current_index;
+ work->serialize = true;
+ *conflict_id = index;
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
/*-------------------------------------------------------------------------
* Function: tpool_add_work
*
@@ -321,12 +425,27 @@ handle_work_request(void *arg)
int
tpool_add_work(void *_work)
{
- static int work_index = 0;
- sf_work_request_t *work = (sf_work_request_t *)_work;
-
+ static int work_index = 0;
+ int conflict_id = -1;
+ sf_work_request_t *work = (sf_work_request_t *)_work;
+ /* We have yet to start processing this new request... */
+ work->in_progress = 0;
hg_thread_mutex_lock(&ioc_mutex);
+ if (check__overlap(_work, work_index, &conflict_id) > 0) {
+#ifdef VERBOSE
+ const char * type = (work->tag == WRITE_INDEP ? "WRITE" : "READ");
+ sf_work_request_t *next = (sf_work_request_t *)(pool_request[conflict_id].args);
+ printf("%s - (%d) Found conflict: index=%d: work(offset=%ld,length=%ld) conflict(offset=%ld, "
+ "length=%ld)\n",
+ type, work_index, conflict_id, work->header[1], work->header[0], next->header[1],
+ next->header[0]);
+ fflush(stdout);
+#endif
+ }
+
if (work_index == pool_concurrent_max)
work_index = 0;
+
pool_request[work_index].func = handle_work_request;
pool_request[work_index].args = work;
hg_thread_pool_post(ioc_thread_pool, &pool_request[work_index++]);
diff --git a/src/H5FDsubfile_int.c b/src/H5FDsubfile_int.c
index b99ea36..0d231fa 100644
--- a/src/H5FDsubfile_int.c
+++ b/src/H5FDsubfile_int.c
@@ -71,6 +71,8 @@ static stat_record_t subfiling_stats[TOTAL_STAT_COUNT];
#define SF_READ_WAIT_TIME (subfiling_stats[READ_WAIT].total / (double)subfiling_stats[READ_WAIT].op_count)
#define SF_QUEUE_DELAYS (subfiling_stats[QUEUE_STAT].total)
+#define SF_ALIGNMENT 8
+
static void
maybe_initialize_statistics(void)
{
@@ -398,6 +400,9 @@ open_subfile_with_context(subfiling_context_t *sf_context, uint64_t fid, int fla
sf_context->sf_context_id,
start_t,
NULL,
+ 0,
+ 0,
+ 0,
0};
if (flags & O_CREAT) {
@@ -553,16 +558,17 @@ close__subfiles(subfiling_context_t *sf_context, uint64_t fid)
sf_logfile = NULL;
}
}
- if (sf_context->h5_filename) {
- free(sf_context->h5_filename);
- sf_context->h5_filename = NULL;
- }
- if (sf_context->subfile_prefix) {
- free(sf_context->subfile_prefix);
- sf_context->subfile_prefix = NULL;
- }
+
#endif
}
+ if (sf_context->h5_filename) {
+ free(sf_context->h5_filename);
+ sf_context->h5_filename = NULL;
+ }
+ if (sf_context->subfile_prefix) {
+ free(sf_context->subfile_prefix);
+ sf_context->subfile_prefix = NULL;
+ }
MPI_Allreduce(&errors, &global_errors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
@@ -746,24 +752,21 @@ gather_topology_info(sf_topology_t *info)
app_layout_t *app_layout = NULL;
HDassert(info != NULL);
- HDassert((app_layout = info->app_layout) != NULL);
+ app_layout = info->app_layout;
+ HDassert(app_layout != NULL);
sf_world_size = app_layout->world_size;
sf_world_rank = app_layout->world_rank;
- if (app_layout->layout)
- return;
-
if (1) {
long hostid = gethostid();
layout_t my_hostinfo;
- app_layout->layout = (layout_t *)calloc((size_t)sf_world_size + 1, sizeof(layout_t));
if (app_layout->layout == NULL) {
- perror("calloc failure!");
- MPI_Abort(MPI_COMM_WORLD, 1);
+ app_layout->layout = (layout_t *)calloc((size_t)sf_world_size + 1, sizeof(layout_t));
+ HDassert(app_layout->layout != NULL);
}
- app_layout->hostid = hostid;
+ app_layout->hostid = hostid;
my_hostinfo.rank = sf_world_rank;
my_hostinfo.hostid = hostid;
app_layout->layout[sf_world_rank] = my_hostinfo;
@@ -804,17 +807,12 @@ count_nodes(sf_topology_t *info, int my_rank)
long nextid;
HDassert(info != NULL);
- HDassert((app_layout = info->app_layout) != NULL);
+ app_layout = info->app_layout;
- if (app_layout->layout == NULL) {
+ if ((node_count = app_layout->node_count) == 0)
gather_topology_info(info);
- }
- if (app_layout->node_ranks == NULL) {
- app_layout->node_ranks = (int *)calloc((size_t)(app_layout->world_size + 1), sizeof(int));
- }
-
- HDassert(app_layout->node_ranks != NULL);
+ HDassert(app_layout->node_ranks);
nextid = app_layout->layout[0].hostid;
/* Possibly record my hostid_index */
@@ -871,7 +869,7 @@ identify_ioc_ranks(int node_count, int iocs_per_node, sf_topology_t *info)
int total_ioc_count = 0;
app_layout_t *app_layout = NULL;
HDassert(info != NULL);
- HDassert((app_layout = info->app_layout) != NULL);
+ app_layout = info->app_layout;
for (n = 0; n < node_count; n++) {
int k;
@@ -1051,35 +1049,51 @@ H5FD__determine_ioc_count(int world_size, int world_rank, ioc_selection_t ioc_se
{
int ioc_count = 0;
ioc_selection_t ioc_selection = ioc_selection_options;
- sf_topology_t * app_topology = NULL;
+ /* Once the application layout is determined,
+ * we should be able to reuse the structure for every
+ * file open.
+ */
+ app_layout_t * app_layout = sf_app_layout;
+ sf_topology_t *app_topology = NULL;
HDassert(thisapp != NULL);
- if (!ioc_count || (ioc_selection != ioc_select_method)) {
+ if (thisapp) {
int rank_multiple = 0;
int iocs_per_node = 1;
char *envValue = NULL;
int * io_concentrator = NULL;
if ((app_topology = *thisapp) == NULL) {
- app_topology = (sf_topology_t *)calloc(1, sizeof(sf_topology_t));
+ app_topology = (sf_topology_t *)HDmalloc(sizeof(sf_topology_t));
HDassert(app_topology != NULL);
+ memset(app_topology, 0, sizeof(sf_topology_t));
}
- if (sf_app_layout == NULL) {
- sf_app_layout = (app_layout_t *)calloc(1, sizeof(app_layout_t));
- HDassert(sf_app_layout != NULL);
+ if (app_layout == NULL) {
+ /* do a single allocation to encompass the app_layout_t
+ * and all of it's elements (layout and node_ranks).
+ */
+ size_t node_rank_size = sizeof(int) * (size_t)((world_size + 1));
+ size_t layout_size = sizeof(layout_t) * (size_t)((world_size + 1));
+ size_t alloc_size = sizeof(app_layout_t) + node_rank_size + layout_size;
+ app_layout = (app_layout_t *)HDmalloc(alloc_size);
+ HDassert(app_layout != NULL);
+ HDmemset(app_layout, 0, alloc_size);
+ app_layout->node_ranks = (int *)&app_layout[1];
+ app_layout->layout = (layout_t *)&app_layout->node_ranks[world_size + 2];
}
+
/* Once the application layout has been filled once, any additional
* file open operations won't be required to gather that information.
*/
- app_topology->app_layout = sf_app_layout;
- sf_app_layout->world_size = world_size;
- sf_app_layout->world_rank = world_rank;
+ app_topology->app_layout = app_layout;
+ app_layout->world_size = world_size;
+ app_layout->world_rank = world_rank;
if (app_topology->io_concentrator == NULL) {
app_topology->io_concentrator = io_concentrator =
- (int *)HDmalloc(((size_t)world_size * sizeof(int)));
+ (int *)HDcalloc((size_t)world_size, sizeof(int));
}
- assert(io_concentrator != NULL);
+ HDassert(io_concentrator != NULL);
app_topology->selection_type = ioc_selection = ioc_select_method;
if (ioc_select_method == SELECT_IOC_WITH_CONFIG) {
@@ -1139,6 +1153,8 @@ next:
if (ioc_select_method == SELECT_IOC_ONE_PER_NODE) {
app_topology->selection_type = ioc_select_method;
+ app_topology->app_layout = app_layout;
+ sf_app_layout = app_layout;
ioc_count = count_nodes(app_topology, world_rank);
if ((envValue = HDgetenv("H5_IOC_COUNT_PER_NODE")) != NULL) {
@@ -1149,6 +1165,7 @@ next:
}
ioc_count = identify_ioc_ranks(ioc_count, iocs_per_node, app_topology);
}
+
if (ioc_count > 0) {
app_topology->n_io_concentrators = ioc_count;
/* Create a vector of "potential" file descriptors
@@ -1332,6 +1349,7 @@ herr_t
H5FDsubfiling_init(ioc_selection_t ioc_select_method, char *ioc_select_option, int64_t *sf_context)
{
herr_t ret_value = SUCCEED;
+ size_t alloc_size;
int ioc_count;
int world_rank, world_size;
sf_topology_t * thisApp = NULL;
@@ -1355,6 +1373,12 @@ H5FDsubfiling_init(ioc_selection_t ioc_select_method, char *ioc_select_option, i
goto done;
}
+ alloc_size = sizeof(sf_topology_t);
+ thisApp = HDmalloc(alloc_size);
+ HDassert(thisApp);
+
+ HDmemset(thisApp, 0, alloc_size);
+
/* Compute the number an distribution map of the set of IO Concentrators */
if ((ioc_count = H5FD__determine_ioc_count(world_size, world_rank, ioc_select_method, ioc_select_option,
&thisApp)) <= 0) {
diff --git a/src/H5FDsubfile_mpi.c b/src/H5FDsubfile_mpi.c
index 6e060c5..2204d8d 100644
--- a/src/H5FDsubfile_mpi.c
+++ b/src/H5FDsubfile_mpi.c
@@ -31,19 +31,18 @@ static double sf_queue_delay_time = 0.0;
* intend to use the user defined HDF5 filename for a
* zeroth subfile as well as for all metadata.
*/
-#define SF_NODE_LOCAL_TEMPLATE "%ld_node_local_%d_of_%d"
-#define SF_FILENAME_TEMPLATE "%ld_subfile_%d_of_%d"
+#define SF_FILENAME_TEMPLATE ".subfile_%ld_%d_of_%d"
static int *request_count_per_rank = NULL;
-atomic_int sf_workinprogress = 0;
-atomic_int sf_work_pending = 0;
-atomic_int sf_file_open_count = 0;
-atomic_int sf_file_close_count = 0;
-atomic_int sf_file_refcount = 0;
-atomic_int sf_ioc_fini_refcount = 0;
-atomic_int sf_ioc_ready = 0;
-volatile int sf_shutdown_flag = 0;
+atomic_int sf_workinprogress = 0;
+atomic_int sf_work_pending = 0;
+atomic_int sf_file_open_count = 0;
+atomic_int sf_file_close_count = 0;
+atomic_int sf_file_refcount = 0;
+atomic_int sf_ioc_fini_refcount = 0;
+atomic_int sf_ioc_ready = 0;
+atomic_int sf_shutdown_flag = 0;
/*
* Structure definitions to enable async io completions
@@ -793,7 +792,7 @@ get_ioc_subfile_path(int ioc, int ioc_count, subfiling_context_t *sf_context)
char * prefix = sf_context->subfile_prefix;
if (prefix != NULL) {
- sprintf(filepath, "%s/" SF_NODE_LOCAL_TEMPLATE, prefix, sf_context->h5_file_id, ioc, ioc_count);
+ sprintf(filepath, "%s/" SF_FILENAME_TEMPLATE, prefix, sf_context->h5_file_id, ioc, ioc_count);
}
else {
strcpy(filepath, sf_context->h5_filename);
@@ -1002,7 +1001,6 @@ write__independent_async(int n_io_concentrators, hid_t context_id, int64_t offse
fflush(stdout);
#endif
status = MPI_Send(msg, 3, MPI_INT64_T, io_concentrator[ioc_start], WRITE_INDEP, sf_context->sf_msg_comm);
-
if (status != MPI_SUCCESS) {
int len;
char estring[MPI_MAX_ERROR_STRING];
@@ -1123,7 +1121,7 @@ H5FD__write_vector_internal(hid_t h5_fid, hssize_t count, haddr_t addrs[], size_
sf_context = get__subfiling_object(sf_context_id);
assert(sf_context != NULL);
- active_reqs = (MPI_Request *)calloc((size_t)(count + 2), sizeof(MPI_Request));
+ active_reqs = (MPI_Request *)calloc((size_t)(count + 2), sizeof(struct __mpi_req));
assert(active_reqs);
sf_async_reqs = (io_req_t **)calloc((size_t)count, sizeof(void *));
@@ -1206,7 +1204,7 @@ H5FD__read_vector_internal(hid_t h5_fid, hssize_t count, haddr_t addrs[], size_t
sf_context = get__subfiling_object(sf_context_id);
assert(sf_context != NULL);
- active_reqs = (MPI_Request *)calloc((size_t)(count + 2), sizeof(MPI_Request));
+ active_reqs = (MPI_Request *)calloc((size_t)(count + 2), sizeof(struct __mpi_req));
assert(active_reqs);
sf_async_reqs = (io_req_t **)calloc((size_t)count, sizeof(void *));
@@ -1274,7 +1272,7 @@ sf_shutdown_local_ioc(hid_t fid)
subfiling_context_t *sf_context = get__subfiling_object(context_id);
assert(sf_context != NULL);
if (sf_context->topology->rank_is_ioc) {
- sf_shutdown_flag = 1;
+ atomic_fetch_add(&sf_shutdown_flag, 1);
}
return 0;
}
@@ -1381,6 +1379,7 @@ ioc_main(int64_t context_id)
atomic_init(&sf_file_close_count, 0);
atomic_init(&sf_file_refcount, 0);
atomic_init(&sf_ioc_fini_refcount, 0);
+ atomic_init(&sf_shutdown_flag, 0);
atomic_init(&sf_ioc_ready, 1);
shutdown_requested = 0;
@@ -1431,7 +1430,6 @@ ioc_main(int64_t context_id)
incoming_requests[index].subfile_rank = subfile_rank;
incoming_requests[index].start_time = queue_start_time;
incoming_requests[index].buffer = NULL;
- incoming_requests[index].completed = 0;
tpool_add_work(&incoming_requests[index]);
if (index == max_work_depth - 1) {
atomic_init(&sf_workinprogress, 0);
@@ -1445,7 +1443,7 @@ ioc_main(int64_t context_id)
else {
usleep(delay);
}
- shutdown_requested = sf_shutdown_flag;
+ shutdown_requested = atomic_load(&sf_shutdown_flag);
}
if (incoming_requests) {
@@ -1453,7 +1451,7 @@ ioc_main(int64_t context_id)
}
/* Reset the shutdown flag */
- sf_shutdown_flag = 0;
+ atomic_init(&sf_shutdown_flag, 0);
return 0;
}
@@ -1598,7 +1596,11 @@ queue_write_indep(sf_work_request_t *msg, int subfile_rank, int source, MPI_Comm
return ret;
}
+ if (msg->serialize)
+ ioc__wait_for_serialize(msg);
+
fd = sf_context->sf_fid;
+
if (fd < 0) {
printf("[ioc(%d)] WARNING: %s called while subfile_fid = %d (closed)\n", subfile_rank, __func__, fd);
fflush(stdout);
@@ -1619,7 +1621,6 @@ queue_write_indep(sf_work_request_t *msg, int subfile_rank, int source, MPI_Comm
sf_queue_delay_time += t_queue_delay;
/* Done... */
- msg->completed = 1;
if (sf_eof > sf_context->sf_eof)
sf_context->sf_eof = sf_eof;
@@ -1740,56 +1741,58 @@ queue_read_indep(sf_work_request_t *msg, int subfile_rank, int source, MPI_Comm
/* ---------------------------------------------------
* Helper function for subfiling_open_file() see below
+ * Subfiles should be located in the same directory
+ * as the HDF5 file unless the user has provided
+ * an alternate directory name as indicated by the
+ * sf_context->subfile_prefix argument.
* ---------------------------------------------------*/
static void
-get__subfile_name(subfiling_context_t *sf_context, int64_t h5_file_id, int subfile_rank, char **_prefix,
+get__subfile_name(subfiling_context_t *sf_context, int64_t h5_file_id, int subfile_rank, char **_basename,
char **_subfile_dir, char *filepath)
{
- const char slash = '/';
- char workdir[PATH_MAX];
- char configdir[PATH_MAX];
-
char *prefix = NULL, *subfile_dir = NULL;
+ char *base = NULL;
int n_io_concentrators = sf_context->topology->n_io_concentrators;
- memset(workdir, 0, PATH_MAX);
- getcwd(workdir, PATH_MAX);
+ /* We require this to be non-null */
+ HDassert(sf_context);
- if ((prefix = sf_context->subfile_prefix) == NULL) {
- memset(configdir, 0, PATH_MAX);
- strncpy(configdir, sf_context->h5_filename, strlen(sf_context->h5_filename));
- prefix = dirname(configdir);
- }
+ prefix = (char *)malloc(PATH_MAX);
+ HDassert(prefix);
- size_t prefix_len = strlen(prefix);
- if (strcmp(prefix, workdir)) {
- if (prefix[prefix_len - 1] == slash) {
- if (sf_context->subfile_prefix)
- sprintf(filepath, "%s" SF_NODE_LOCAL_TEMPLATE, prefix, h5_file_id, subfile_rank,
- n_io_concentrators);
- else
- sprintf(filepath, "%s" SF_FILENAME_TEMPLATE, prefix, h5_file_id, subfile_rank,
- n_io_concentrators);
- }
- else {
- if (sf_context->subfile_prefix)
- sprintf(filepath, "%s/" SF_NODE_LOCAL_TEMPLATE, prefix, h5_file_id, subfile_rank,
- n_io_concentrators);
- else
- sprintf(filepath, "%s/" SF_FILENAME_TEMPLATE, prefix, h5_file_id, subfile_rank,
- n_io_concentrators);
- }
+ /* Under normal operation, we co-locate subfiles
+ * with the HDF5 file
+ */
+ strcpy(prefix, sf_context->h5_filename);
+ base = basename(prefix);
+ *_basename = strdup(base);
+
+ if (sf_context->subfile_prefix == NULL) {
+ subfile_dir = dirname(prefix);
+ *_subfile_dir = strdup(subfile_dir);
}
else {
- memset(configdir, 0, PATH_MAX);
- strcpy(configdir, sf_context->h5_filename);
- subfile_dir = dirname(configdir);
- sprintf(filepath, "%s/" SF_FILENAME_TEMPLATE, subfile_dir, h5_file_id, subfile_rank,
- n_io_concentrators);
+ /* Note: Users may specify a directory name which is inaccessable
+ * from where the current is running. In particular, "node-local"
+ * storage is not uniformly available to all processes.
+ * We would like to check if the user pathname unavailable and
+ * if so, we could default to creating the subfiles in the
+ * current directory. (?)
+ */
+ *_subfile_dir = strdup(sf_context->subfile_prefix);
}
- *_prefix = prefix;
- *_subfile_dir = subfile_dir;
+ /* The subfile naming should produce files of the following form:
+ * If we assume the HDF5 file is named ABC.h5, then subfiles
+ * will have names:
+ * ABC.h5.subfile_<file-number>_0_of_2,
+ * ABC.h5.subfile_<file-number>_1_of_2, and
+ * ABC.h5.subfile_<file-number>.config
+ */
+ sprintf(filepath, "%s/%s" SF_FILENAME_TEMPLATE, subfile_dir, base, h5_file_id, subfile_rank,
+ n_io_concentrators);
+ if (prefix)
+ HDfree(prefix);
}
/*-------------------------------------------------------------------------
@@ -1821,10 +1824,14 @@ get__subfile_name(subfiling_context_t *sf_context, int64_t h5_file_id, int subfi
int
subfiling_open_file(sf_work_request_t *msg, int subfile_rank, int flags)
{
- int errors = 0;
- char filepath[PATH_MAX];
+ int errors = 0;
+ char filepath[PATH_MAX];
+ char linebuf[PATH_MAX];
+
+ char * temp = NULL;
char * prefix = NULL;
char * subfile_dir = NULL;
+ char * base = NULL;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
double t_start = 0.0, t_end = 0.0;
@@ -1837,7 +1844,6 @@ subfiling_open_file(sf_work_request_t *msg, int subfile_rank, int flags)
/* Only allow the actual IO concentrator ranks to create sub-files */
if (subfile_rank >= 0) {
int k, retries = 2;
- char config[PATH_MAX];
int64_t h5_file_id = msg->header[1];
int64_t file_context_id = msg->header[2];
subfiling_context_t *sf_context = get__subfiling_object(file_context_id);
@@ -1850,20 +1856,20 @@ subfiling_open_file(sf_work_request_t *msg, int subfile_rank, int flags)
* and possibly (IFF our subfile_rank is 0) a config file.
*/
- get__subfile_name(sf_context, h5_file_id, subfile_rank, &prefix, &subfile_dir, filepath);
+ get__subfile_name(sf_context, h5_file_id, subfile_rank, &base, &subfile_dir, filepath);
sf_context->sf_filename = strdup(filepath);
assert(sf_context->sf_filename);
/* Check if we need to create the subfiles */
if (sf_context->sf_fid == -2) {
- const char *dotconfig = "-subfile_config";
- int n_io_concentrators = sf_context->topology->n_io_concentrators;
- int * io_concentrator = sf_context->topology->io_concentrator;
+ int n_io_concentrators = sf_context->topology->n_io_concentrators;
+ int *io_concentrator = sf_context->topology->io_concentrator;
for (k = 0; k < retries; k++) {
int fd;
if ((fd = HDopen(filepath, O_CREAT | O_RDWR | O_TRUNC, mode)) > 0) {
sf_context->sf_fid = fd;
+ sf_context->sf_eof = 0;
break;
}
}
@@ -1882,38 +1888,31 @@ subfiling_open_file(sf_work_request_t *msg, int subfile_rank, int flags)
errors++;
goto done;
}
-
- memset(config, 0, sizeof(filepath));
- sprintf(config, "%s%s", sf_context->h5_filename, dotconfig);
-
+ sprintf(filepath, "%s/%s.subfile_%ld.config", subfile_dir, base, h5_file_id);
+ /* SUBFILE rank 0 does the work creating a config file */
if ((subfile_rank == 0) && (flags & O_CREAT)) {
FILE *f = NULL;
/* If a config file already exists, AND
* the user wants to truncate subfiles (if they exist),
* then we should also truncate an existing config file.
*/
- if (access(config, flags) == 0) {
- truncate(config, 0);
+ if (access(filepath, flags) == 0) {
+ truncate(filepath, 0);
}
- f = HDfopen(config, "w+");
+ f = HDfopen(filepath, "w+");
if (f != NULL) {
- char linebuf[PATH_MAX];
sprintf(linebuf, "stripe_size=%ld\n", sf_context->sf_stripe_size);
- HDfwrite(linebuf, strlen(linebuf), 1, f);
+ HDfwrite(linebuf, 1, strlen(linebuf), f);
sprintf(linebuf, "aggregator_count=%d\n", n_io_concentrators);
- HDfwrite(linebuf, strlen(linebuf), 1, f);
+ HDfwrite(linebuf, 1, strlen(linebuf), f);
sprintf(linebuf, "hdf5_file=%s\n", sf_context->h5_filename);
- HDfwrite(linebuf, strlen(linebuf), 1, f);
+ HDfwrite(linebuf, 1, strlen(linebuf), f);
+ sprintf(linebuf, "subfile_dir=%s\n", subfile_dir);
for (k = 0; k < n_io_concentrators; k++) {
- if (prefix)
- sprintf(linebuf, "%s/%ld_node_local_temp_%d_of_%d:%d\n", prefix, h5_file_id,
- subfile_rank, n_io_concentrators, io_concentrator[k]);
- else
- sprintf(linebuf, "%ld_subfile_%d_of_%d:%d\n", h5_file_id, subfile_rank,
- n_io_concentrators, io_concentrator[k]);
-
- HDfwrite(linebuf, strlen(linebuf), 1, f);
+ sprintf(linebuf, "%s.subfile_%ld_%d_of_%d:%d\n", base, h5_file_id, subfile_rank,
+ n_io_concentrators, io_concentrator[k]);
+ HDfwrite(linebuf, 1, strlen(linebuf), f);
}
fclose(f);
@@ -1924,6 +1923,7 @@ subfiling_open_file(sf_work_request_t *msg, int subfile_rank, int flags)
goto done;
}
}
+
#ifndef NDEBUG
if (sf_verbose_flag) {
if (sf_logfile) {
@@ -1961,6 +1961,10 @@ subfiling_open_file(sf_work_request_t *msg, int subfile_rank, int flags)
done:
t_end = MPI_Wtime();
+ if (base)
+ HDfree(base);
+ if (subfile_dir)
+ HDfree(subfile_dir);
#ifndef NDEBUG
if (sf_verbose_flag) {
diff --git a/src/H5FDsubfiling.c b/src/H5FDsubfiling.c
index 27ed44a..b19df57 100644
--- a/src/H5FDsubfiling.c
+++ b/src/H5FDsubfiling.c
@@ -900,14 +900,16 @@ H5FD__subfiling_close(H5FD_t *_file)
{
H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file;
herr_t ret_value = SUCCEED; /* Return value */
- // subfiling_context_t *sf_context = NULL;
+ subfiling_context_t *sf_context = NULL;
FUNC_ENTER_NOAPI_NOINIT
/* Sanity check */
HDassert(file_ptr);
-#ifdef VERBOSE
+
sf_context = (subfiling_context_t *)get__subfiling_object(file_ptr->fa.common.context_id);
+
+#ifdef VERBOSE
if (sf_context->topology->rank_is_ioc)
printf("[%s %d] fd=%d\n", __func__, file_ptr->mpi_rank, sf_context->sf_fid);
else
@@ -918,6 +920,20 @@ H5FD__subfiling_close(H5FD_t *_file)
HSYS_GOTO_ERROR(H5E_IO, H5E_CANTCLOSEFILE, FAIL, "unable to close file")
}
+ if (sf_context != NULL) {
+ if (sf_context->subfile_prefix) {
+ HDfree(sf_context->subfile_prefix);
+ sf_context->subfile_prefix = NULL;
+ }
+ if (sf_context->sf_filename) {
+ HDfree(sf_context->sf_filename);
+ sf_context->sf_filename = NULL;
+ }
+ if (sf_context->h5_filename) {
+ HDfree(sf_context->h5_filename);
+ sf_context->h5_filename = NULL;
+ }
+ }
/* if set, close the copy of the plist for the underlying VFD. */
if ((H5I_INVALID_HID != file_ptr->fa.common.ioc_fapl_id) &&
(H5I_dec_ref(file_ptr->fa.common.ioc_fapl_id) < 0))
@@ -1099,13 +1115,65 @@ H5FD__subfiling_set_eoa(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, haddr_t a
/*-------------------------------------------------------------------------
* Function: H5FD_subfiling_get_eof
*
- * Purpose: Returns the end-of-file marker, which is the greater of
- * either the filesystem end-of-file or the HDF5 end-of-address
- * markers.
+ * Purpose: Returns the end-of-file marker from the filesystem
+ * perspective.
*
* Return: End of file address, the first address past the end of the
* "file", either the filesystem file or the HDF5 file.
*
+ * SUBFILING NOTE:
+ * The EOF calculation for subfiling is somewhat different
+ * than for the more traditional HDF5 file implementations.
+ * This statement derives from the fact that unlike "normal"
+ * HDF5 files, subfiling introduces a multi-file representation
+ * of a single HDF5 file. The plurality of sub-files represents
+ * a software RAID-0 based HDF5 file. As such, each sub-file
+ * contains a designated portion of the address space of the
+ * virtual HDF5 storage. We have no notion of HDF5 datatypes,
+ * datasets, metadata, or other HDF5 structures; only BYTES.
+ *
+ * The organization of the bytes within sub-files is consistent
+ * with the RAID-0 striping, i.e. there are IO Concentrators
+ * (IOCs) which correspond to a stripe-count (in Lustre) as
+ * well as a stripe_size. The combiniation of these two
+ * variables determines the "address" (a combination of IOC
+ * and a file offset) of any storage operation.
+ *
+ * Having a defined storage layout, the virtual file EOF
+ * calculation shoud be the MAXIMUM value returned by the
+ * collection of IOCs. Every MPI rank which hosts an IOC
+ * maintains it's own EOF by updating that value for each
+ * WRITE operation that completes, i.e. if a new local EOF
+ * is greater than the existing local EOF, the new EOF
+ * will replace the old. The local EOF calculation is as
+ * follows.
+ * 1. At file creation, each IOC is assigned a rank value
+ * (0 to N-1, where N is the total number of IOCs) and
+ * a 'sf_base_addr' = 'subfile_rank' * 'sf_stripe_size')
+ * we also determine the 'sf_blocksize_per_stripe' which
+ * is simply the 'sf_stripe_size' * 'n_ioc_concentrators'
+ *
+ * 2. For every write operation, the IOC recieves a message
+ * containing a file_offset and the data_size.
+ * 3. The file_offset + data_size are in turn used to
+ * create a stripe_id:
+ * IOC-(ioc_rank) IOC-(ioc_rank+1)
+ * |<- sf_base_address |<- sf_base_address |
+ * ID +--------------------+--------------------+
+ * 0:|<- sf_stripe_size ->|<- sf_stripe_size ->|
+ * 1:|<- sf_stripe_size ->|<- sf_stripe_size ->|
+ * ~ ~ ~
+ * N:|<- sf_stripe_size ->|<- sf_stripe_size ->|
+ * +--------------------+--------------------+
+ *
+ * The new 'stripe_id' is then used to calculate a
+ * potential new EOF:
+ * sf_eof = (stripe_id * sf_blocksize_per_stripe) + sf_base_addr
+ * + ((file_offset + data_size) % sf_stripe_size)
+ *
+ * 4. If (sf_eof > current_sf_eof), then current_sf_eof = sf_eof.
+ *
+ *
* Programmer: Richard Warren
*
*-------------------------------------------------------------------------
@@ -1208,11 +1276,12 @@ H5FD__subfiling_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATT
#endif
if (ioc_total > 1) {
+ size_t max_depth;
blocksize = sf_context->sf_blocksize_per_stripe;
#if 0 /* JRM */
size_t max_depth = (size_t)(size / blocksize) + 2;
#else /* JRM */
- size_t max_depth = (size / (size_t)blocksize) + 2;
+ max_depth = (size / (size_t)blocksize) + 2;
#endif /* JRM */
int next, ioc_count = 0, ioc_start = -1;
@@ -1447,11 +1516,12 @@ H5FD__subfiling_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_AT
#endif
if (ioc_total > 1) {
+ size_t max_depth;
blocksize = sf_context->sf_blocksize_per_stripe;
#if 0 /* JRM */
- size_t max_depth = (size_t)(size / blocksize) + 2;
+ size_t max_depth = (size_t)(size / blocksize) + 2;
#else /* JRM */
- size_t max_depth = (size_t)(size / (size_t)blocksize) + 2;
+ max_depth = (size_t)(size / (size_t)blocksize) + 2;
#endif /* JRM */
int next, ioc_count = 0, ioc_start = -1;
@@ -1507,13 +1577,13 @@ H5FD__subfiling_write(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_AT
size, /* (in) IO size */
1); /* (in) data extent of the 'type' assumes byte */
#else /* JRM */
- count = init__indep_io(sf_context, /* We use the context to look up config info */
+ count = init__indep_io(sf_context, /* We use the context to look up config info */
max_depth, ioc_total, (int64_t *)source_data_offset, /* (out) Memory offset */
(int64_t *)sf_data_size, /* (out) Length of this contiguous block */
(int64_t *)sf_offset, /* (out) File offset */
- &ioc_start, /* (out) IOC index corresponding to starting offset */
- &ioc_count, /* (out) number of actual IOCs used */
- offset, /* (in) Starting file offset */
+ &ioc_start, /* (out) IOC index corresponding to starting offset */
+ &ioc_count, /* (out) number of actual IOCs used */
+ offset, /* (in) Starting file offset */
(int64_t)size, /* (in) IO size */
1); /* (in) data extent of the 'type' assumes byte */
#endif /* JRM */
@@ -1840,7 +1910,7 @@ H5FD__subfiling_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5
H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file;
herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_NOAPI_NOINIT
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
HDassert(file);
@@ -1875,22 +1945,18 @@ H5FD__subfiling_truncate(H5FD_t *_file, hid_t H5_ATTR_UNUSED dxpl_id, hbool_t H5
static herr_t
H5FD__subfiling_lock(H5FD_t *_file, hbool_t rw)
{
- H5FD_subfiling_t *file_ptr = (H5FD_subfiling_t *)_file; /* VFD file struct */
+ H5FD_subfiling_t *file = (H5FD_subfiling_t *)_file; /* VFD file struct */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI_NOINIT
- HDassert(file_ptr);
-
- /* Set exclusive or shared lock based on rw status */
- if (file_ptr->fa.require_ioc) {
+ HDassert(file);
+ if (file->fa.require_ioc)
puts("Subfiling driver doesn't suport file locking");
- }
else {
- if (H5FD_lock(file_ptr->sf_file, rw) < 0)
+ if (H5FD_lock(file->sf_file, rw) < 0)
HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file")
} /* end if */
-
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5FD_subfiling_lock() */
@@ -1916,14 +1982,8 @@ H5FD__subfiling_unlock(H5FD_t *_file)
HDassert(file);
- if (HDflock(file->fd, LOCK_UN) < 0) {
- if (ENOSYS == errno)
- HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL,
- "file locking disabled on this file system (use "
- "HDF5_USE_FILE_LOCKING environment variable to override)")
- else
- HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to unlock file")
- } /* end if */
+ if (H5FD_unlock(file->sf_file) < 0)
+ HSYS_GOTO_ERROR(H5E_FILE, H5E_BADFILE, FAIL, "unable to lock file")
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -2069,7 +2129,7 @@ create__simple_vector(hid_t H5_ATTR_UNUSED file_space_id, void *memDataBuf, hadd
bufs[0] = nextBuf;
offsets[0] = addrBase;
- blocklens[0] = (hssize_t)((hssize_t)elements * type_extent);
+ blocklens[0] = (hssize_t)((hssize_t)elements * (hssize_t)type_extent);
if (*vlen < 0) {
*_offsets = offsets;
@@ -2246,9 +2306,10 @@ get__base_offset(int mpi_rank, int mpi_size, size_t dtype_extent, hid_t mem_spac
}
herr_t
-H5FD__dataset_write_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_t dtype_extent, int mpi_rank,
- int mpi_size, void *_dset, hid_t mem_type_id, hid_t mem_space_id,
- hid_t file_space_id, hid_t plist_id, const void *buf)
+H5FD__dataset_write_contiguous(hid_t H5_ATTR_UNUSED h5_file_id, haddr_t dataset_baseAddr, size_t dtype_extent,
+ int mpi_rank, int mpi_size, void H5_ATTR_UNUSED *_dset,
+ hid_t H5_ATTR_UNUSED mem_type_id, hid_t mem_space_id, hid_t file_space_id,
+ hid_t H5_ATTR_UNUSED plist_id, const void *buf)
{
herr_t ret_value = SUCCEED; /* Return value */
hssize_t num_elem_file = (hssize_t)-1, num_elem_mem = (hssize_t)-1;
@@ -2262,20 +2323,21 @@ H5FD__dataset_write_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_
FUNC_ENTER_PACKAGE
if ((num_elem_file = H5Sget_select_npoints(file_space_id)) < 0)
- puts("can't get number of points in file selection");
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't get number of points in file selection")
+
if ((num_elem_mem = H5Sget_select_npoints(mem_space_id)) < 0)
- puts("can't get number of points in memory selection");
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't get number of points in memory selection")
if (num_elem_file != num_elem_mem)
- puts("number of elements selected in file and memory dataspaces is "
- "different");
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL,
+ "number of elements selected"
+ " in file and memory dataspaces is different")
- if (H5S_get_validated_dataspace(mem_space_id, &mem_space) < 0) {
- puts("could not get a validated dataspace from mem_space_id");
- }
- if (H5S_get_validated_dataspace(file_space_id, &file_space) < 0) {
- puts("could not get a validated dataspace from file_space_id");
- }
+ if (H5S_get_validated_dataspace(mem_space_id, &mem_space) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "could not get a validated dataspace from mem_space_id")
+
+ if (H5S_get_validated_dataspace(file_space_id, &file_space) < 0)
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "could not get a validated dataspace from file_space_id")
if (num_elem_file > 0) {
sel_type = H5Sget_select_type(file_space_id);
@@ -2357,25 +2419,27 @@ done:
}
herr_t
-H5FD__dataset_read_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_t dtype_extent, int mpi_rank,
- int mpi_size, void *_dset, hid_t mem_type_id, hid_t mem_space_id,
- hid_t file_space_id, hid_t plist_id, void *buf)
+H5FD__dataset_read_contiguous(hid_t H5_ATTR_UNUSED h5_file_id, haddr_t dataset_baseAddr, size_t dtype_extent,
+ int mpi_rank, int mpi_size, void H5_ATTR_UNUSED *_dset,
+ hid_t H5_ATTR_UNUSED mem_type_id, hid_t mem_space_id, hid_t file_space_id,
+ hid_t H5_ATTR_UNUSED plist_id, void *buf)
{
- H5FD_t * dset = (H5FD_t *)_dset;
herr_t ret_value = SUCCEED; /* Return value */
hssize_t num_elem_file = -1, num_elem_mem = -1;
H5S_sel_type sel_type;
hssize_t sf_vlen = -1;
+ int status = 0;
FUNC_ENTER_PACKAGE
if ((num_elem_file = H5Sget_select_npoints(file_space_id)) < 0)
- puts("can't get number of points in file selection");
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't get number of points in file selection")
if ((num_elem_mem = H5Sget_select_npoints(mem_space_id)) < 0)
- puts("can't get number of points in memory selection");
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "can't get number of points in memory selection")
if (num_elem_file != num_elem_mem)
- puts("number of elements selected in file and memory dataspaces is "
- "different");
+ HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL,
+ "number of elements selected"
+ " in file and memory dataspaces is different")
if (num_elem_file > 0) {
sel_type = H5Sget_select_type(file_space_id);
@@ -2384,7 +2448,6 @@ H5FD__dataset_read_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_t
// printf("[%d] H5S_SEL_NONE\n", mpi_rank);
break;
case H5S_SEL_POINTS: {
- int status;
haddr_t rank_baseAddr;
rank_baseAddr =
get__base_offset(mpi_rank, mpi_size, dtype_extent, mem_space_id, file_space_id);
@@ -2397,7 +2460,6 @@ H5FD__dataset_read_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_t
break;
}
case H5S_SEL_HYPERSLABS: {
- int status;
haddr_t rank_baseAddr;
const H5S_t *mem_space;
const H5S_t *file_space;
@@ -2417,11 +2479,10 @@ H5FD__dataset_read_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_t
goto done;
}
if (status > 0) {
- hssize_t previous_vlen = sf_vlen;
if (sf_offsets == NULL)
sf_offsets = (haddr_t *)malloc(sizeof(haddr_t));
if (sf_sizes == NULL)
- sf_sizes = (hsize_t *)malloc(sizeof(hsize_t));
+ sf_sizes = (hssize_t *)malloc(sizeof(hsize_t));
if (sf_bufs == NULL)
sf_bufs = (void **)malloc(sizeof(void *));
sf_vlen = 1;
@@ -2430,13 +2491,12 @@ H5FD__dataset_read_contiguous(hid_t h5_file_id, haddr_t dataset_baseAddr, size_t
assert(sf_bufs);
sf_offsets[0] = rank_baseAddr;
- sf_sizes[0] = num_elem_mem * dtype_extent;
+ sf_sizes[0] = (hssize_t)((hssize_t)num_elem_mem * (hssize_t)dtype_extent);
sf_bufs[0] = buf;
}
break;
}
case H5S_SEL_ALL: {
- int status;
haddr_t rank_baseAddr;
rank_baseAddr =
get__base_offset(mpi_rank, mpi_size, dtype_extent, mem_space_id, file_space_id);
@@ -2558,7 +2618,7 @@ done:
#endif /* JRM */
void
-manage_client_logfile(int client_rank, int flag_value)
+manage_client_logfile(int H5_ATTR_UNUSED client_rank, int H5_ATTR_UNUSED flag_value)
{
#ifndef NDEBUG
if (flag_value) {
diff --git a/src/H5FDsubfiling_priv.h b/src/H5FDsubfiling_priv.h
index d26bf4c..4753423 100644
--- a/src/H5FDsubfiling_priv.h
+++ b/src/H5FDsubfiling_priv.h
@@ -326,15 +326,19 @@ typedef struct {
*/
typedef struct {
/* {Datasize, Offset, FileID} */
- int64_t header[3]; /* The basic RPC input plus */
- int tag; /* the supplied OPCODE tag */
- int source; /* Rank of who sent the message */
- int subfile_rank; /* The IOC rank */
- hid_t context_id; /* context to be used to complete */
- double start_time; /* the request, + time of receipt */
- /* from which we calc Time(queued) */
- void *buffer; /* for writes, we keep the buffer */
- int completed; /* around for awhile... */
+ int64_t header[3]; /* The basic RPC input plus */
+ int tag; /* the supplied OPCODE tag */
+ int source; /* Rank of who sent the message */
+ int subfile_rank; /* The IOC rank */
+ hid_t context_id; /* context to be used to complete */
+ double start_time; /* the request, + time of receipt */
+ /* from which we calc Time(queued) */
+ void *buffer; /* for writes, we keep the buffer */
+ /* around for awhile... */
+ volatile int in_progress; /* Not used! */
+ volatile int serialize; /* worker thread needs to wait while true */
+ volatile int dependents; //* If current work item has dependents */
+ int depend_id; /* work queue index of the dependent */
} sf_work_request_t;
typedef struct { /* Format of a context map entry */
diff --git a/src/Makefile.am b/src/Makefile.am
index e4e0c63..514f77c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -121,8 +121,12 @@ libhdf5_la_SOURCES= H5.c H5checksum.c H5dbg.c H5lib_settings.c H5system.c \
# Only compile parallel sources if necessary
if BUILD_PARALLEL_CONDITIONAL
- libhdf5_la_SOURCES += H5mpi.c H5ACmpio.c H5Cmpio.c H5Dmpio.c H5Fmpi.c H5FDmpi.c H5FDmpio.c H5Smpio.c \
- H5FDsubfiling.c H5FDsubfile_int.c H5FDsubfile_mpi.c H5FDioc.c H5FDioc_threads.c
+ libhdf5_la_SOURCES += H5mpi.c H5ACmpio.c H5Cmpio.c H5Dmpio.c H5Fmpi.c H5FDmpi.c H5FDmpio.c H5Smpio.c
+endif
+
+# Only compile the subfiling VFD if necessary
+if SUBFILING_VFD_CONDITIONAL
+ libhdf5_la_SOURCES += H5FDsubfiling.c H5FDsubfile_int.c H5FDsubfile_mpi.c H5FDioc.c H5FDioc_threads.c
endif
# Only compile the direct VFD if necessary
@@ -162,6 +166,21 @@ include_HEADERS = hdf5.h H5api_adpt.h H5overflow.h H5pubconf.h H5public.h H5vers
H5VLnative.h H5VLpassthru.h H5VLpublic.h \
H5Zpublic.h
+if HAVE_MERCURY_CONDITIONAL
+ include_HEADERS += mercury/src/util/mercury_thread.h \
+ mercury/src/util/mercury_thread_mutex.h mercury/src/util/mercury_thread_pool.h
+
+ libhdf5_la_SOURCES += mercury/src/util/mercury_atomic_queue.c \
+ mercury/src/util/mercury_dlog.c mercury/src/util/mercury_event.c \
+ mercury/src/util/mercury_hash_table.c mercury/src/util/mercury_log.c \
+ mercury/src/util/mercury_mem.c mercury/src/util/mercury_mem_pool.c \
+ mercury/src/util/mercury_poll.c mercury/src/util/mercury_request.c \
+ mercury/src/util/mercury_thread.c mercury/src/util/mercury_thread_condition.c \
+ mercury/src/util/mercury_thread_pool.c mercury/src/util/mercury_thread_mutex.c \
+ mercury/src/util/mercury_thread_rwlock.c mercury/src/util/mercury_thread_spin.c \
+ mercury/src/util/mercury_util.c
+endif
+
# install libhdf5.settings in lib directory
settingsdir=$(libdir)
settings_DATA=libhdf5.settings
diff --git a/src/mercury/COPYING b/src/mercury/COPYING
new file mode 100644
index 0000000..42095c5
--- /dev/null
+++ b/src/mercury/COPYING
@@ -0,0 +1,39 @@
+Copyright (C) 2013-2020, Argonne National Laboratory, Department of Energy,
+ UChicago Argonne, LLC and The HDF Group.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted for any purpose (including commercial purposes)
+provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions, and the following disclaimer in the documentation
+ and/or materials provided with the distribution.
+
+3. In addition, redistributions of modified forms of the source or binary
+ code must carry prominent notices stating that the original code was
+ changed and the date of the change.
+
+4. All publications or advertising materials mentioning features or use of
+ this software are asked, but not required, to acknowledge that it was
+ developed by ANL / the university of Chicago / The HDF Group and credit
+ the contributors.
+
+5. Neither the name of ANL / the university of Chicago / The HDF Group, nor
+ the name of any Contributor may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/src/mercury/README.md b/src/mercury/README.md
new file mode 100644
index 0000000..0e7e6e5
--- /dev/null
+++ b/src/mercury/README.md
@@ -0,0 +1,221 @@
+Mercury
+=======
+[![Build status][travis-ci-svg]][travis-ci-link]
+[![Latest version][mercury-release-svg]][mercury-release-link]
+
+ Mercury is an RPC framework specifically designed for use in HPC systems
+ that allows asynchronous transfer of parameters and execution requests,
+ as well as direct support of large data arguments. The network implementation
+ is abstracted, allowing easy porting to future systems and efficient use
+ of existing native transport mechanisms. Mercury's interface is generic
+ and allows any function call to be serialized.
+
+ Please see the accompanying COPYING file for license details.
+
+ Contributions and patches are welcomed but require a Contributor License
+ Agreement (CLA) to be filled out. Please contact us if you are interested
+ in contributing to Mercury by subscribing to the [mailing lists][mailing-lists].
+
+Architectures supported
+=======================
+
+ Architectures supported by MPI implementations are generally supported by the
+ network abstraction layer. The OFI libfabric plugin as well as the SM plugin
+ are stable and provide the best performance in most workloads. Libfabric
+ providers currently supported are: `tcp`, `verbs`, `psm2`, `gni`.
+ MPI and BMI (tcp) plugins are still supported but gradually being moved as
+ deprecated, therefore should only be used as fallback methods.
+ The CCI plugin is deprecated and underlying CCI transport plugins
+ (`tcp`, `sm`, `verbs`, `gni`) are no longer supported.
+
+ See the [plugin requirements](#plugin-requirements) section for
+ plugin requirement details.
+
+Documentation
+=============
+
+ Please see the documentation available on the mercury [website][documentation]
+ for a quick introduction to Mercury.
+
+Software requirements
+=====================
+
+ Compiling and running Mercury requires up-to-date versions of various
+ software packages. Beware that using excessively old versions of these
+ packages can cause indirect errors that are very difficult to track down.
+
+Plugin requirements
+-------------------
+
+To make use of the libfabric/OFI plugin, please refer to the libfabric build
+instructions available on this [page][libfabric].
+
+To make use of the native NA SM (shared-memory) plugin on Linux,
+the cross-memory attach (CMA) feature introduced in kernel v3.2 is required.
+The yama security module must also be configured to allow remote process memory
+to be accessed (see this [page][yama]). On MacOS, code signing with inclusion of
+the na_sm.plist file into the binary is currently required to allow process
+memory to be accessed.
+
+To make use of the BMI plugin, the most convenient way is to install it through
+spack or one can also do:
+
+ git clone https://xgitlab.cels.anl.gov/sds/bmi.git && cd bmi
+ ./prepare && ./configure --enable-shared --enable-bmi-only
+ make && make install
+
+To make use of the MPI plugin, Mercury requires a _well-configured_ MPI
+implementation (MPICH2 v1.4.1 or higher / OpenMPI v1.6 or higher) with
+`MPI_THREAD_MULTIPLE` available on targets that will accept remote
+connections. Processes that are _not_ accepting incoming connections are
+_not_ required to have a multithreaded level of execution.
+
+To make use of the CCI plugin, please refer to the CCI build instructions
+available on this [page][cci].
+
+Optional requirements
+---------------------
+
+For optional automatic code generation features (which are used for generating
+serialization and deserialization routines), the preprocessor subset of the
+BOOST library must be included (Boost v1.48 or higher is recommended).
+The library itself is therefore not necessary since only the header is used.
+Mercury includes those headers if one does not have BOOST installed and
+wants to make use of this feature.
+
+On Linux OpenPA v1.0.3 or higher is required (the version that is included
+with MPICH can also be used) for systems that do not have `stdatomic.h`
+(GCC version less than 4.9).
+
+Building
+========
+
+If you install the full sources, put the tarball in a directory where you
+have permissions (e.g., your home directory) and unpack it:
+
+ gzip -cd mercury-X.tar.gz | tar xvf -
+
+ or
+
+ bzip2 -dc mercury-X.tar.bz2 | tar xvf -
+
+Replace `'X'` with the version number of the package.
+
+(Optional) If you checked out the sources using git (without the `--recursive`
+option) and want to build the testing suite (which requires the kwsys
+submodule) or use checksums (which requires the mchecksum submodule), you need
+to issue from the root of the source directory the following command:
+
+ git submodule update --init
+
+Mercury makes use of the CMake build-system and requires that you do an
+out-of-source build. In order to do that, you must create a new build
+directory and run the `ccmake` command from it:
+
+ cd mercury-X
+ mkdir build
+ cd build
+ ccmake .. (where ".." is the relative path to the mercury-X directory)
+
+Type `'c'` multiple times and choose suitable options. Recommended options are:
+
+ BUILD_SHARED_LIBS ON (or OFF if the library you link
+ against requires static libraries)
+ BUILD_TESTING ON
+ Boost_INCLUDE_DIR /path/to/include/directory
+ CMAKE_INSTALL_PREFIX /path/to/install/directory
+ MERCURY_ENABLE_DEBUG ON/OFF
+ MERCURY_ENABLE_PARALLEL_TESTING ON/OFF
+ MERCURY_USE_BOOST_PP ON
+ MERCURY_USE_CHECKSUMS ON
+ MERCURY_USE_SYSTEM_BOOST ON/OFF
+ MERCURY_USE_SYSTEM_MCHECKSUM ON/OFF
+ MERCURY_USE_XDR OFF
+ NA_USE_BMI ON/OFF
+ NA_USE_MPI ON/OFF
+ NA_USE_CCI ON/OFF
+ NA_USE_OFI ON/OFF
+ NA_USE_SM ON/OFF
+
+Setting include directory and library paths may require you to toggle to
+the advanced mode by typing `'t'`. Once you are done and do not see any
+errors, type `'g'` to generate makefiles. Once you exit the CMake
+configuration screen and are ready to build the targets, do:
+
+ make
+
+(Optional) Verbose compile/build output:
+
+This is done by inserting `VERBOSE=1` in the `make` command. E.g.:
+
+ make VERBOSE=1
+
+Installing
+==========
+
+Assuming that the `CMAKE_INSTALL_PREFIX` has been set (see previous step)
+and that you have write permissions to the destination directory, do
+from the build directory:
+
+ make install
+
+Testing
+=======
+
+Tests can be run to check that basic RPC functionality (requests and bulk
+data transfers) is properly working. CTest is used to run the tests,
+simply run from the build directory:
+
+ ctest .
+
+(Optional) Verbose testing:
+
+This is done by inserting `-V` in the `ctest` command. E.g.:
+
+ ctest -V .
+
+Extra verbose information can be displayed by inserting `-VV`. E.g.:
+
+ ctest -VV .
+
+Some tests run with one server process and X client processes. To change the
+number of client processes that are being used, the `MPIEXEC_MAX_NUMPROCS`
+variable needs to be modified (toggle to advanced mode if you do not see
+it). The default value is automatically detected by CMake based on the number
+of cores that are available.
+Note that you need to run `make` again after the makefile generation
+to use the new value.
+
+FAQ
+===
+
+Below is a list of the most common questions.
+
+- _Q: Why am I getting undefined references to libfabric symbols?_
+
+ A: In rare occasions, multiple copies of the libfabric library are installed
+ on the same system. To make sure that you are using the correct copy of the
+ libfabric library, do:
+
+ ldconfig -p | grep libfabric
+
+ If the library returned is not the one that you would expect, make sure to
+ either set `LD_LIBRARY_PATH` or add an entry in your `/etc/ld.so.conf.d`
+ directory.
+
+- _Q: Is there any logging mechanism?_
+
+ A: To turn on error/warning/debug logs, the `HG_LOG_LEVEL` or
+ `HG_NA_LOG_LEVEL` environment variables can be set to either `error`,
+ `warning` or `debug` values. Note that for debugging output to be printed,
+ the CMake variable `MERCURY_ENABLE_DEBUG` must also be set at compile time.
+
+[mailing-lists]: http://mercury-hpc.github.io/help#mailing-lists
+[documentation]: http://mercury-hpc.github.io/documentation/
+[cci]: http://cci-forum.com/?page_id=46
+[libfabric]: https://github.com/ofiwg/libfabric
+[travis-ci-svg]: https://travis-ci.org/mercury-hpc/mercury.svg
+[travis-ci-link]: https://travis-ci.org/mercury-hpc/mercury
+[mercury-release-svg]: https://img.shields.io/github/release/mercury-hpc/mercury.svg
+[mercury-release-link]: https://github.com/mercury-hpc/mercury/releases/latest
+[yama]: https://www.kernel.org/doc/Documentation/security/Yama.txt
diff --git a/src/mercury/include/mercury.h b/src/mercury/include/mercury.h
new file mode 100644
index 0000000..9f44012
--- /dev/null
+++ b/src/mercury/include/mercury.h
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_H
+#define MERCURY_H
+
+#include "mercury_header.h"
+#include "mercury_types.h"
+
+#include "mercury_core.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* See mercury_types.h */
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* See mercury_types.h */
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get Mercury version number.
+ *
+ * \param major [OUT] pointer to unsigned integer
+ * \param minor [OUT] pointer to unsigned integer
+ * \param patch [OUT] pointer to unsigned integer
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Version_get(unsigned int *major, unsigned int *minor, unsigned int *patch);
+
+/**
+ * Convert error return code to string (null terminated).
+ *
+ * \param errnum [IN] error return code
+ *
+ * \return String
+ */
+HG_PUBLIC const char *HG_Error_to_string(hg_return_t errnum);
+
+/**
+ * Initialize the Mercury layer.
+ * Must be finalized with HG_Finalize().
+ *
+ * \param na_info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param na_listen [IN] listen for incoming connections
+ *
+ * \return Pointer to HG class or NULL in case of failure
+ */
+HG_PUBLIC hg_class_t *HG_Init(const char *na_info_string, hg_bool_t na_listen);
+
+/**
+ * Initialize the Mercury layer with options provided by init_info.
+ * Must be finalized with HG_Finalize().
+ * \remark HG_Init_opt() may become HG_Init() in the future.
+ *
+ * \param na_info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param na_listen [IN] listen for incoming connections
+ * \param hg_init_info [IN] (Optional) HG init info, NULL if no info
+ *
+ * \return Pointer to HG class or NULL in case of failure
+ */
+HG_PUBLIC hg_class_t *HG_Init_opt(const char *na_info_string, hg_bool_t na_listen,
+ const struct hg_init_info *hg_init_info);
+
+/**
+ * Finalize the Mercury layer.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Finalize(hg_class_t *hg_class);
+
+/**
+ * Clean up all temporary files that were created in previous HG instances.
+ * While temporary resources (e.g., tmp files) are cleaned up on a call
+ * to HG_Finalize(), this routine gives a chance to programs that terminate
+ * abnormally to easily clean up those resources.
+ */
+HG_PUBLIC void HG_Cleanup(void);
+
+/**
+ * Set the log level for HG. That setting is valid for all HG classes.
+ *
+ * \param level [IN] level string, valid values are:
+ * "none", "error", "warning", "debug"
+ */
+HG_PUBLIC void HG_Set_log_level(const char *level);
+
+/**
+ * Set the log sub-system for HG. That setting is valid for all HG classes.
+ *
+ * \param subsys [IN] string of subsystems, format is:
+ * subsys1,subsys2,subsys3,etc
+ * subsystem can be turned off, e.g.:
+ * ~subsys1
+ */
+HG_PUBLIC void HG_Set_log_subsys(const char *subsys);
+
+/**
+ * Obtain the name of the given class.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return the name of the class, or NULL if not a valid class
+ */
+static HG_INLINE const char *HG_Class_get_name(const hg_class_t *hg_class);
+
+/**
+ * Obtain the protocol of the given class.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return the name of the class's transport, or NULL if not a valid class
+ */
+static HG_INLINE const char *HG_Class_get_protocol(const hg_class_t *hg_class);
+
+/**
+ * Test whether class is listening or not.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return HG_TRUE if listening or HG_FALSE if not, or not a valid class
+ */
+static HG_INLINE hg_bool_t HG_Class_is_listening(const hg_class_t *hg_class);
+
+/**
+ * Obtain the maximum eager size for sending RPC inputs, for a given class.
+ * NOTE: This doesn't currently work when using XDR encoding.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return the maximum size, or 0 if hg_class is not a valid class or XDR is
+ * being used
+ */
+static HG_INLINE hg_size_t HG_Class_get_input_eager_size(const hg_class_t *hg_class);
+
+/**
+ * Obtain the maximum eager size for sending RPC outputs, for a given class.
+ * NOTE: This doesn't currently work when using XDR encoding.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return the maximum size, or 0 if hg_class is not a valid class or XDR is
+ * being used
+ */
+static HG_INLINE hg_size_t HG_Class_get_output_eager_size(const hg_class_t *hg_class);
+
+/**
+ * Set offset used for serializing / deserializing input. This allows upper
+ * layers to manually define a reserved space that can be used for the
+ * definition of custom headers. The actual input is encoded / decoded
+ * using the defined offset. By default, no offset is set.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param offset [IN] offset size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Class_set_input_offset(hg_class_t *hg_class, hg_size_t offset);
+
+/**
+ * Set offset used for serializing / deserializing output. This allows upper
+ * layers to manually define a reserved space that can be used for the
+ * definition of custom headers. The actual output is encoded / decoded
+ * using the defined offset. By default, no offset is set.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param offset [IN] offset size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Class_set_output_offset(hg_class_t *hg_class, hg_size_t offset);
+
+/**
+ * Associate user data to class. When HG_Finalize() is called,
+ * free_callback (if defined) is called to free the associated data.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param data [IN] pointer to user data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Class_set_data(hg_class_t *hg_class, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Retrieve previously associated data from a given class.
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE void *HG_Class_get_data(const hg_class_t *hg_class);
+
+/**
+ * Set callback to be called on HG handle creation. Handles are created
+ * both on HG_Create() and HG_Context_create() calls. This allows upper layers
+ * to create and attach data to a handle (using HG_Set_data()) and later
+ * retrieve it using HG_Get_data().
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Class_set_handle_create_callback(hg_class_t *hg_class,
+ hg_return_t (*callback)(hg_handle_t, void *),
+ void *arg);
+
+/**
+ * Create a new context. Must be destroyed by calling HG_Context_destroy().
+ *
+ * \remark This routine is internally equivalent to:
+ * - HG_Core_context_create()
+ * - If listening
+ * - HG_Core_context_post() with repost set to HG_TRUE
+ *
+ * \param hg_class [IN] pointer to HG class
+ *
+ * \return Pointer to HG context or NULL in case of failure
+ */
+HG_PUBLIC hg_context_t *HG_Context_create(hg_class_t *hg_class);
+
+/**
+ * Create a new context with a user-defined context identifier. The context
+ * identifier can be used to route RPC requests to specific contexts by using
+ * HG_Set_target_id().
+ * Context must be destroyed by calling HG_Context_destroy().
+ *
+ * \remark This routine is internally equivalent to:
+ * - HG_Core_context_create_id() with specified context ID
+ * - If listening
+ * - HG_Core_context_post() with repost set to HG_TRUE
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] user-defined context ID
+ *
+ * \return Pointer to HG context or NULL in case of failure
+ */
+HG_PUBLIC hg_context_t *HG_Context_create_id(hg_class_t *hg_class, hg_uint8_t id);
+
+/**
+ * Destroy a context created by HG_Context_create().
+ *
+ * \param context [IN] pointer to HG context
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Context_destroy(hg_context_t *context);
+
+/**
+ * Retrieve the class used to create the given context.
+ *
+ * \param context [IN] pointer to HG context
+ *
+ * \return Pointer to associated HG class or NULL if not a valid context
+ */
+static HG_INLINE hg_class_t *HG_Context_get_class(const hg_context_t *context);
+
+/**
+ * Retrieve context ID from context (max value of 255).
+ *
+ * \param context [IN] pointer to HG context
+ *
+ * \return Non-negative integer (max value of 255) or 0 if no ID has been set
+ */
+static HG_INLINE hg_uint8_t HG_Context_get_id(const hg_context_t *context);
+
+/**
+ * Associate user data to context. When HG_Context_destroy() is called,
+ * free_callback (if defined) is called to free the associated data.
+ *
+ * \param context [IN] pointer to HG context
+ * \param data [IN] pointer to user data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Context_set_data(hg_context_t *context, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Retrieve previously associated data from a given context.
+ *
+ * \param context [IN] pointer to HG context
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE void *HG_Context_get_data(const hg_context_t *context);
+
+/**
+ * Dynamically register a function func_name as an RPC as well as the
+ * RPC callback executed when the RPC request ID associated to func_name is
+ * received. Associate input and output proc to function ID, so that they can
+ * be used to serialize and deserialize function parameters.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param func_name [IN] unique name associated to function
+ * \param in_proc_cb [IN] pointer to input proc callback
+ * \param out_proc_cb [IN] pointer to output proc callback
+ * \param rpc_cb [IN] RPC callback
+ *
+ * \return unique ID associated to the registered function
+ */
+HG_PUBLIC hg_id_t HG_Register_name(hg_class_t *hg_class, const char *func_name, hg_proc_cb_t in_proc_cb,
+ hg_proc_cb_t out_proc_cb, hg_rpc_cb_t rpc_cb);
+
+/*
+ * Indicate whether HG_Register_name() has been called for the RPC specified by
+ * func_name.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param func_name [IN] function name
+ * \param id [OUT] registered RPC ID
+ * \param flag [OUT] pointer to boolean
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Registered_name(hg_class_t *hg_class, const char *func_name, hg_id_t *id,
+ hg_bool_t *flag);
+
+/**
+ * Dynamically register an RPC ID as well as the RPC callback executed when the
+ * RPC request ID is received. Associate input and output proc to id, so that
+ * they can be used to serialize and deserialize function parameters.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] ID to use to register RPC
+ * \param in_proc_cb [IN] pointer to input proc callback
+ * \param out_proc_cb [IN] pointer to output proc callback
+ * \param rpc_cb [IN] RPC callback
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Register(hg_class_t *hg_class, hg_id_t id, hg_proc_cb_t in_proc_cb,
+ hg_proc_cb_t out_proc_cb, hg_rpc_cb_t rpc_cb);
+
+/**
+ * Deregister RPC ID. Further requests with RPC ID will return an error, it
+ * is therefore up to the user to make sure that all requests for that RPC ID
+ * have been treated before it is unregistered.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] registered function ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Deregister(hg_class_t *hg_class, hg_id_t id);
+
+/**
+ * Indicate whether HG_Register() has been called.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] function ID
+ * \param flag [OUT] pointer to boolean
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Registered(hg_class_t *hg_class, hg_id_t id, hg_bool_t *flag);
+
+/**
+ * Indicate whether HG_Register() has been called, and if so return pointers
+ * to proc callback functions for the RPC.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] function ID
+ * \param flag [OUT] pointer to boolean
+ * \param in_proc_cb [OUT] pointer to input encoder cb
+ * \param out_proc_cb [OUT] pointer to output encoder cb
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Registered_proc_cb(hg_class_t *hg_class, hg_id_t id, hg_bool_t *flag,
+ hg_proc_cb_t *in_proc_cb, hg_proc_cb_t *out_proc_cb);
+
+/**
+ * Register and associate user data to registered function. When HG_Finalize()
+ * is called, free_callback (if defined) is called to free the registered
+ * data.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] registered function ID
+ * \param data [IN] pointer to data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Register_data(hg_class_t *hg_class, hg_id_t id, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Indicate whether HG_Register_data() has been called and return associated
+ * data.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] registered function ID
+ *
+ * \return Pointer to data or NULL
+ */
+HG_PUBLIC void *HG_Registered_data(hg_class_t *hg_class, hg_id_t id);
+
+/**
+ * Disable response for a given RPC ID. This allows an origin process to send an
+ * RPC to a target without waiting for a response. The RPC completes locally and
+ * the callback on the origin is therefore pushed to the completion queue once
+ * the RPC send is completed. By default, all RPCs expect a response to
+ * be sent back.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] registered function ID
+ * \param disable [IN] boolean (HG_TRUE to disable
+ * HG_FALSE to re-enable)
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Registered_disable_response(hg_class_t *hg_class, hg_id_t id, hg_bool_t disable);
+
+/**
+ * Check if response is disabled for a given RPC ID
+ * (i.e., HG_Registered_disable_response() has been called for this RPC ID).
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param id [IN] registered function ID
+ * \param disabled [OUT] boolean (HG_TRUE if disabled
+ * HG_FALSE if enabled)
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Registered_disabled_response(hg_class_t *hg_class, hg_id_t id, hg_bool_t *disabled);
+
+/**
+ * Lookup an addr from a peer address/name. Addresses need to be
+ * freed by calling HG_Addr_free(). After completion, user callback is
+ * placed into a completion queue and can be triggered using HG_Trigger().
+ *
+ * \param context [IN] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param name [IN] lookup name
+ * \param op_id [OUT] pointer to returned operation ID (unused)
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_lookup1(hg_context_t *context, hg_cb_t callback, void *arg, const char *name,
+ hg_op_id_t *op_id);
+
+/* This will map to HG_Addr_lookup2() in the future */
+#ifndef HG_Addr_lookup
+#define HG_Addr_lookup HG_Addr_lookup1
+#endif
+
+/**
+ * Lookup an addr from a peer address/name. Addresses need to be
+ * freed by calling HG_Addr_free().
+ *
+ * \remark This is the immediate version of HG_Addr_lookup1().
+ *
+ * \param hg_class [IN/OUT] pointer to HG class
+ * \param name [IN] lookup name
+ * \param addr [OUT] pointer to abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_lookup2(hg_class_t *hg_class, const char *name, hg_addr_t *addr);
+
+/**
+ * Free the addr.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_free(hg_class_t *hg_class, hg_addr_t addr);
+
+/**
+ * Hint that the address is no longer valid. This may happen if the peer is
+ * no longer responding. This can be used to force removal of the
+ * peer address from the list of the peers, before freeing it and reclaim
+ * resources.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_set_remove(hg_class_t *hg_class, hg_addr_t addr);
+
+/**
+ * Access self address. Address must be freed with HG_Addr_free().
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param addr [OUT] pointer to abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_self(hg_class_t *hg_class, hg_addr_t *addr);
+
+/**
+ * Duplicate an existing HG abstract address. The duplicated address can be
+ * stored for later use and the origin address be freed safely. The duplicated
+ * address must be freed with HG_Addr_free().
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param addr [IN] abstract address
+ * \param new_addr [OUT] pointer to abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_dup(hg_class_t *hg_class, hg_addr_t addr, hg_addr_t *new_addr);
+
+/**
+ * Compare two addresses.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param addr1 [IN] abstract address
+ * \param addr2 [IN] abstract address
+ *
+ * \return HG_TRUE if addresses are determined to be equal, HG_FALSE otherwise
+ */
+HG_PUBLIC hg_bool_t HG_Addr_cmp(hg_class_t *hg_class, hg_addr_t addr1, hg_addr_t addr2);
+
+/**
+ * Convert an addr to a string (returned string includes the terminating
+ * null byte '\0'). If buf is NULL, the address is not converted and only
+ * the required size of the buffer is returned. If the input value passed
+ * through buf_size is too small, HG_SIZE_ERROR is returned and the buf_size
+ * output is set to the minimum size required.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param buf [IN/OUT] pointer to destination buffer
+ * \param buf_size [IN/OUT] pointer to buffer size
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Addr_to_string(hg_class_t *hg_class, char *buf, hg_size_t *buf_size, hg_addr_t addr);
+
+/**
+ * Initiate a new HG RPC using the specified function ID and the local/remote
+ * target defined by addr. The HG handle created can be used to query input
+ * and output, as well as issuing the RPC by calling HG_Forward().
+ * After completion the handle must be freed using HG_Destroy().
+ *
+ * \param context [IN] pointer to HG context
+ * \param addr [IN] abstract network address of destination
+ * \param id [IN] registered function ID
+ * \param handle [OUT] pointer to HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Create(hg_context_t *context, hg_addr_t addr, hg_id_t id, hg_handle_t *handle);
+
+/**
+ * Destroy HG handle. Decrement reference count, resources associated to the
+ * handle are freed when the reference count is null.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Destroy(hg_handle_t handle);
+
+/**
+ * Reset an existing HG handle to make it reusable for RPC forwarding.
+ * Both target address and RPC ID can be modified at this time.
+ * Operations on that handle must be completed in order to reset that handle
+ * safely.
+ *
+ * \param handle [IN] HG handle
+ * \param addr [IN] abstract network address of destination
+ * \param id [IN] registered function ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Reset(hg_handle_t handle, hg_addr_t addr, hg_id_t id);
+
+/**
+ * Increment ref count on handle.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Ref_incr(hg_handle_t hg_handle);
+
+/**
+ * Retrieve ref count from handle.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Non-negative value or negative if the handle is not valid
+ */
+static HG_INLINE hg_int32_t HG_Ref_get(hg_handle_t handle);
+
+/**
+ * Get info from handle.
+ *
+ * \remark Users must call HG_Addr_dup() to safely re-use the addr field.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Pointer to info or NULL in case of failure
+ */
+static HG_INLINE const struct hg_info *HG_Get_info(hg_handle_t handle);
+
+/**
+ * Associate user data to handle. When HG_Destroy() is called,
+ * free_callback (if defined) is called to free the associated data.
+ *
+ * \param handle [IN] HG handle
+ * \param data [IN] pointer to user data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Set_data(hg_handle_t handle, void *data, void (*free_callback)(void *));
+
+/**
+ * Retrieve previously associated data from a given handle.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE void *HG_Get_data(hg_handle_t handle);
+
+/**
+ * Get input from handle (requires registration of input proc to deserialize
+ * parameters). Input must be freed using HG_Free_input().
+ *
+ * \remark This is equivalent to:
+ * - HG_Core_get_input()
+ * - Call hg_proc to deserialize parameters
+ *
+ * \param handle [IN] HG handle
+ * \param in_struct [IN/OUT] pointer to input structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Get_input(hg_handle_t handle, void *in_struct);
+
+/**
+ * Free resources allocated when deserializing the input.
+ * User may copy parameters contained in the input structure before calling
+ * HG_Free_input().
+ *
+ * \param handle [IN] HG handle
+ * \param in_struct [IN/OUT] pointer to input structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Free_input(hg_handle_t handle, void *in_struct);
+
+/**
+ * Get output from handle (requires registration of output proc to deserialize
+ * parameters). Output must be freed using HG_Free_output().
+ *
+ * \remark This is equivalent to:
+ * - HG_Core_get_output()
+ * - Call hg_proc to deserialize parameters
+ *
+ *
+ * \param handle [IN] HG handle
+ * \param out_struct [IN/OUT] pointer to output structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Get_output(hg_handle_t handle, void *out_struct);
+
+/**
+ * Free resources allocated when deserializing the output.
+ * User may copy parameters contained in the output structure before calling
+ * HG_Free_output().
+ *
+ * \param handle [IN] HG handle
+ * \param out_struct [IN/OUT] pointer to input structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Free_output(hg_handle_t handle, void *out_struct);
+
+/**
+ * Get raw input buffer from handle that can be used for encoding and decoding
+ * parameters.
+ *
+ * \remark Can be used for manual encoding / decoding when HG proc routines
+ * cannot be automatically used or there is need for special handling before
+ * HG_Get_input() can be called, for instance when using a custom header.
+ * To use proc routines conjunctively, HG_Class_set_input_offset() can be used
+ * to define the offset at which HG_Forward() / HG_Get_input() will start
+ * encoding / decoding the input parameters.
+ *
+ * \remark in_buf_size argument will be ignored if NULL
+ *
+ * \param handle [IN] HG handle
+ * \param in_buf [OUT] pointer to input buffer
+ * \param in_buf_size [OUT] pointer to input buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Get_input_buf(hg_handle_t handle, void **in_buf, hg_size_t *in_buf_size);
+
+/**
+ * Get raw output buffer from handle that can be used for encoding and decoding
+ * parameters.
+ *
+ * \remark Can be used for manual encoding / decoding when HG proc routines
+ * cannot be automatically used or there is need for special handling before
+ * HG_Get_output() can be called, for instance when using a custom header.
+ * To use proc routines conjunctively, HG_Class_set_output_offset() can be used
+ * to define the offset at which HG_Respond() / HG_Get_output() will start
+ * encoding / decoding the output parameters.
+ *
+ * \remark out_buf_size argument will be ignored if NULL
+ *
+ * \param handle [IN] HG handle
+ * \param out_buf [OUT] pointer to output buffer
+ * \param out_buf_size [OUT] pointer to output buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Get_output_buf(hg_handle_t handle, void **out_buf, hg_size_t *out_buf_size);
+
+/**
+ * Get raw extra input buffer from handle that can be used for encoding and
+ * decoding parameters. This buffer is only valid if the input payload is large
+ * enough that it cannot fit into an eager buffer.
+ *
+ * \remark NULL pointer will be returned if there is no associated buffer.
+ *
+ * \remark in_buf_size argument will be ignored if NULL.
+ *
+ * \param handle [IN] HG handle
+ * \param in_buf [OUT] pointer to input buffer
+ * \param in_buf_size [OUT] pointer to input buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Get_input_extra_buf(hg_handle_t handle, void **in_buf, hg_size_t *in_buf_size);
+
+/**
+ * Get raw extra output buffer from handle that can be used for encoding and
+ * decoding parameters. This buffer is only valid if the output payload is large
+ * enough that it cannot fit into an eager buffer.
+ *
+ * \remark NULL pointer will be returned if there is no associated buffer.
+ *
+ * \remark out_buf_size argument will be ignored if NULL.
+ *
+ * \param handle [IN] HG handle
+ * \param out_buf [OUT] pointer to output buffer
+ * \param out_buf_size [OUT] pointer to output buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Get_output_extra_buf(hg_handle_t handle, void **out_buf, hg_size_t *out_buf_size);
+
+/**
+ * Set target context ID that will receive and process the RPC request
+ * (ID is defined on target context creation, see HG_Context_create_id()).
+ *
+ * \param handle [IN] HG handle
+ * \param id [IN] user-defined target context ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Set_target_id(hg_handle_t handle, hg_uint8_t id);
+
+/**
+ * Forward a call to a local/remote target using an existing HG handle.
+ * Input structure can be passed and parameters serialized using a previously
+ * registered input proc. After completion, user callback is placed into a
+ * completion queue and can be triggered using HG_Trigger(). RPC output can
+ * be queried using HG_Get_output() and freed using HG_Free_output().
+ *
+ * \remark This routine is internally equivalent to:
+ * - HG_Core_get_input()
+ * - Call hg_proc to serialize parameters
+ * - HG_Core_forward()
+ *
+ * \param handle [IN] HG handle
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param in_struct [IN] pointer to input structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Forward(hg_handle_t handle, hg_cb_t callback, void *arg, void *in_struct);
+
+/**
+ * Respond back to origin using an existing HG handle.
+ * Output structure can be passed and parameters serialized using a previously
+ * registered output proc. After completion, user callback is placed into a
+ * completion queue and can be triggered using HG_Trigger().
+ *
+ * \remark This routine is internally equivalent to:
+ * - HG_Core_get_output()
+ * - Call hg_proc to serialize parameters
+ * - HG_Core_respond()
+ *
+ * \param handle [IN] HG handle
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param out_struct [IN] pointer to output structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Respond(hg_handle_t handle, hg_cb_t callback, void *arg, void *out_struct);
+
+/**
+ * Try to progress RPC execution for at most timeout until timeout is reached or
+ * any completion has occurred.
+ * Progress should not be considered as wait, in the sense that it cannot be
+ * assumed that completion of a specific operation will occur only when
+ * progress is called.
+ *
+ * \param context [IN] pointer to HG context
+ * \param timeout [IN] timeout (in milliseconds)
+ *
+ * \return HG_SUCCESS if any completion has occurred / HG error code otherwise
+ */
+HG_PUBLIC hg_return_t HG_Progress(hg_context_t *context, unsigned int timeout);
+
+/**
+ * Execute at most max_count callbacks. If timeout is non-zero, wait up to
+ * timeout before returning. Function can return when at least one or more
+ * callbacks are triggered (at most max_count).
+ *
+ * \param context [IN] pointer to HG context
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param max_count [IN] maximum number of callbacks triggered
+ * \param actual_count [IN] actual number of callbacks triggered
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Trigger(hg_context_t *context, unsigned int timeout, unsigned int max_count,
+ unsigned int *actual_count);
+
+/**
+ * Cancel an ongoing operation.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return HG_SUCCESS or HG_CANCEL_ERROR or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Cancel(hg_handle_t handle);
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/* HG class */
+struct hg_class {
+ hg_core_class_t *core_class; /* Core class */
+ hg_size_t in_offset; /* Input offset */
+ hg_size_t out_offset; /* Output offset */
+};
+
+/* HG context */
+struct hg_context {
+ hg_core_context_t *core_context; /* Core context */
+ hg_class_t * hg_class; /* HG class */
+};
+
+/* HG handle */
+struct hg_handle {
+ struct hg_info info; /* HG info */
+ hg_core_handle_t core_handle; /* Core handle */
+ void * data; /* User data */
+ void (*data_free_callback)(void *); /* User data free callback */
+};
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const char *
+HG_Class_get_name(const hg_class_t *hg_class)
+{
+ return HG_Core_class_get_name(hg_class->core_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const char *
+HG_Class_get_protocol(const hg_class_t *hg_class)
+{
+ return HG_Core_class_get_protocol(hg_class->core_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_bool_t
+HG_Class_is_listening(const hg_class_t *hg_class)
+{
+ return HG_Core_class_is_listening(hg_class->core_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+HG_Class_get_input_eager_size(const hg_class_t *hg_class)
+{
+ hg_size_t core = HG_Core_class_get_input_eager_size(hg_class->core_class),
+ header = hg_header_get_size(HG_INPUT);
+
+ return (core > header) ? core - header : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+HG_Class_get_output_eager_size(const hg_class_t *hg_class)
+{
+ hg_size_t core = HG_Core_class_get_output_eager_size(hg_class->core_class),
+ header = hg_header_get_size(HG_OUTPUT);
+
+ return (core > header) ? core - header : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Class_set_input_offset(hg_class_t *hg_class, hg_size_t offset)
+{
+ /* Extra input header must not be larger than eager size */
+ if (offset > HG_Class_get_input_eager_size(hg_class))
+ return HG_INVALID_ARG;
+
+ hg_class->in_offset = offset;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Class_set_output_offset(hg_class_t *hg_class, hg_size_t offset)
+{
+ /* Extra output header must not be larger than eager size */
+ if (offset > HG_Class_get_output_eager_size(hg_class))
+ return HG_INVALID_ARG;
+
+ hg_class->out_offset = offset;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Class_set_data(hg_class_t *hg_class, void *data, void (*free_callback)(void *))
+{
+ return HG_Core_class_set_data(hg_class->core_class, data, free_callback);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+HG_Class_get_data(const hg_class_t *hg_class)
+{
+ return HG_Core_class_get_data(hg_class->core_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_class_t *
+ HG_Context_get_class(const hg_context_t *context)
+{
+ return context->hg_class;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_uint8_t
+HG_Context_get_id(const hg_context_t *context)
+{
+ return HG_Core_context_get_id(context->core_context);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Context_set_data(hg_context_t *context, void *data, void (*free_callback)(void *))
+{
+ return HG_Core_context_set_data(context->core_context, data, free_callback);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+HG_Context_get_data(const hg_context_t *context)
+{
+ return HG_Core_context_get_data(context->core_context);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Ref_incr(hg_handle_t handle)
+{
+ return HG_Core_ref_incr(handle->core_handle);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_int32_t
+HG_Ref_get(hg_handle_t handle)
+{
+ return HG_Core_ref_get(handle->core_handle);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const struct hg_info *
+HG_Get_info(hg_handle_t handle)
+{
+ return &handle->info;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Set_data(hg_handle_t handle, void *data, void (*free_callback)(void *))
+{
+ handle->data = data;
+ handle->data_free_callback = free_callback;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+HG_Get_data(hg_handle_t handle)
+{
+ return handle->data;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Set_target_id(hg_handle_t handle, hg_uint8_t id)
+{
+ handle->info.context_id = id;
+
+ return HG_Core_set_target_id(handle->core_handle, id);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_H */
diff --git a/src/mercury/include/mercury_atomic.h b/src/mercury/include/mercury_atomic.h
new file mode 100644
index 0000000..d5a1417
--- /dev/null
+++ b/src/mercury/include/mercury_atomic.h
@@ -0,0 +1,625 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_ATOMIC_H
+#define MERCURY_ATOMIC_H
+
+#include "mercury_util_config.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+typedef struct {
+ volatile LONG value;
+} hg_atomic_int32_t;
+typedef struct {
+ volatile LONGLONG value;
+} hg_atomic_int64_t;
+#define HG_ATOMIC_VAR_INIT(x) \
+ { \
+ (x) \
+ }
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+#include <opa_primitives.h>
+typedef OPA_int_t hg_atomic_int32_t;
+typedef OPA_ptr_t hg_atomic_int64_t; /* OPA has only limited 64-bit support */
+#define HG_ATOMIC_VAR_INIT(x) OPA_PTR_T_INITIALIZER(x)
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+#ifndef __cplusplus
+#include <stdatomic.h>
+typedef atomic_int hg_atomic_int32_t;
+#if (HG_UTIL_ATOMIC_LONG_WIDTH == 8) && !defined(__APPLE__)
+typedef atomic_long hg_atomic_int64_t;
+#else
+typedef atomic_llong hg_atomic_int64_t;
+#endif
+#else
+#include <atomic>
+typedef std::atomic_int hg_atomic_int32_t;
+#if (HG_UTIL_ATOMIC_LONG_WIDTH == 8) && !defined(__APPLE__)
+typedef std::atomic_long hg_atomic_int64_t;
+#else
+typedef std::atomic_llong hg_atomic_int64_t;
+#endif
+using std::atomic_fetch_add_explicit;
+using std::atomic_thread_fence;
+using std::memory_order_acq_rel;
+using std::memory_order_acquire;
+using std::memory_order_release;
+#endif
+#define HG_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x)
+#elif defined(__APPLE__)
+#include <libkern/OSAtomic.h>
+typedef struct {
+ volatile hg_util_int32_t value;
+} hg_atomic_int32_t;
+typedef struct {
+ volatile hg_util_int64_t value;
+} hg_atomic_int64_t;
+#define HG_ATOMIC_VAR_INIT(x) \
+ { \
+ (x) \
+ }
+#else
+#error "Not supported on this platform."
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Init atomic value (32-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_init32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * Set atomic value (32-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_set32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * Get atomic value (32-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ *
+ * \return Value of the atomic integer
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_get32(hg_atomic_int32_t *ptr);
+
+/**
+ * Increment atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ *
+ * \return Incremented value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_incr32(hg_atomic_int32_t *ptr);
+
+/**
+ * Decrement atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ *
+ * \return Decremented value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_decr32(hg_atomic_int32_t *ptr);
+
+/**
+ * OR atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param value [IN] value to OR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_or32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * XOR atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param value [IN] value to XOR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_xor32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * AND atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param value [IN] value to AND with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_and32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * Compare and swap values (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param compare_value [IN] value to compare to
+ * \param swap_value [IN] value to swap with if ptr value is equal to
+ * compare value
+ *
+ * \return HG_UTIL_TRUE if swapped or HG_UTIL_FALSE
+ */
+static HG_UTIL_INLINE hg_util_bool_t hg_atomic_cas32(hg_atomic_int32_t *ptr, hg_util_int32_t compare_value,
+ hg_util_int32_t swap_value);
+
+/**
+ * Init atomic value (64-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_init64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * Set atomic value (64-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic64 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_set64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * Get atomic value (64-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic64 integer
+ *
+ * \return Value of the atomic integer
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_get64(hg_atomic_int64_t *ptr);
+
+/**
+ * Increment atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ *
+ * \return Incremented value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_incr64(hg_atomic_int64_t *ptr);
+
+/**
+ * Decrement atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ *
+ * \return Decremented value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_decr64(hg_atomic_int64_t *ptr);
+
+/**
+ * OR atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param value [IN] value to OR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_or64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * XOR atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param value [IN] value to XOR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_xor64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * AND atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param value [IN] value to AND with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_and64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * Compare and swap values (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param compare_value [IN] value to compare to
+ * \param swap_value [IN] value to swap with if ptr value is equal to
+ * compare value
+ *
+ * \return HG_UTIL_TRUE if swapped or HG_UTIL_FALSE
+ */
+static HG_UTIL_INLINE hg_util_bool_t hg_atomic_cas64(hg_atomic_int64_t *ptr, hg_util_int64_t compare_value,
+ hg_util_int64_t swap_value);
+
+/**
+ * Memory barrier.
+ *
+ */
+static HG_UTIL_INLINE void hg_atomic_fence(void);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_init32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+#if defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ atomic_init(ptr, value);
+#else
+ hg_atomic_set32(ptr, value);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_set32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+#if defined(_WIN32)
+ ptr->value = value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ OPA_store_int(ptr, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_store_explicit(ptr, value, memory_order_release);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+#error "Not supported on this platform."
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_get32(hg_atomic_int32_t *ptr)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = ptr->value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = OPA_load_int(ptr);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_load_explicit(ptr, memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = ptr->value;
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_incr32(hg_atomic_int32_t *ptr)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedIncrementNoFence(&ptr->value);
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = OPA_fetch_and_incr_int(ptr) + 1;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_add_explicit(ptr, 1, memory_order_acq_rel) + 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicIncrement32(&ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_decr32(hg_atomic_int32_t *ptr)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedDecrementNoFence(&ptr->value);
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = OPA_fetch_and_decr_int(ptr) - 1;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_sub_explicit(ptr, 1, memory_order_acq_rel) - 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicDecrement32(&ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_or32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedOrNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_or_explicit(ptr, value, memory_order_acq_rel);
+#elif defined(__APPLE__)
+ ret = OSAtomicOr32Orig((uint32_t)value, (volatile uint32_t *)&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get32(ptr);
+ } while (!hg_atomic_cas32(ptr, ret, (ret | value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_xor32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedXorNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_xor_explicit(ptr, value, memory_order_acq_rel);
+#elif defined(__APPLE__)
+ ret = OSAtomicXor32Orig((uint32_t)value, (volatile uint32_t *)&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get32(ptr);
+ } while (!hg_atomic_cas32(ptr, ret, (ret ^ value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_and32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedAndNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_and_explicit(ptr, value, memory_order_acq_rel);
+#elif defined(__APPLE__)
+ ret = OSAtomicAnd32Orig((uint32_t)value, (volatile uint32_t *)&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get32(ptr);
+ } while (!hg_atomic_cas32(ptr, ret, (ret & value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_bool_t
+hg_atomic_cas32(hg_atomic_int32_t *ptr, hg_util_int32_t compare_value, hg_util_int32_t swap_value)
+{
+ hg_util_bool_t ret;
+
+#if defined(_WIN32)
+ ret = (compare_value == InterlockedCompareExchangeNoFence(&ptr->value, swap_value, compare_value));
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = (hg_util_bool_t)(compare_value == OPA_cas_int(ptr, compare_value, swap_value));
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_compare_exchange_strong_explicit(ptr, &compare_value, swap_value, memory_order_acq_rel,
+ memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = OSAtomicCompareAndSwap32(compare_value, swap_value, &ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_init64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+#if defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ atomic_init(ptr, value);
+#else
+ hg_atomic_set64(ptr, value);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_set64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+#if defined(_WIN32)
+ ptr->value = value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ OPA_store_ptr(ptr, (void *)value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_store_explicit(ptr, value, memory_order_release);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+#error "Not supported on this platform."
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_get64(hg_atomic_int64_t *ptr)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = ptr->value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = (hg_util_int64_t)OPA_load_ptr(ptr);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_load_explicit(ptr, memory_order_acquire);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_incr64(hg_atomic_int64_t *ptr)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedIncrementNoFence64(&ptr->value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_add_explicit(ptr, 1L, memory_order_acq_rel) + 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicIncrement64(&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, ret + 1));
+ ret++;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_decr64(hg_atomic_int64_t *ptr)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedDecrementNoFence64(&ptr->value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_sub_explicit(ptr, 1L, memory_order_acq_rel) - 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicDecrement64(&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, ret - 1));
+ ret--;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_or64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedOr64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_or_explicit(ptr, value, memory_order_acq_rel);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, (ret | value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_xor64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedXor64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_xor_explicit(ptr, value, memory_order_acq_rel);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, (ret ^ value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_and64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedAnd64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_and_explicit(ptr, value, memory_order_acq_rel);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, (ret & value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_bool_t
+hg_atomic_cas64(hg_atomic_int64_t *ptr, hg_util_int64_t compare_value, hg_util_int64_t swap_value)
+{
+ hg_util_bool_t ret;
+
+#if defined(_WIN32)
+ ret = (compare_value == InterlockedCompareExchangeNoFence64(&ptr->value, swap_value, compare_value));
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = (hg_util_bool_t)(compare_value ==
+ (hg_util_int64_t)OPA_cas_ptr(ptr, (void *)compare_value, (void *)swap_value));
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_compare_exchange_strong_explicit(ptr, &compare_value, swap_value, memory_order_acq_rel,
+ memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = OSAtomicCompareAndSwap64(compare_value, swap_value, &ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_fence()
+{
+#if defined(_WIN32)
+ MemoryBarrier();
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ OPA_read_write_barrier();
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_thread_fence(memory_order_acq_rel);
+#elif defined(__APPLE__)
+ OSMemoryBarrier();
+#else
+#error "Not supported on this platform."
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_ATOMIC_H */
diff --git a/src/mercury/include/mercury_atomic_queue.h b/src/mercury/include/mercury_atomic_queue.h
new file mode 100644
index 0000000..61b5128
--- /dev/null
+++ b/src/mercury/include/mercury_atomic_queue.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Implementation derived from:
+ * https://github.com/freebsd/freebsd/blob/master/sys/sys/buf_ring.h
+ *
+ * -
+ * Copyright (c) 2007-2009 Kip Macy <kmacy@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef MERCURY_ATOMIC_QUEUE_H
+#define MERCURY_ATOMIC_QUEUE_H
+
+#include "mercury_atomic.h"
+#include "mercury_mem.h"
+
+/* For busy loop spinning */
+#ifndef cpu_spinwait
+#if defined(_WIN32)
+#define cpu_spinwait YieldProcessor
+#elif defined(__x86_64__) || defined(__i386__)
+#include <immintrin.h>
+#define cpu_spinwait _mm_pause
+#elif defined(__arm__)
+#define cpu_spinwait() __asm__ __volatile__("yield")
+#else
+#warning "Processor yield is not supported on this architecture."
+#define cpu_spinwait(x)
+#endif
+#endif
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+struct hg_atomic_queue {
+ hg_atomic_int32_t prod_head;
+ hg_atomic_int32_t prod_tail;
+ unsigned int prod_size;
+ unsigned int prod_mask;
+ hg_util_uint64_t drops;
+ hg_atomic_int32_t cons_head __attribute__((aligned(HG_MEM_CACHE_LINE_SIZE)));
+ hg_atomic_int32_t cons_tail;
+ unsigned int cons_size;
+ unsigned int cons_mask;
+ hg_atomic_int64_t ring[] __attribute__((aligned(HG_MEM_CACHE_LINE_SIZE)));
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Allocate a new queue that can hold \count elements.
+ *
+ * \param count [IN] maximum number of elements
+ *
+ * \return pointer to allocated queue or NULL on failure
+ */
+HG_UTIL_PUBLIC struct hg_atomic_queue *hg_atomic_queue_alloc(unsigned int count);
+
+/**
+ * Free an existing queue.
+ *
+ * \param hg_atomic_queue [IN] pointer to queue
+ */
+HG_UTIL_PUBLIC void hg_atomic_queue_free(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Push an entry to the queue.
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ * \param entry [IN] pointer to object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_atomic_queue_push(struct hg_atomic_queue *hg_atomic_queue, void *entry);
+
+/**
+ * Pop an entry from the queue (multi-consumer).
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return Pointer to popped object or NULL if queue is empty
+ */
+static HG_UTIL_INLINE void *hg_atomic_queue_pop_mc(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Pop an entry from the queue (single consumer).
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return Pointer to popped object or NULL if queue is empty
+ */
+static HG_UTIL_INLINE void *hg_atomic_queue_pop_sc(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Determine whether queue is empty.
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return HG_UTIL_TRUE if empty, HG_UTIL_FALSE if not
+ */
+static HG_UTIL_INLINE hg_util_bool_t hg_atomic_queue_is_empty(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Determine number of entries in a queue.
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return Number of entries queued or 0 if none
+ */
+static HG_UTIL_INLINE unsigned int hg_atomic_queue_count(struct hg_atomic_queue *hg_atomic_queue);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_atomic_queue_push(struct hg_atomic_queue *hg_atomic_queue, void *entry)
+{
+ hg_util_int32_t prod_head, prod_next, cons_tail;
+
+ do {
+ prod_head = hg_atomic_get32(&hg_atomic_queue->prod_head);
+ prod_next = (prod_head + 1) & (int)hg_atomic_queue->prod_mask;
+ cons_tail = hg_atomic_get32(&hg_atomic_queue->cons_tail);
+
+ if (prod_next == cons_tail) {
+ hg_atomic_fence();
+ if (prod_head == hg_atomic_get32(&hg_atomic_queue->prod_head) &&
+ cons_tail == hg_atomic_get32(&hg_atomic_queue->cons_tail)) {
+ hg_atomic_queue->drops++;
+ /* Full */
+ return HG_UTIL_FAIL;
+ }
+ continue;
+ }
+ } while (!hg_atomic_cas32(&hg_atomic_queue->prod_head, prod_head, prod_next));
+
+ hg_atomic_set64(&hg_atomic_queue->ring[prod_head], (hg_util_int64_t)entry);
+
+ /*
+ * If there are other enqueues in progress
+ * that preceded us, we need to wait for them
+ * to complete
+ */
+ while (hg_atomic_get32(&hg_atomic_queue->prod_tail) != prod_head)
+ cpu_spinwait();
+
+ hg_atomic_set32(&hg_atomic_queue->prod_tail, prod_next);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_atomic_queue_pop_mc(struct hg_atomic_queue *hg_atomic_queue)
+{
+ hg_util_int32_t cons_head, cons_next;
+ void * entry = NULL;
+
+ do {
+ cons_head = hg_atomic_get32(&hg_atomic_queue->cons_head);
+ cons_next = (cons_head + 1) & (int)hg_atomic_queue->cons_mask;
+
+ if (cons_head == hg_atomic_get32(&hg_atomic_queue->prod_tail))
+ return NULL;
+ } while (!hg_atomic_cas32(&hg_atomic_queue->cons_head, cons_head, cons_next));
+
+ entry = (void *)hg_atomic_get64(&hg_atomic_queue->ring[cons_head]);
+
+ /*
+ * If there are other dequeues in progress
+ * that preceded us, we need to wait for them
+ * to complete
+ */
+ while (hg_atomic_get32(&hg_atomic_queue->cons_tail) != cons_head)
+ cpu_spinwait();
+
+ hg_atomic_set32(&hg_atomic_queue->cons_tail, cons_next);
+
+ return entry;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_atomic_queue_pop_sc(struct hg_atomic_queue *hg_atomic_queue)
+{
+ hg_util_int32_t cons_head, cons_next;
+ hg_util_int32_t prod_tail;
+ void * entry = NULL;
+
+ cons_head = hg_atomic_get32(&hg_atomic_queue->cons_head);
+ prod_tail = hg_atomic_get32(&hg_atomic_queue->prod_tail);
+ cons_next = (cons_head + 1) & (int)hg_atomic_queue->cons_mask;
+
+ if (cons_head == prod_tail)
+ /* Empty */
+ return NULL;
+
+ hg_atomic_set32(&hg_atomic_queue->cons_head, cons_next);
+
+ entry = (void *)hg_atomic_get64(&hg_atomic_queue->ring[cons_head]);
+
+ hg_atomic_set32(&hg_atomic_queue->cons_tail, cons_next);
+
+ return entry;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_bool_t
+hg_atomic_queue_is_empty(struct hg_atomic_queue *hg_atomic_queue)
+{
+ return (hg_atomic_get32(&hg_atomic_queue->cons_head) == hg_atomic_get32(&hg_atomic_queue->prod_tail));
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE unsigned int
+hg_atomic_queue_count(struct hg_atomic_queue *hg_atomic_queue)
+{
+ return ((hg_atomic_queue->prod_size + (unsigned int)hg_atomic_get32(&hg_atomic_queue->prod_tail) -
+ (unsigned int)hg_atomic_get32(&hg_atomic_queue->cons_tail)) &
+ hg_atomic_queue->prod_mask);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_ATOMIC_QUEUE_H */
diff --git a/src/mercury/include/mercury_bulk.h b/src/mercury/include/mercury_bulk.h
new file mode 100644
index 0000000..598a842
--- /dev/null
+++ b/src/mercury/include/mercury_bulk.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_BULK_H
+#define MERCURY_BULK_H
+
+#include "mercury_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* The memory attributes associated with the bulk handle
+ * can be defined as read only, write only or read-write */
+#define HG_BULK_READ_ONLY (1 << 0)
+#define HG_BULK_WRITE_ONLY (1 << 1)
+#define HG_BULK_READWRITE (HG_BULK_READ_ONLY | HG_BULK_WRITE_ONLY)
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create an abstract bulk handle from specified memory segments.
+ * Memory allocated is then freed when HG_Bulk_free() is called.
+ * \remark If NULL is passed to buf_ptrs, i.e.,
+ * \verbatim HG_Bulk_create(count, NULL, buf_sizes, flags, &handle) \endverbatim
+ * memory for the missing buf_ptrs array will be internally allocated.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param count [IN] number of segments
+ * \param buf_ptrs [IN] array of pointers
+ * \param buf_sizes [IN] array of sizes
+ * \param flags [IN] permission flag:
+ * - HG_BULK_READWRITE
+ * - HG_BULK_READ_ONLY
+ * - HG_BULK_WRITE_ONLY
+ * \param handle [OUT] pointer to returned abstract bulk handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_create(hg_class_t *hg_class, hg_uint32_t count, void **buf_ptrs,
+ const hg_size_t *buf_sizes, hg_uint8_t flags, hg_bulk_t *handle);
+
+/**
+ * Free bulk handle.
+ *
+ * \param handle [IN/OUT] abstract bulk handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_free(hg_bulk_t handle);
+
+/**
+ * Increment ref count on bulk handle.
+ *
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_ref_incr(hg_bulk_t handle);
+
+/**
+ * Bind an existing bulk handle to a local HG context and associate its local
+ * address. This function can be used to forward and share a bulk handle
+ * between targets, which would not have direct access to the origin without
+ * extra RPCs. In that case, the origin address of the bulk handle is embedded
+ * and serialized/deserialized with HG_Bulk_serialize()/HG_Bulk_deserialize().
+ * Users should note that binding a handle adds an extra overhead on
+ * serialization, therefore it is recommended to use it with care.
+ * When binding a handle on origin, HG_Bulk_bind_transfer() can be used since
+ * origin information is embedded in the handle.
+ *
+ * Usage example:
+ * Origin sends an RPC request with a bulk handle attached to target A, target A
+ * forwards the origin's bulk handle to another target B. When target B receives
+ * the deserialized bulk handle, it has the address/info required to initiate a
+ * bulk transfer to/from the origin.
+ * For that usage, the origin will have called this function to bind the bulk
+ * handle to its local context, prior to sending the RPC request to target A.
+ *
+ * \param context [IN] pointer to HG context
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_bind(hg_bulk_t handle, hg_context_t *context);
+
+/**
+ * Return attached addressing information from a handle that was previously
+ * bound to a context using HG_Bulk_bind().
+ *
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return abstract HG address or HG_ADDR_NULL in case of error
+ */
+HG_PUBLIC hg_addr_t HG_Bulk_get_addr(hg_bulk_t handle);
+
+/**
+ * Return attached context ID from a handle that was previously bound to a
+ * context using HG_Bulk_bind().
+ *
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return valid context ID or 0 by default
+ */
+HG_PUBLIC hg_uint8_t HG_Bulk_get_context_id(hg_bulk_t handle);
+
+/**
+ * Access bulk handle to retrieve memory segments abstracted by handle.
+ * \remark When using mercury in co-resident mode (i.e., when addr passed is
+ * self addr), this function allows to avoid copy of bulk data by directly
+ * accessing pointers from an existing HG bulk handle.
+ *
+ * \param handle [IN] abstract bulk handle
+ * \param offset [IN] bulk offset
+ * \param size [IN] bulk size
+ * \param flags [IN] permission flag:
+ * - HG_BULK_READWRITE
+ * - HG_BULK_READ_ONLY
+ * \param max_count [IN] maximum number of segments to be returned
+ * \param buf_ptrs [IN/OUT] array of buffer pointers
+ * \param buf_sizes [IN/OUT] array of buffer sizes
+ * \param actual_count [OUT] actual number of segments returned
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_access(hg_bulk_t handle, hg_size_t offset, hg_size_t size, hg_uint8_t flags,
+ hg_uint32_t max_count, void **buf_ptrs, hg_size_t *buf_sizes,
+ hg_uint32_t *actual_count);
+
+/**
+ * Get total size of data abstracted by bulk handle.
+ *
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return Non-negative value
+ */
+static HG_INLINE hg_size_t HG_Bulk_get_size(hg_bulk_t handle);
+
+/**
+ * Get total number of segments abstracted by bulk handle.
+ *
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return Non-negative value
+ */
+static HG_INLINE hg_uint32_t HG_Bulk_get_segment_count(hg_bulk_t handle);
+
+/**
+ * Get permission flags set on an existing bulk handle.
+ *
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return Non-negative value
+ */
+static HG_INLINE hg_uint8_t HG_Bulk_get_flags(hg_bulk_t handle);
+
+/**
+ * Get size required to serialize bulk handle.
+ *
+ * \param handle [IN] abstract bulk handle
+ * \param flags [IN] option flags, valid flags are:
+ * HG_BULK_SM, HG_BULK_EAGER
+ *
+ * \return Non-negative value
+ */
+HG_PUBLIC hg_size_t HG_Bulk_get_serialize_size(hg_bulk_t handle, unsigned long flags);
+
+/**
+ * Serialize bulk handle into a buffer.
+ *
+ * \param buf [IN/OUT] pointer to buffer
+ * \param buf_size [IN] buffer size
+ * \param flags [IN] option flags, valid flags are:
+ * HG_BULK_SM, HG_BULK_EAGER
+ * \param handle [IN] abstract bulk handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_serialize(void *buf, hg_size_t buf_size, unsigned long flags, hg_bulk_t handle);
+
+/**
+ * Deserialize bulk handle from an existing buffer.
+ *
+ * \param hg_class [IN] pointer to HG class
+ * \param handle [OUT] abstract bulk handle
+ * \param buf [IN] pointer to buffer
+ * \param buf_size [IN] buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_deserialize(hg_class_t *hg_class, hg_bulk_t *handle, const void *buf,
+ hg_size_t buf_size);
+
+/**
+ * Transfer data to/from origin using abstract bulk handles and explicit origin
+ * address information. After completion, user callback is placed into a
+ * completion queue and can be triggered using HG_Trigger().
+ *
+ * \param context [IN] pointer to HG context
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param op [IN] transfer operation:
+ * - HG_BULK_PUSH
+ * - HG_BULK_PULL
+ * \param origin_addr [IN] abstract address of origin
+ * \param origin_handle [IN] abstract bulk handle
+ * \param origin_offset [IN] offset
+ * \param local_handle [IN] abstract bulk handle
+ * \param local_offset [IN] offset
+ * \param size [IN] size of data to be transferred
+ * \param op_id [OUT] pointer to returned operation ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_transfer(hg_context_t *context, hg_cb_t callback, void *arg, hg_bulk_op_t op,
+ hg_addr_t origin_addr, hg_bulk_t origin_handle,
+ hg_size_t origin_offset, hg_bulk_t local_handle,
+ hg_size_t local_offset, hg_size_t size, hg_op_id_t *op_id);
+
+/**
+ * Transfer data to/from origin using abstract bulk handles and implicit origin
+ * information (embedded in the origin handle). After completion, user callback
+ * is placed into a completion queue and can be triggered using HG_Trigger().
+ *
+ * \param context [IN] pointer to HG context
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param op [IN] transfer operation:
+ * - HG_BULK_PUSH
+ * - HG_BULK_PULL
+ * \param origin_handle [IN] abstract bulk handle
+ * \param origin_offset [IN] offset
+ * \param local_handle [IN] abstract bulk handle
+ * \param local_offset [IN] offset
+ * \param size [IN] size of data to be transferred
+ * \param op_id [OUT] pointer to returned operation ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_bind_transfer(hg_context_t *context, hg_cb_t callback, void *arg,
+ hg_bulk_op_t op, hg_bulk_t origin_handle, hg_size_t origin_offset,
+ hg_bulk_t local_handle, hg_size_t local_offset, hg_size_t size,
+ hg_op_id_t *op_id);
+
+/**
+ * Transfer data to/from origin using abstract bulk handles, explicit origin
+ * address information and origin context ID (associating the transfer to a
+ * remote context ID). After completion, user callback is placed into a
+ * completion queue and can be triggered using HG_Trigger().
+ *
+ * \param context [IN] pointer to HG context
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param op [IN] transfer operation:
+ * - HG_BULK_PUSH
+ * - HG_BULK_PULL
+ * \param origin_addr [IN] abstract address of origin
+ * \param origin_id [IN] context ID of origin
+ * \param origin_handle [IN] abstract bulk handle
+ * \param origin_offset [IN] offset
+ * \param local_handle [IN] abstract bulk handle
+ * \param local_offset [IN] offset
+ * \param size [IN] size of data to be transferred
+ * \param op_id [OUT] pointer to returned operation ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_transfer_id(hg_context_t *context, hg_cb_t callback, void *arg, hg_bulk_op_t op,
+ hg_addr_t origin_addr, hg_uint8_t origin_id,
+ hg_bulk_t origin_handle, hg_size_t origin_offset,
+ hg_bulk_t local_handle, hg_size_t local_offset, hg_size_t size,
+ hg_op_id_t *op_id);
+
+/**
+ * Cancel an ongoing operation.
+ *
+ * \param op_id [IN] operation ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Bulk_cancel(hg_op_id_t op_id);
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/* HG bulk descriptor info */
+struct hg_bulk_desc_info {
+ hg_size_t len; /* Size of region */
+ hg_uint32_t segment_count; /* Segment count */
+ hg_uint8_t flags; /* Flags of operation access */
+};
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+HG_Bulk_get_size(hg_bulk_t handle)
+{
+ return ((struct hg_bulk_desc_info *)handle)->len;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_uint32_t
+HG_Bulk_get_segment_count(hg_bulk_t handle)
+{
+ return ((struct hg_bulk_desc_info *)handle)->segment_count;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_uint8_t
+HG_Bulk_get_flags(hg_bulk_t handle)
+{
+ return ((struct hg_bulk_desc_info *)handle)->flags;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_BULK_H */
diff --git a/src/mercury/include/mercury_config.h b/src/mercury/include/mercury_config.h
new file mode 100644
index 0000000..6fe5064
--- /dev/null
+++ b/src/mercury/include/mercury_config.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Generated file. Only edit mercury_config.h.in. */
+
+#ifndef MERCURY_CONFIG_H
+#define MERCURY_CONFIG_H
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* Type definitions */
+#ifdef _WIN32
+typedef signed __int64 hg_int64_t;
+typedef signed __int32 hg_int32_t;
+typedef signed __int16 hg_int16_t;
+typedef signed __int8 hg_int8_t;
+typedef unsigned __int64 hg_uint64_t;
+typedef unsigned __int32 hg_uint32_t;
+typedef unsigned __int16 hg_uint16_t;
+typedef unsigned __int8 hg_uint8_t;
+/* Limits on Integer Constants */
+#define UINT64_MAX _UI64_MAX
+#else
+#include <stddef.h>
+#include <stdint.h>
+typedef int64_t hg_int64_t;
+typedef int32_t hg_int32_t;
+typedef int16_t hg_int16_t;
+typedef int8_t hg_int8_t;
+typedef uint64_t hg_uint64_t;
+typedef uint32_t hg_uint32_t;
+typedef uint16_t hg_uint16_t;
+typedef uint8_t hg_uint8_t;
+#endif
+typedef hg_uint64_t hg_ptr_t;
+typedef hg_uint8_t hg_bool_t;
+
+/* True / false */
+#define HG_TRUE 1
+#define HG_FALSE 0
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Reflects major releases of Mercury */
+#define HG_VERSION_MAJOR 2
+/* Reflects any API changes */
+#define HG_VERSION_MINOR 1
+/* Reflects any library code changes */
+#define HG_VERSION_PATCH 0
+
+/* Visibility of symbols */
+#if defined(_WIN32)
+#define HG_ABI_IMPORT __declspec(dllimport)
+#define HG_ABI_EXPORT __declspec(dllexport)
+#define HG_ABI_HIDDEN
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+#define HG_ABI_IMPORT __attribute__((visibility("default")))
+#define HG_ABI_EXPORT __attribute__((visibility("default")))
+#define HG_ABI_HIDDEN __attribute__((visibility("hidden")))
+#else
+#define HG_ABI_IMPORT
+#define HG_ABI_EXPORT
+#define HG_ABI_HIDDEN
+#endif
+
+/* Inline macro */
+#ifdef _WIN32
+#define HG_INLINE __inline
+#else
+#define HG_INLINE __inline__
+#endif
+
+/* Fallthrough macro */
+#if defined(__GNUC__) && (__GNUC__ >= 7)
+#define HG_FALLTHROUGH() __attribute__((fallthrough))
+#else
+#define HG_FALLTHROUGH()
+#endif
+
+/* Shared libraries */
+/* #undef HG_BUILD_SHARED_LIBS */
+#ifdef HG_BUILD_SHARED_LIBS
+#ifdef mercury_EXPORTS
+#define HG_PUBLIC HG_ABI_EXPORT
+#else
+#define HG_PUBLIC HG_ABI_IMPORT
+#endif
+#define HG_PRIVATE HG_ABI_HIDDEN
+#else
+#define HG_PUBLIC
+#define HG_PRIVATE
+#endif
+
+/* Build Options */
+/* #undef HG_HAS_BOOST */
+/* #undef HG_HAS_CHECKSUMS */
+/* #undef HG_HAS_XDR */
+/* #undef HG_HAS_COLLECT_STATS */
+
+/* #undef HG_HAS_DEBUG */
+
+#endif /* MERCURY_CONFIG_H */
diff --git a/src/mercury/include/mercury_core.h b/src/mercury/include/mercury_core.h
new file mode 100644
index 0000000..3d5c850
--- /dev/null
+++ b/src/mercury/include/mercury_core.h
@@ -0,0 +1,1074 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_CORE_H
+#define MERCURY_CORE_H
+
+#include "mercury_core_header.h"
+#include "mercury_core_types.h"
+
+#include "na.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_core_class hg_core_class_t; /* Opaque HG core class */
+typedef struct hg_core_context hg_core_context_t; /* Opaque HG core context */
+typedef struct hg_core_addr * hg_core_addr_t; /* Abstract HG address */
+typedef struct hg_core_handle *hg_core_handle_t; /* Abstract RPC handle */
+typedef struct hg_core_op_id * hg_core_op_id_t; /* Abstract operation id */
+
+/* HG info struct */
+struct hg_core_info {
+ hg_core_class_t * core_class; /* HG core class */
+ hg_core_context_t *context; /* HG core context */
+ hg_core_addr_t addr; /* HG address at target/origin */
+ hg_id_t id; /* RPC ID */
+ hg_uint8_t context_id; /* Context ID at target/origin */
+};
+
+/* Callback info structs */
+struct hg_core_cb_info_lookup {
+ hg_core_addr_t addr; /* HG address */
+};
+
+struct hg_core_cb_info_forward {
+ hg_core_handle_t handle; /* HG handle */
+};
+
+struct hg_core_cb_info_respond {
+ hg_core_handle_t handle; /* HG handle */
+};
+
+struct hg_core_cb_info {
+ union { /* Union of callback info structures */
+ struct hg_core_cb_info_lookup lookup;
+ struct hg_core_cb_info_forward forward;
+ struct hg_core_cb_info_respond respond;
+ } info;
+ void * arg; /* User data */
+ hg_cb_type_t type; /* Callback type */
+ hg_return_t ret; /* Return value */
+};
+
+/* RPC / HG callbacks */
+typedef hg_return_t (*hg_core_rpc_cb_t)(hg_core_handle_t handle);
+typedef hg_return_t (*hg_core_cb_t)(const struct hg_core_cb_info *callback_info);
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Constant values */
+#define HG_CORE_ADDR_NULL ((hg_core_addr_t)0)
+#define HG_CORE_HANDLE_NULL ((hg_core_handle_t)0)
+#define HG_CORE_OP_ID_NULL ((hg_core_op_id_t)0)
+#define HG_CORE_OP_ID_IGNORE ((hg_core_op_id_t *)1)
+
+/* Flags */
+#define HG_CORE_MORE_DATA (1 << 0) /* More data required */
+#define HG_CORE_NO_RESPONSE (1 << 1) /* No response required */
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the core Mercury layer.
+ * Must be finalized with HG_Core_finalize().
+ *
+ * \param na_info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param na_listen [IN] listen for incoming connections
+ *
+ * \return Pointer to HG core class or NULL in case of failure
+ */
+HG_PUBLIC hg_core_class_t *HG_Core_init(const char *na_info_string, hg_bool_t na_listen);
+
+/**
+ * Initialize the Mercury layer with options provided by init_info.
+ * Must be finalized with HG_Core_finalize().
+ * \remark HG_Core_init_opt() may become HG_Core_init() in the future.
+ *
+ * \param na_info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param na_listen [IN] listen for incoming connections
+ * \param hg_init_info [IN] (Optional) HG init info, NULL if no info
+ *
+ * \return Pointer to HG core class or NULL in case of failure
+ */
+HG_PUBLIC hg_core_class_t *HG_Core_init_opt(const char *na_info_string, hg_bool_t na_listen,
+ const struct hg_init_info *hg_init_info);
+
+/**
+ * Finalize the Mercury layer.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_finalize(hg_core_class_t *hg_core_class);
+
+/**
+ * Clean up all temporary files that were created in previous HG instances.
+ * While temporary resources (e.g., tmp files) are cleaned up on a call
+ * to HG_Finalize(), this routine gives a chance to programs that terminate
+ * abnormally to easily clean up those resources.
+ */
+HG_PUBLIC void HG_Core_cleanup(void);
+
+/**
+ * Set callback that will be triggered when additional data needs to be
+ * transferred and HG_Core_set_more_data() has been called, usually when the
+ * eager message size is exceeded. This allows upper layers to manually transfer
+ * data using bulk transfers for example. The done_callback argument allows the
+ * upper layer to notify back once the data has been successfully acquired.
+ * The release callback allows the upper layer to release resources that were
+ * allocated when acquiring the data.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param more_data_acquire_callback [IN] pointer to acquire function callback
+ * \param more_data_release_callback [IN] pointer to release function callback
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_set_more_data_callback(
+ struct hg_core_class *hg_core_class,
+ hg_return_t (*more_data_acquire_callback)(hg_core_handle_t, hg_op_t,
+ hg_return_t (*done_callback)(hg_core_handle_t)),
+ void (*more_data_release_callback)(hg_core_handle_t));
+
+/**
+ * Obtain the name of the given class.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return the name of the class, or NULL if not a valid class
+ */
+static HG_INLINE const char *HG_Core_class_get_name(const hg_core_class_t *hg_core_class);
+
+/**
+ * Obtain the protocol of the given class.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return the protocol of the class, or NULL if not a valid class
+ */
+static HG_INLINE const char *HG_Core_class_get_protocol(const hg_core_class_t *hg_core_class);
+
+/**
+ * Test whether class is listening or not.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return HG_TRUE if listening or HG_FALSE if not, or not a valid class
+ */
+static HG_INLINE hg_bool_t HG_Core_class_is_listening(const hg_core_class_t *hg_core_class);
+
+/**
+ * Obtain the underlying NA class.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return Pointer to NA class or NULL if not a valid class
+ */
+static HG_INLINE na_class_t *HG_Core_class_get_na(const hg_core_class_t *hg_core_class);
+
+#ifdef NA_HAS_SM
+/**
+ * Obtain the underlying NA SM class.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return Pointer to NA SM class or NULL if not a valid class
+ */
+static HG_INLINE na_class_t *HG_Core_class_get_na_sm(const hg_core_class_t *hg_core_class);
+#endif
+
+/**
+ * Obtain the maximum eager size for sending RPC inputs.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return the maximum size, or 0 if hg_core_class is not a valid class or
+ * XDR is being used
+ */
+static HG_INLINE hg_size_t HG_Core_class_get_input_eager_size(const hg_core_class_t *hg_core_class);
+
+/**
+ * Obtain the maximum eager size for sending RPC outputs.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return the maximum size, or 0 if hg_core_class is not a valid class or XDR
+ * is being used
+ */
+static HG_INLINE hg_size_t HG_Core_class_get_output_eager_size(const hg_core_class_t *hg_core_class);
+
+/**
+ * Associate user data to class. When HG_Core_finalize() is called,
+ * free_callback (if defined) is called to free the associated data.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param data [IN] pointer to user data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Core_class_set_data(hg_core_class_t *hg_core_class, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Retrieve previously associated data from a given class.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE void *HG_Core_class_get_data(const hg_core_class_t *hg_core_class);
+
+/**
+ * Create a new context. Must be destroyed by calling HG_Core_context_destroy().
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ *
+ * \return Pointer to HG core context or NULL in case of failure
+ */
+HG_PUBLIC hg_core_context_t *HG_Core_context_create(hg_core_class_t *hg_core_class);
+
+/**
+ * Create a new context with a user-defined context identifier. The context
+ * identifier can be used to route RPC requests to specific contexts by using
+ * HG_Core_set_target_id().
+ * Context must be destroyed by calling HG_Core_context_destroy().
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param id [IN] context ID
+ *
+ * \return Pointer to HG core context or NULL in case of failure
+ */
+HG_PUBLIC hg_core_context_t *HG_Core_context_create_id(hg_core_class_t *hg_core_class, hg_uint8_t id);
+
+/**
+ * Destroy a context created by HG_Core_context_create().
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_context_destroy(hg_core_context_t *context);
+
+/**
+ * Retrieve the class used to create the given context.
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return the associated class
+ */
+static HG_INLINE hg_core_class_t *HG_Core_context_get_class(const hg_core_context_t *context);
+
+/**
+ * Retrieve the underlying NA context.
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return the associated context
+ */
+static HG_INLINE na_context_t *HG_Core_context_get_na(const hg_core_context_t *context);
+
+#ifdef NA_HAS_SM
+/**
+ * Retrieve the underlying NA SM context.
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return the associated context
+ */
+static HG_INLINE na_context_t *HG_Core_context_get_na_sm(const hg_core_context_t *context);
+#endif
+
+/**
+ * Retrieve context ID from context.
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return Non-negative integer (max value of 255) or 0 if no ID has been set
+ */
+static HG_INLINE hg_uint8_t HG_Core_context_get_id(const hg_core_context_t *context);
+
+/**
+ * Associate user data to context. When HG_Core_context_destroy() is called,
+ * free_callback (if defined) is called to free the associated data.
+ *
+ * \param context [IN] pointer to HG core context
+ * \param data [IN] pointer to user data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Core_context_set_data(hg_core_context_t *context, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Retrieve previously associated data from a given context.
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE void *HG_Core_context_get_data(const hg_core_context_t *context);
+
+/**
+ * Set callback to be called on HG core handle creation. Handles are created
+ * both on HG_Core_create() and HG_Core_context_post() calls. This allows
+ * upper layers to create and attach data to a handle (using HG_Core_set_data())
+ * and later retrieve it using HG_Core_get_data().
+ *
+ * \param context [IN] pointer to HG core context
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_context_set_handle_create_callback(
+ hg_core_context_t *context, hg_return_t (*callback)(hg_core_handle_t, void *), void *arg);
+
+/**
+ * Post requests associated to context in order to receive incoming RPCs.
+ * Requests are automatically re-posted after completion until the context is
+ * destroyed. Additionally a callback can be triggered on HG handle
+ * creation. This allows upper layers to instantiate data that needs to be
+ * attached to a handle. Number of requests that are posted can be controlled
+ * through HG init info.
+ *
+ * \param context [IN] pointer to HG core context
+ *
+ * \return the associated class
+ */
+HG_PUBLIC hg_return_t HG_Core_context_post(hg_core_context_t *context);
+
+/**
+ * Dynamically register an RPC ID as well as the RPC callback executed
+ * when the RPC request ID is received.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param id [IN] ID to use to register RPC
+ * \param rpc_cb [IN] RPC callback
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_register(hg_core_class_t *hg_core_class, hg_id_t id, hg_core_rpc_cb_t rpc_cb);
+
+/**
+ * Deregister RPC ID. Further requests with RPC ID will return an error, it
+ * is therefore up to the user to make sure that all requests for that RPC ID
+ * have been treated before it is unregistered.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param id [IN] registered function ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_deregister(hg_core_class_t *hg_core_class, hg_id_t id);
+
+/**
+ * Indicate whether HG_Core_register() has been called.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param id [IN] function ID
+ * \param flag [OUT] pointer to boolean
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_registered(hg_core_class_t *hg_core_class, hg_id_t id, hg_bool_t *flag);
+
+/**
+ * Register and associate user data to registered function. When
+ * HG_Core_finalize() is called, free_callback (if defined) is called to free
+ * the registered data.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param id [IN] registered function ID
+ * \param data [IN] pointer to data
+ * \param free_callback [IN] pointer to function
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_register_data(hg_core_class_t *hg_core_class, hg_id_t id, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Indicate whether HG_Core_register_data() has been called and return
+ * associated data.
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param id [IN] registered function ID
+ *
+ * \return Pointer to data or NULL
+ */
+HG_PUBLIC void *HG_Core_registered_data(hg_core_class_t *hg_core_class, hg_id_t id);
+
+/**
+ * Lookup an addr from a peer address/name. Addresses need to be
+ * freed by calling HG_Core_addr_free(). After completion, user callback is
+ * placed into a completion queue and can be triggered using HG_Core_trigger().
+ *
+ * \param context [IN] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param name [IN] lookup name
+ * \param op_id [OUT] pointer to returned operation ID (unused)
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_lookup1(hg_core_context_t *context, hg_core_cb_t callback, void *arg,
+ const char *name, hg_core_op_id_t *op_id);
+
+/**
+ * Lookup an addr from a peer address/name. Addresses need to be
+ * freed by calling HG_Core_addr_free().
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param name [IN] lookup name
+ * \param addr [OUT] pointer to abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_lookup2(hg_core_class_t *hg_core_class, const char *name,
+ hg_core_addr_t *addr);
+
+/**
+ * Free the addr from the list of peers.
+ *
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_free(hg_core_addr_t addr);
+
+/**
+ * Hint that the address is no longer valid. This may happen if the peer is
+ * no longer responding. This can be used to force removal of the
+ * peer address from the list of the peers, before freeing it and reclaim
+ * resources.
+ *
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_set_remove(hg_core_addr_t addr);
+
+/**
+ * Obtain the underlying NA address from an HG address.
+ *
+ * \param addr [IN] abstract address
+ *
+ * \return abstract NA addr or NA_ADDR_NULL if not a valid HG address
+ */
+static HG_INLINE na_addr_t HG_Core_addr_get_na(hg_core_addr_t addr);
+
+#ifdef NA_HAS_SM
+/**
+ * Obtain the underlying NA SM address from an HG address.
+ *
+ * \param addr [IN] abstract address
+ *
+ * \return abstract NA addr or NA_ADDR_NULL if not a valid HG address
+ */
+static HG_INLINE na_addr_t HG_Core_addr_get_na_sm(hg_core_addr_t addr);
+#endif
+
+/**
+ * Access self address. Address must be freed with HG_Core_addr_free().
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param addr [OUT] pointer to abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_self(hg_core_class_t *hg_core_class, hg_core_addr_t *addr);
+
+/**
+ * Duplicate an existing HG abstract address. The duplicated address can be
+ * stored for later use and the origin address be freed safely. The duplicated
+ * address must be freed with HG_Core_addr_free().
+ *
+ * \param addr [IN] abstract address
+ * \param new_addr [OUT] pointer to abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_dup(hg_core_addr_t addr, hg_core_addr_t *new_addr);
+
+/**
+ * Compare two addresses.
+ *
+ * \param addr1 [IN] abstract address
+ * \param addr2 [IN] abstract address
+ *
+ * \return HG_TRUE if addresses are determined to be equal, HG_FALSE otherwise
+ */
+HG_PUBLIC hg_bool_t HG_Core_addr_cmp(hg_core_addr_t addr1, hg_core_addr_t addr2);
+
+/**
+ * Test whether address is self or not.
+ *
+ * \param addr [IN] pointer to abstract address
+ *
+ * \return HG_TRUE if address is self address, HG_FALSE otherwise
+ */
+static HG_INLINE hg_bool_t HG_Core_addr_is_self(hg_core_addr_t addr);
+
+/**
+ * Convert an addr to a string (returned string includes the terminating
+ * null byte '\0'). If buf is NULL, the address is not converted and only
+ * the required size of the buffer is returned. If the input value passed
+ * through buf_size is too small, HG_SIZE_ERROR is returned and the buf_size
+ * output is set to the minimum size required.
+ *
+ * \param buf [IN/OUT] pointer to destination buffer
+ * \param buf_size [IN/OUT] pointer to buffer size
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_to_string(char *buf, hg_size_t *buf_size, hg_core_addr_t addr);
+
+/**
+ * Get size required to serialize address.
+ *
+ * \param addr [IN] abstract address
+ * \param flags [IN] optional flags
+ *
+ * \return Non-negative value
+ */
+HG_PUBLIC hg_size_t HG_Core_addr_get_serialize_size(hg_core_addr_t addr, unsigned long flags);
+
+/**
+ * Serialize address into a buffer.
+ *
+ * \param buf [IN/OUT] pointer to destination buffer
+ * \param buf_size [IN] pointer to buffer size
+ * \param flags [IN] optional flags
+ * \param addr [IN] abstract address
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_serialize(void *buf, hg_size_t buf_size, unsigned long flags,
+ hg_core_addr_t addr);
+
+/**
+ * Deserialize address from a buffer. The returned address must be freed with
+ * HG_Core_addr_free().
+ *
+ * \param hg_core_class [IN] pointer to HG core class
+ * \param addr [OUT] pointer to abstract address
+ * \param buf [IN] pointer to buffer used for deserialization
+ * \param buf_size [IN] buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_addr_deserialize(hg_core_class_t *hg_core_class, hg_core_addr_t *addr,
+ const void *buf, hg_size_t buf_size);
+
+/**
+ * Initiate a new HG RPC using the specified function ID and the local/remote
+ * target defined by addr. The HG handle created can be used to query input
+ * and output buffers, as well as issuing the RPC by using HG_Core_forward().
+ * After completion the handle must be freed using HG_Core_destroy().
+ *
+ * \param context [IN] pointer to HG core context
+ * \param addr [IN] target address
+ * \param id [IN] registered function ID
+ * \param handle [OUT] pointer to HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_create(hg_core_context_t *context, hg_core_addr_t addr, hg_id_t id,
+ hg_core_handle_t *handle);
+
+/**
+ * Destroy HG handle. Decrement reference count, resources associated to the
+ * handle are freed when the reference count is null.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_destroy(hg_core_handle_t handle);
+
+/**
+ * Reset an existing HG handle to make it reusable for RPC forwarding.
+ * Both target address and RPC ID can be modified at this time.
+ * Operations on that handle must be completed in order to reset that handle
+ * safely.
+ *
+ * \param handle [IN] HG handle
+ * \param addr [IN] abstract network address of destination
+ * \param id [IN] registered function ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_reset(hg_core_handle_t handle, hg_core_addr_t addr, hg_id_t id);
+
+/**
+ * Increment ref count on handle.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_ref_incr(hg_core_handle_t handle);
+
+/**
+ * Retrieve ref count from handle.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Non-negative value or negative if the handle is not valid
+ */
+HG_PUBLIC hg_int32_t HG_Core_ref_get(hg_core_handle_t handle);
+
+/**
+ * Allows upper layers to attach data to an existing HG handle.
+ * The free_callback argument allows allocated resources to be released when
+ * the handle gets freed.
+ *
+ * \param handle [IN] HG handle
+ * \param data [IN] pointer to user data
+ * \param free_callback pointer to free function callback
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Core_set_data(hg_core_handle_t handle, void *data,
+ void (*free_callback)(void *));
+
+/**
+ * Allows upper layers to retrieve data from an existing HG handle.
+ * Only valid if HG_Core_set_data() has been previously called.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE void *HG_Core_get_data(hg_core_handle_t handle);
+
+/**
+ * Get info from handle.
+ *
+ * \remark Users must call HG_Core_addr_dup() to safely re-use the addr field.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Pointer to info or NULL in case of failure
+ */
+static HG_INLINE const struct hg_core_info *HG_Core_get_info(hg_core_handle_t handle);
+
+/**
+ * Allows upper layers to retrieve cached RPC data from an existing HG handle.
+ * Only valid if HG_Core_register_data() has been previously called.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return Pointer to user data or NULL if not set or any error has occurred
+ */
+static HG_INLINE const void *HG_Core_get_rpc_data(hg_core_handle_t handle);
+
+/**
+ * Set target context ID that will receive and process the RPC request
+ * (ID is defined on target context creation, see HG_Core_context_create_id()).
+ *
+ * \param handle [IN] HG handle
+ * \param id [IN] user-defined target context ID
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Core_set_target_id(hg_core_handle_t handle, hg_uint8_t id);
+
+/**
+ * Get input buffer from handle that can be used for serializing/deserializing
+ * parameters.
+ *
+ * \param handle [IN] HG handle
+ * \param in_buf [OUT] pointer to input buffer
+ * \param in_buf_size [OUT] pointer to input buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Core_get_input(hg_core_handle_t handle, void **in_buf,
+ hg_size_t *in_buf_size);
+
+/**
+ * Get output buffer from handle that can be used for serializing/deserializing
+ * parameters.
+ *
+ * \param handle [IN] HG handle
+ * \param out_buf [OUT] pointer to output buffer
+ * \param out_buf_size [OUT] pointer to output buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t HG_Core_get_output(hg_core_handle_t handle, void **out_buf,
+ hg_size_t *out_buf_size);
+
+/**
+ * Forward a call using an existing HG handle. Input and output buffers can be
+ * queried from the handle to serialize/deserialize parameters.
+ * Additionally, a bulk handle can be passed if the size of the input is larger
+ * than the queried input buffer size.
+ * After completion, the handle must be freed using HG_Core_destroy(), the user
+ * callback is placed into a completion queue and can be triggered using
+ * HG_Core_trigger().
+ *
+ * \param handle [IN] HG handle
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param payload_size [IN] size of payload to send
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_forward(hg_core_handle_t handle, hg_core_cb_t callback, void *arg,
+ hg_uint8_t flags, hg_size_t payload_size);
+
+/**
+ * Respond back to the origin. The output buffer, which can be used to encode
+ * the response, must first be queried using HG_Core_get_output().
+ * After completion, the user callback is placed into a completion queue and
+ * can be triggered using HG_Core_trigger().
+ *
+ * \param handle [IN] HG handle
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param payload_size [IN] size of payload to send
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_respond(hg_core_handle_t handle, hg_core_cb_t callback, void *arg,
+ hg_uint8_t flags, hg_size_t payload_size);
+
+/**
+ * Try to progress RPC execution for at most timeout until timeout is reached or
+ * any completion has occurred.
+ * Progress should not be considered as wait, in the sense that it cannot be
+ * assumed that completion of a specific operation will occur only when
+ * progress is called.
+ *
+ * \param context [IN] pointer to HG core context
+ * \param timeout [IN] timeout (in milliseconds)
+ *
+ * \return HG_SUCCESS if any completion has occurred / HG error code otherwise
+ */
+HG_PUBLIC hg_return_t HG_Core_progress(hg_core_context_t *context, unsigned int timeout);
+
+/**
+ * Execute at most max_count callbacks. If timeout is non-zero, wait up to
+ * timeout before returning. Function can return when at least one or more
+ * callbacks are triggered (at most max_count).
+ *
+ * \param context [IN] pointer to HG core context
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param max_count [IN] maximum number of callbacks triggered
+ * \param actual_count [IN] actual number of callbacks triggered
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_trigger(hg_core_context_t *context, unsigned int timeout,
+ unsigned int max_count, unsigned int *actual_count);
+
+/**
+ * Cancel an ongoing operation.
+ *
+ * \param handle [IN] HG handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Core_cancel(hg_core_handle_t handle);
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/* HG core class */
+struct hg_core_class {
+ na_class_t *na_class; /* NA class */
+#ifdef NA_HAS_SM
+ na_class_t *na_sm_class; /* NA SM class */
+#endif
+ void *data; /* User data */
+ void (*data_free_callback)(void *); /* User data free callback */
+};
+
+/* HG core context */
+struct hg_core_context {
+ struct hg_core_class *core_class; /* HG core class */
+ na_context_t * na_context; /* NA context */
+#ifdef NA_HAS_SM
+ na_context_t *na_sm_context; /* NA SM context */
+#endif
+ void *data; /* User data */
+ void (*data_free_callback)(void *); /* User data free callback */
+ hg_uint8_t id; /* Context ID */
+};
+
+/* HG core addr */
+struct hg_core_addr {
+ struct hg_core_class *core_class; /* HG core class */
+ na_addr_t na_addr; /* NA address */
+#ifdef NA_HAS_SM
+ na_addr_t na_sm_addr; /* NA SM address */
+#endif
+ hg_bool_t is_self; /* Self address */
+};
+
+/* HG core RPC registration info */
+struct hg_core_rpc_info {
+ hg_core_rpc_cb_t rpc_cb; /* RPC callback */
+ void * data; /* User data */
+ void (*free_callback)(void *); /* User data free callback */
+};
+
+/* HG core handle */
+struct hg_core_handle {
+ struct hg_core_info info; /* HG info */
+ struct hg_core_rpc_info *rpc_info; /* Associated RPC registration info */
+ void * data; /* User data */
+ void (*data_free_callback)(void *); /* User data free callback */
+ void * in_buf; /* Input buffer */
+ void * out_buf; /* Output buffer */
+ na_size_t in_buf_size; /* Input buffer size */
+ na_size_t out_buf_size; /* Output buffer size */
+ na_size_t na_in_header_offset; /* Input NA header offset */
+ na_size_t na_out_header_offset; /* Output NA header offset */
+};
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const char *
+HG_Core_class_get_name(const hg_core_class_t *hg_core_class)
+{
+ return NA_Get_class_name(hg_core_class->na_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const char *
+HG_Core_class_get_protocol(const hg_core_class_t *hg_core_class)
+{
+ return NA_Get_class_protocol(hg_core_class->na_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_bool_t
+HG_Core_class_is_listening(const hg_core_class_t *hg_core_class)
+{
+ return NA_Is_listening(hg_core_class->na_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE na_class_t *
+ HG_Core_class_get_na(const hg_core_class_t *hg_core_class)
+{
+ return hg_core_class->na_class;
+}
+
+/*---------------------------------------------------------------------------*/
+#ifdef NA_HAS_SM
+static HG_INLINE na_class_t *
+ HG_Core_class_get_na_sm(const hg_core_class_t *hg_core_class)
+{
+ return hg_core_class->na_sm_class;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+HG_Core_class_get_input_eager_size(const hg_core_class_t *hg_core_class)
+{
+ hg_size_t unexp = NA_Msg_get_max_unexpected_size(hg_core_class->na_class),
+ header = hg_core_header_request_get_size() +
+ NA_Msg_get_unexpected_header_size(hg_core_class->na_class);
+
+ return (unexp > header) ? unexp - header : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+HG_Core_class_get_output_eager_size(const hg_core_class_t *hg_core_class)
+{
+ hg_size_t exp = NA_Msg_get_max_expected_size(hg_core_class->na_class),
+ header = hg_core_header_response_get_size() +
+ NA_Msg_get_expected_header_size(hg_core_class->na_class);
+
+ return (exp > header) ? exp - header : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Core_class_set_data(hg_core_class_t *hg_core_class, void *data, void (*free_callback)(void *))
+{
+ hg_core_class->data = data;
+ hg_core_class->data_free_callback = free_callback;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+HG_Core_class_get_data(const hg_core_class_t *hg_core_class)
+{
+ return hg_core_class->data;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_core_class_t *
+ HG_Core_context_get_class(const hg_core_context_t *context)
+{
+ return context->core_class;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE na_context_t *
+ HG_Core_context_get_na(const hg_core_context_t *context)
+{
+ return context->na_context;
+}
+
+/*---------------------------------------------------------------------------*/
+#ifdef NA_HAS_SM
+static HG_INLINE na_context_t *
+ HG_Core_context_get_na_sm(const hg_core_context_t *context)
+{
+ return context->na_sm_context;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_uint8_t
+HG_Core_context_get_id(const hg_core_context_t *context)
+{
+ return context->id;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Core_context_set_data(hg_core_context_t *context, void *data, void (*free_callback)(void *))
+{
+ context->data = data;
+ context->data_free_callback = free_callback;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+HG_Core_context_get_data(const hg_core_context_t *context)
+{
+ return context->data;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE na_addr_t
+HG_Core_addr_get_na(hg_core_addr_t addr)
+{
+ return addr->na_addr;
+}
+
+/*---------------------------------------------------------------------------*/
+#ifdef NA_HAS_SM
+static HG_INLINE na_addr_t
+HG_Core_addr_get_na_sm(hg_core_addr_t addr)
+{
+ return addr->na_sm_addr;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_bool_t
+HG_Core_addr_is_self(hg_core_addr_t addr)
+{
+ return addr->is_self;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Core_set_data(hg_core_handle_t handle, void *data, void (*free_callback)(void *))
+{
+ handle->data = data;
+ handle->data_free_callback = free_callback;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+HG_Core_get_data(hg_core_handle_t handle)
+{
+ return handle->data;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const struct hg_core_info *
+HG_Core_get_info(hg_core_handle_t handle)
+{
+ return &handle->info;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE const void *
+HG_Core_get_rpc_data(hg_core_handle_t handle)
+{
+ return (handle->rpc_info) ? handle->rpc_info->data : NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Core_set_target_id(hg_core_handle_t handle, hg_uint8_t id)
+{
+ handle->info.context_id = id;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Core_get_input(hg_core_handle_t handle, void **in_buf, hg_size_t *in_buf_size)
+{
+ hg_size_t header_offset = hg_core_header_request_get_size() + handle->na_in_header_offset;
+
+ /* Space must be left for request header */
+ *in_buf = (char *)handle->in_buf + header_offset;
+ *in_buf_size = handle->in_buf_size - header_offset;
+
+ return HG_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+HG_Core_get_output(hg_core_handle_t handle, void **out_buf, hg_size_t *out_buf_size)
+{
+ hg_size_t header_offset = hg_core_header_response_get_size() + handle->na_out_header_offset;
+
+ /* Space must be left for response header */
+ *out_buf = (char *)handle->out_buf + header_offset;
+ *out_buf_size = handle->out_buf_size - header_offset;
+
+ return HG_SUCCESS;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_CORE_H */
diff --git a/src/mercury/include/mercury_core_header.h b/src/mercury/include/mercury_core_header.h
new file mode 100644
index 0000000..355adfa
--- /dev/null
+++ b/src/mercury/include/mercury_core_header.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_CORE_HEADER_H
+#define MERCURY_CORE_HEADER_H
+
+#include "mercury_core_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#if defined(__GNUC__) || defined(_WIN32)
+#pragma pack(push, 1)
+#else
+#warning "Proc header struct padding may not be consistent across platforms."
+#endif
+#ifdef HG_HAS_CHECKSUMS
+union hg_core_header_hash {
+ hg_uint16_t header; /* Header checksum (16-bits checksum) */
+ hg_uint32_t pad;
+};
+#endif
+
+struct hg_core_header_request {
+ hg_uint8_t hg; /* Mercury identifier */
+ hg_uint8_t protocol; /* Version number */
+ hg_uint64_t id; /* RPC request identifier */
+ hg_uint8_t flags; /* Flags */
+ hg_uint8_t cookie; /* Cookie */
+ /* 96 bits here */
+#ifdef HG_HAS_CHECKSUMS
+ union hg_core_header_hash hash; /* Hash */
+ /* 128 bits here */
+#endif
+};
+
+struct hg_core_header_response {
+ hg_int8_t ret_code; /* Return code */
+ hg_uint8_t flags; /* Flags */
+ hg_uint16_t cookie; /* Cookie */
+ hg_uint64_t pad; /* Pad */
+ /* 96 bits here */
+#ifdef HG_HAS_CHECKSUMS
+ union hg_core_header_hash hash; /* Hash */
+ /* 128 bits here */
+#endif
+};
+#if defined(__GNUC__) || defined(_WIN32)
+#pragma pack(pop)
+#endif
+
+/* Common header struct request/response */
+struct hg_core_header {
+ union {
+ struct hg_core_header_request request;
+ struct hg_core_header_response response;
+ } msg;
+#ifdef HG_HAS_CHECKSUMS
+ void *checksum; /* Checksum of header */
+#endif
+};
+
+/*
+ * 0 HG_CORE_HEADER_SIZE size
+ * |______________|__________________________|
+ * | Header | Encoded Data |
+ * |______________|__________________________|
+ *
+ *
+ * Request:
+ * mercury byte / protocol version number / rpc id / flags / cookie / checksum
+ *
+ * Response:
+ * flags / return code / cookie / checksum
+ */
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Mercury identifier for packets sent */
+#define HG_CORE_IDENTIFIER (('H' << 1) | ('G')) /* 0xD7 */
+
+/* Mercury protocol version number */
+#define HG_CORE_PROTOCOL_VERSION 0x05
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static HG_INLINE size_t hg_core_header_request_get_size(void);
+static HG_INLINE size_t hg_core_header_response_get_size(void);
+
+/**
+ * Get size reserved for request header (separate user data stored in payload).
+ *
+ * \return Non-negative size value
+ */
+static HG_INLINE size_t
+hg_core_header_request_get_size(void)
+{
+ return sizeof(struct hg_core_header_request);
+}
+
+/**
+ * Get size reserved for response header (separate user data stored in payload).
+ *
+ * \return Non-negative size value
+ */
+static HG_INLINE size_t
+hg_core_header_response_get_size(void)
+{
+ return sizeof(struct hg_core_header_response);
+}
+
+/**
+ * Initialize RPC request header.
+ *
+ * \param hg_core_header [IN/OUT] pointer to request header structure
+ *
+ */
+HG_PRIVATE void hg_core_header_request_init(struct hg_core_header *hg_core_header);
+
+/**
+ * Initialize RPC response header.
+ *
+ * \param hg_core_header [IN/OUT] pointer to response header structure
+ *
+ */
+HG_PRIVATE void hg_core_header_response_init(struct hg_core_header *hg_core_header);
+
+/**
+ * Finalize RPC request header.
+ *
+ * \param hg_core_header [IN/OUT] pointer to request header structure
+ *
+ */
+HG_PRIVATE void hg_core_header_request_finalize(struct hg_core_header *hg_core_header);
+
+/**
+ * Finalize RPC response header.
+ *
+ * \param hg_core_header [IN/OUT] pointer to response header structure
+ *
+ */
+HG_PRIVATE void hg_core_header_response_finalize(struct hg_core_header *hg_core_header);
+
+/**
+ * Reset RPC request header.
+ *
+ * \param hg_core_header [IN/OUT] pointer to request header structure
+ *
+ */
+HG_PRIVATE void hg_core_header_request_reset(struct hg_core_header *hg_core_header);
+
+/**
+ * Reset RPC response header.
+ *
+ * \param hg_core_header [IN/OUT] pointer to response header structure
+ *
+ */
+HG_PRIVATE void hg_core_header_response_reset(struct hg_core_header *hg_core_header);
+
+/**
+ * Process private information for sending/receiving RPC request.
+ *
+ * \param op [IN] operation type: HG_ENCODE / HG_DECODE
+ * \param buf [IN/OUT] buffer
+ * \param buf_size [IN] buffer size
+ * \param hg_core_header [IN/OUT] pointer to header structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PRIVATE hg_return_t hg_core_header_request_proc(hg_proc_op_t op, void *buf, size_t buf_size,
+ struct hg_core_header *hg_core_header);
+
+/**
+ * Process private information for sending/receiving response.
+ *
+ * \param op [IN] operation type: HG_ENCODE / HG_DECODE
+ * \param buf [IN/OUT] buffer
+ * \param buf_size [IN] buffer size
+ * \param header [IN/OUT] pointer to header structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PRIVATE hg_return_t hg_core_header_response_proc(hg_proc_op_t op, void *buf, size_t buf_size,
+ struct hg_core_header *hg_core_header);
+
+/**
+ * Verify private information from request header.
+ *
+ * \param hg_core_header [IN] pointer to request header structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PRIVATE hg_return_t hg_core_header_request_verify(const struct hg_core_header *hg_core_header);
+
+/**
+ * Verify private information from response header.
+ *
+ * \param hg_core_header [IN] pointer to response header structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PRIVATE hg_return_t hg_core_header_response_verify(const struct hg_core_header *hg_core_header);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_CORE_HEADER_H */
diff --git a/src/mercury/include/mercury_core_types.h b/src/mercury/include/mercury_core_types.h
new file mode 100644
index 0000000..636ab75
--- /dev/null
+++ b/src/mercury/include/mercury_core_types.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_CORE_TYPES_H
+#define MERCURY_CORE_TYPES_H
+
+#include "mercury_config.h"
+#include "na_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef hg_uint64_t hg_size_t; /* Size */
+typedef hg_uint64_t hg_id_t; /* RPC ID */
+
+/**
+ * HG init info struct
+ * NB. should be initialized using HG_INIT_INFO_INITIALIZER
+ */
+struct hg_init_info {
+ /* NA init info struct, see na_types.h for documentation */
+ struct na_init_info na_init_info;
+
+ /* Optional NA class that can be used for initializing an HG class. Using
+ * that option makes the init string passed to HG_Init() ignored.
+ * Default is: NULL */
+ na_class_t *na_class;
+
+ /* Controls the initial number of requests that are posted on context
+ * creation when the HG class is initialized with listen set to true.
+ * A value of zero is equivalent to using the internal default value.
+ * Default value is: 256 */
+ hg_uint32_t request_post_init;
+
+ /* Controls the number of requests that are incrementally posted when the
+ * initial number of requests is exhausted, a value of 0 means that only the
+ * initial number of requests will be re-used after they complete. Note that
+ * if the number of requests that are posted reaches 0, the underlying
+ * NA transport is responsible for queueing incoming requests. This value is
+ * used only if \request_post_init is set to a non-zero value.
+ * Default value is: 256 */
+ hg_uint32_t request_post_incr;
+
+ /* Controls whether the NA shared-memory interface should be automatically
+ * used if/when the RPC target address shares the same node as its origin.
+ * Default is: false */
+ hg_bool_t auto_sm;
+
+ /* Controls whether mercury should _NOT_ attempt to transfer small bulk data
+ * along with the RPC request.
+ * Default is: false */
+ hg_bool_t no_bulk_eager;
+
+ /* Disable internal loopback interface that enables forwarding of RPC
+ * requests to self addresses. Doing so will force traffic to be routed
+ * through NA. For performance reasons, users should be cautious when using
+ * that option.
+ * Default is: false */
+ hg_bool_t no_loopback;
+
+ /* (Debug) Print stats at exit.
+ * Default is: false */
+ hg_bool_t stats;
+};
+
+/* Error return codes:
+ * Functions return 0 for success or corresponding return code */
+#define HG_RETURN_VALUES \
+ X(HG_SUCCESS) /*!< operation succeeded */ \
+ X(HG_PERMISSION) /*!< operation not permitted */ \
+ X(HG_NOENTRY) /*!< no such file or directory */ \
+ X(HG_INTERRUPT) /*!< operation interrupted */ \
+ X(HG_AGAIN) /*!< operation must be retried */ \
+ X(HG_NOMEM) /*!< out of memory */ \
+ X(HG_ACCESS) /*!< permission denied */ \
+ X(HG_FAULT) /*!< bad address */ \
+ X(HG_BUSY) /*!< device or resource busy */ \
+ X(HG_EXIST) /*!< entry already exists */ \
+ X(HG_NODEV) /*!< no such device */ \
+ X(HG_INVALID_ARG) /*!< invalid argument */ \
+ X(HG_PROTOCOL_ERROR) /*!< protocol error */ \
+ X(HG_OVERFLOW) /*!< value too large */ \
+ X(HG_MSGSIZE) /*!< message size too long */ \
+ X(HG_PROTONOSUPPORT) /*!< protocol not supported */ \
+ X(HG_OPNOTSUPPORTED) /*!< operation not supported on endpoint */ \
+ X(HG_ADDRINUSE) /*!< address already in use */ \
+ X(HG_ADDRNOTAVAIL) /*!< cannot assign requested address */ \
+ X(HG_HOSTUNREACH) /*!< cannot reach host during operation */ \
+ X(HG_TIMEOUT) /*!< operation reached timeout */ \
+ X(HG_CANCELED) /*!< operation canceled */ \
+ X(HG_CHECKSUM_ERROR) /*!< checksum error */ \
+ X(HG_NA_ERROR) /*!< generic NA error */ \
+ X(HG_OTHER_ERROR) /*!< generic HG error */ \
+ X(HG_RETURN_MAX)
+
+#define X(a) a,
+typedef enum hg_return { HG_RETURN_VALUES } hg_return_t;
+#undef X
+
+/* Compat return codes */
+#define HG_INVALID_PARAM HG_INVALID_ARG
+#define HG_SIZE_ERROR HG_MSGSIZE
+#define HG_NOMEM_ERROR HG_NOMEM
+#define HG_NO_MATCH HG_NOENTRY
+
+/* Callback operation type */
+typedef enum hg_cb_type {
+ HG_CB_LOOKUP, /*!< lookup callback */
+ HG_CB_FORWARD, /*!< forward callback */
+ HG_CB_RESPOND, /*!< respond callback */
+ HG_CB_BULK /*!< bulk transfer callback */
+} hg_cb_type_t;
+
+/* Input / output operation type */
+typedef enum { HG_UNDEF, HG_INPUT, HG_OUTPUT } hg_op_t;
+
+/**
+ * Encode/decode operations.
+ */
+typedef enum {
+ HG_ENCODE, /*!< causes the type to be encoded into the stream */
+ HG_DECODE, /*!< causes the type to be extracted from the stream */
+ HG_FREE /*!< can be used to release the space allocated by an HG_DECODE
+ request */
+} hg_proc_op_t;
+
+/**
+ * Encode/decode operation flags.
+ */
+#define HG_CORE_SM (1 << 0)
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Max timeout */
+#define HG_MAX_IDLE_TIME (3600 * 1000)
+
+/* HG size max */
+#define HG_SIZE_MAX (UINT64_MAX)
+
+/* HG init info initializer */
+#define HG_INIT_INFO_INITIALIZER \
+ { \
+ NA_INIT_INFO_INITIALIZER, NULL, 0, 0, HG_FALSE, HG_FALSE, HG_FALSE, HG_FALSE \
+ }
+
+#endif /* MERCURY_CORE_TYPES_H */
diff --git a/src/mercury/include/mercury_dlog.h b/src/mercury/include/mercury_dlog.h
new file mode 100644
index 0000000..557b745
--- /dev/null
+++ b/src/mercury/include/mercury_dlog.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_DLOG_H
+#define MERCURY_DLOG_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_atomic.h"
+#include "mercury_list.h"
+#include "mercury_thread_mutex.h"
+#include "mercury_time.h"
+
+#include <stdio.h>
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*
+ * putting a magic number at the front of the dlog allows us to search
+ * for a dlog in a coredump file after a crash and examine its contents.
+ */
+#define HG_DLOG_MAGICLEN 16 /* bytes to reserve for magic# */
+#define HG_DLOG_STDMAGIC ">D.LO.G<" /* standard for first 8 bytes */
+
+/*
+ * HG_DLOG_INITIALIZER: initializer for a dlog in a global variable.
+ * LESIZE is the number of entries in the LE array. use it like this:
+ *
+ * #define FOO_NENTS 128
+ * struct hg_dlog_entry foo_le[FOO_NENTS];
+ * struct hg_dlog foo_dlog = HG_DLOG_INITIALIZER("foo", foo_le, FOO_NENTS, 0);
+ */
+#define HG_DLOG_INITIALIZER(NAME, LE, LESIZE, LELOOP) \
+ { \
+ HG_DLOG_STDMAGIC NAME, HG_THREAD_MUTEX_INITIALIZER, HG_LIST_HEAD_INITIALIZER(cnts32), \
+ HG_LIST_HEAD_INITIALIZER(cnts64), LE, LESIZE, LELOOP, 0, 0, 0, 0 \
+ }
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*
+ * hg_dlog_entry: an entry in the dlog
+ */
+struct hg_dlog_entry {
+ const char * file; /* file name */
+ unsigned int line; /* line number */
+ const char * func; /* function name */
+ const char * msg; /* entry message (optional) */
+ const void * data; /* user data (optional) */
+ hg_time_t time; /* time added to log */
+};
+
+/*
+ * hg_dlog_dcount32: 32-bit debug counter in the dlog
+ */
+struct hg_dlog_dcount32 {
+ const char * name; /* counter name (short) */
+ const char * descr; /* description of counter */
+ hg_atomic_int32_t c; /* the counter itself */
+ HG_LIST_ENTRY(hg_dlog_dcount32) l; /* linkage */
+};
+
+/*
+ * hg_dlog_dcount64: 64-bit debug counter in the dlog
+ */
+struct hg_dlog_dcount64 {
+ const char * name; /* counter name (short) */
+ const char * descr; /* description of counter */
+ hg_atomic_int64_t c; /* the counter itself */
+ HG_LIST_ENTRY(hg_dlog_dcount64) l; /* linkage */
+};
+
+/*
+ * hg_dlog: main structure
+ */
+struct hg_dlog {
+ char dlog_magic[HG_DLOG_MAGICLEN]; /* magic number + name */
+ hg_thread_mutex_t dlock; /* lock for this data struct */
+
+ /* counter lists */
+ HG_LIST_HEAD(hg_dlog_dcount32) cnts32; /* counter list */
+ HG_LIST_HEAD(hg_dlog_dcount64) cnts64; /* counter list */
+
+ /* log */
+ struct hg_dlog_entry *le; /* array of log entries */
+ unsigned int lesize; /* size of le[] array */
+ int leloop; /* circular buffer? */
+ unsigned int lefree; /* next free entry in le[] */
+ unsigned int leadds; /* #adds done if < lesize */
+ int lestop; /* stop taking new logs */
+
+ int mallocd; /* allocated with malloc? */
+};
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * malloc and return a new dlog
+ *
+ * \param name [IN] name of dlog (truncated past 8 bytes)
+ * \param lesize [IN] number of entries to allocate for log buffer
+ * \param leloop [IN] set to make log circular (can overwrite old
+ * entries)
+ *
+ * \return the new dlog or NULL on malloc error
+ */
+HG_UTIL_PUBLIC struct hg_dlog *hg_dlog_alloc(char *name, unsigned int lesize, int leloop);
+
+/**
+ * free anything we malloc'd on a dlog. assumes we have the final
+ * active reference to dlog and it won't be used anymore after this
+ * call (so no need to lock it).
+ *
+ * \param d [IN] the dlog to finalize
+ */
+HG_UTIL_PUBLIC void hg_dlog_free(struct hg_dlog *d);
+
+/**
+ * make a named atomic32 counter in a dlog and return a pointer to
+ * it. we use the dlock to ensure a counter under a given name only
+ * gets created once (makes it easy to share a counter across files).
+ * aborts if unable to alloc counter. use it like this:
+ *
+ * hg_atomic_int32_t *foo_count;
+ * static int init = 0;
+ * if (init == 0) {
+ * hg_dlog_mkcount32(dlog, &foo_count, "foocount", "counts of foo");
+ * init = 1;
+ * }
+ *
+ * \param d [IN] dlog to create the counter in
+ * \param cptr [IN/OUT] pointer to use for counter (set to NULL to
+ * start)
+ * \param name [IN] short one word name for counter
+ * \param descr [IN] short description of counter
+ */
+HG_UTIL_PUBLIC void hg_dlog_mkcount32(struct hg_dlog *d, hg_atomic_int32_t **cptr, const char *name,
+ const char *descr);
+
+/**
+ * make a named atomic64 counter in a dlog and return a pointer to
+ * it. we use the dlock to ensure a counter under a given name only
+ * gets created once (makes it easy to share a counter across files).
+ * aborts if unable to alloc counter. use it like this:
+ *
+ * hg_atomic_int64_t *foo_count;
+ * static int init = 0;
+ * if (init == 0) {
+ * hg_dlog_mkcount64(dlog, &foo_count, "foocount", "counts of foo");
+ * init = 1;
+ * }
+ *
+ * \param d [IN] dlog to create the counter in
+ * \param cptr [IN/OUT] pointer to use for counter (set to NULL to
+ * start)
+ * \param name [IN] short one word name for counter
+ * \param descr [IN] short description of counter
+ */
+HG_UTIL_PUBLIC void hg_dlog_mkcount64(struct hg_dlog *d, hg_atomic_int64_t **cptr, const char *name,
+ const char *descr);
+
+/**
+ * attempt to add a log record to a dlog. the id and msg should point
+ * to static strings that are valid throughout the life of the program
+ * (not something that is is on the stack).
+ *
+ * \param d [IN] the dlog to add the log record to
+ * \param file [IN] file entry
+ * \param line [IN] line entry
+ * \param func [IN] func entry
+ * \param msg [IN] log entry message (optional, NULL ok)
+ * \param data [IN] user data pointer for record (optional, NULL ok)
+ *
+ * \return 1 if added, 0 otherwise
+ */
+static HG_UTIL_INLINE unsigned int hg_dlog_addlog(struct hg_dlog *d, const char *file, unsigned int line,
+ const char *func, const char *msg, const void *data);
+
+/**
+ * set the value of stop for a dlog (to enable/disable logging)
+ *
+ * \param d [IN] dlog to set stop in
+ * \param stop [IN] value of stop to use (1=stop, 0=go)
+ */
+HG_UTIL_PUBLIC void hg_dlog_setlogstop(struct hg_dlog *d, int stop);
+
+/**
+ * reset the log. this does not change the counters (since users
+ * have direct access to the hg_atomic_int64_t's, we don't need
+ * an API to change them here).
+ *
+ * \param d [IN] dlog to reset
+ */
+HG_UTIL_PUBLIC void hg_dlog_resetlog(struct hg_dlog *d);
+
+/**
+ * dump dlog info to a stream. set trylock if you want to dump even
+ * if it is locked (e.g. you are crashing and you don't care about
+ * locking).
+ *
+ * \param d [IN] dlog to dump
+ * \param log_func [IN] log function to use (default printf)
+ * \param stream [IN] stream to use
+ * \param trylock [IN] just try to lock (warn if it fails)
+ */
+HG_UTIL_PUBLIC void hg_dlog_dump(struct hg_dlog *d, int (*log_func)(FILE *, const char *, ...), FILE *stream,
+ int trylock);
+
+/**
+ * dump dlog info to a file. set trylock if you want to dump even
+ * if it is locked (e.g. you are crashing and you don't care about
+ * locking). the output file is "base.log" or base-pid.log" depending
+ * on the value of addpid.
+ *
+ * \param d [IN] dlog to dump
+ * \param base [IN] output file basename
+ * \param addpid [IN] add pid to output filename
+ * \param trylock [IN] just try to lock (warn if it fails)
+ */
+HG_UTIL_PUBLIC void hg_dlog_dump_file(struct hg_dlog *d, const char *base, int addpid, int trylock);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE unsigned int
+hg_dlog_addlog(struct hg_dlog *d, const char *file, unsigned int line, const char *func, const char *msg,
+ const void *data)
+{
+ unsigned int rv = 0;
+ unsigned int idx;
+
+ hg_thread_mutex_lock(&d->dlock);
+ if (d->lestop)
+ goto done;
+ if (d->leloop == 0 && d->leadds >= d->lesize)
+ goto done;
+ idx = d->lefree;
+ d->lefree = (d->lefree + 1) % d->lesize;
+ if (d->leadds < d->lesize)
+ d->leadds++;
+ d->le[idx].file = file;
+ d->le[idx].line = line;
+ d->le[idx].func = func;
+ d->le[idx].msg = msg;
+ d->le[idx].data = data;
+ hg_time_get_current(&d->le[idx].time);
+ rv = 1;
+
+done:
+ hg_thread_mutex_unlock(&d->dlock);
+ return rv;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_DLOG_H */
diff --git a/src/mercury/include/mercury_event.h b/src/mercury/include/mercury_event.h
new file mode 100644
index 0000000..8be18a5
--- /dev/null
+++ b/src/mercury/include/mercury_event.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_EVENT_H
+#define MERCURY_EVENT_H
+
+#include "mercury_util_config.h"
+
+#ifdef _WIN32
+
+#else
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(HG_UTIL_HAS_SYSEVENTFD_H)
+#include <sys/eventfd.h>
+#ifndef HG_UTIL_HAS_EVENTFD_T
+typedef uint64_t eventfd_t;
+#endif
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+#include <sys/event.h>
+#define HG_EVENT_IDENT 42 /* User-defined ident */
+#endif
+#endif
+
+/**
+ * Purpose: define an event object that can be used as an event
+ * wait/notify mechanism.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a new event object.
+ *
+ * \return file descriptor on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_event_create(void);
+
+/**
+ * Destroy an event object.
+ *
+ * \param fd [IN] event file descriptor
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_event_destroy(int fd);
+
+/**
+ * Notify for event.
+ *
+ * \param fd [IN] event file descriptor
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_event_set(int fd);
+
+/**
+ * Get event notification.
+ *
+ * \param fd [IN] event file descriptor
+ * \param notified [IN] boolean set to HG_UTIL_TRUE if event received
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_event_get(int fd, hg_util_bool_t *notified);
+
+/*---------------------------------------------------------------------------*/
+#if defined(_WIN32)
+/* TODO */
+#elif defined(HG_UTIL_HAS_SYSEVENTFD_H)
+#ifdef HG_UTIL_HAS_EVENTFD_T
+static HG_UTIL_INLINE int
+hg_event_set(int fd)
+{
+ return (eventfd_write(fd, 1) == 0) ? HG_UTIL_SUCCESS : HG_UTIL_FAIL;
+}
+#else
+static HG_UTIL_INLINE int
+hg_event_set(int fd)
+{
+ eventfd_t count = 1;
+ ssize_t s = write(fd, &count, sizeof(eventfd_t));
+
+ return (s == sizeof(eventfd_t)) ? HG_UTIL_SUCCESS : HG_UTIL_FAIL;
+}
+#endif
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+static HG_UTIL_INLINE int
+hg_event_set(int fd)
+{
+ struct kevent kev;
+ struct timespec timeout = {0, 0};
+ int rc;
+
+ EV_SET(&kev, HG_EVENT_IDENT, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ /* Trigger user-defined event */
+ rc = kevent(fd, &kev, 1, NULL, 0, &timeout);
+
+ return (rc == -1) ? HG_UTIL_FAIL : HG_UTIL_SUCCESS;
+}
+#else
+#error "Not supported on this platform."
+#endif
+
+/*---------------------------------------------------------------------------*/
+#if defined(_WIN32)
+#elif defined(HG_UTIL_HAS_SYSEVENTFD_H)
+#ifdef HG_UTIL_HAS_EVENTFD_T
+static HG_UTIL_INLINE int
+hg_event_get(int fd, hg_util_bool_t *signaled)
+{
+ eventfd_t count = 0;
+
+ if ((eventfd_read(fd, &count) == 0) && count)
+ *signaled = HG_UTIL_TRUE;
+ else {
+ if (errno == EAGAIN)
+ *signaled = HG_UTIL_FALSE;
+ else
+ return HG_UTIL_FAIL;
+ }
+
+ return HG_UTIL_SUCCESS;
+}
+#else
+static HG_UTIL_INLINE int
+hg_event_get(int fd, hg_util_bool_t *signaled)
+{
+ eventfd_t count = 0;
+ ssize_t s = read(fd, &count, sizeof(eventfd_t));
+ if ((s == sizeof(eventfd_t)) && count)
+ *signaled = HG_UTIL_TRUE;
+ else {
+ if (errno == EAGAIN)
+ *signaled = HG_UTIL_FALSE;
+ else
+ return HG_UTIL_FAIL;
+ }
+
+ return HG_UTIL_SUCCESS;
+}
+#endif
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+static HG_UTIL_INLINE int
+hg_event_get(int fd, hg_util_bool_t *signaled)
+{
+ struct kevent kev;
+ int nfds;
+ struct timespec timeout = {0, 0};
+
+ /* Check user-defined event */
+ nfds = kevent(fd, NULL, 0, &kev, 1, &timeout);
+ if (nfds == -1)
+ return HG_UTIL_FAIL;
+
+ *signaled = ((nfds > 0) && (kev.ident == HG_EVENT_IDENT)) ? HG_UTIL_TRUE : HG_UTIL_FALSE;
+
+ return HG_UTIL_SUCCESS;
+}
+#else
+#error "Not supported on this platform."
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_EVENT_H */
diff --git a/src/mercury/include/mercury_hash_string.h b/src/mercury/include/mercury_hash_string.h
new file mode 100644
index 0000000..0b136ca
--- /dev/null
+++ b/src/mercury/include/mercury_hash_string.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_HASH_STRING_H
+#define MERCURY_HASH_STRING_H
+
+#include "mercury_util_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Hash function name for unique ID to register.
+ *
+ * \param string [IN] string name
+ *
+ * \return Non-negative ID that corresponds to string name
+ */
+static HG_UTIL_INLINE unsigned int
+hg_hash_string(const char *string)
+{
+ /* This is the djb2 string hash function */
+
+ unsigned int result = 5381;
+ const unsigned char *p;
+
+ p = (const unsigned char *)string;
+
+ while (*p != '\0') {
+ result = (result << 5) + result + *p;
+ ++p;
+ }
+ return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_HASH_STRING_H */
diff --git a/src/mercury/include/mercury_hash_table.h b/src/mercury/include/mercury_hash_table.h
new file mode 100644
index 0000000..0063f02
--- /dev/null
+++ b/src/mercury/include/mercury_hash_table.h
@@ -0,0 +1,242 @@
+/*
+
+Copyright (c) 2005-2008, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+/**
+ * \file mercury_hash_table.h
+ *
+ * \brief Hash table.
+ *
+ * A hash table stores a set of values which can be addressed by a
+ * key. Given the key, the corresponding value can be looked up
+ * quickly.
+ *
+ * To create a hash table, use \ref hg_hash_table_new. To destroy a
+ * hash table, use \ref hg_hash_table_free.
+ *
+ * To insert a value into a hash table, use \ref hg_hash_table_insert.
+ *
+ * To remove a value from a hash table, use \ref hg_hash_table_remove.
+ *
+ * To look up a value by its key, use \ref hg_hash_table_lookup.
+ *
+ * To iterate over all values in a hash table, use
+ * \ref hg_hash_table_iterate to initialize a \ref hg_hash_table_iter
+ * structure. Each value can then be read in turn using
+ * \ref hg_hash_table_iter_next and \ref hg_hash_table_iter_has_more.
+ */
+
+#ifndef HG_HASH_TABLE_H
+#define HG_HASH_TABLE_H
+
+#include "mercury_util_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A hash table structure.
+ */
+
+typedef struct hg_hash_table hg_hash_table_t;
+
+/**
+ * Structure used to iterate over a hash table.
+ */
+
+typedef struct hg_hash_table_iter hg_hash_table_iter_t;
+
+/**
+ * Internal structure representing an entry in a hash table.
+ */
+
+typedef struct hg_hash_table_entry hg_hash_table_entry_t;
+
+/**
+ * A key to look up a value in a \ref hg_hash_table_t.
+ */
+
+typedef void *hg_hash_table_key_t;
+
+/**
+ * A value stored in a \ref hg_hash_table_t.
+ */
+
+typedef void *hg_hash_table_value_t;
+
+/**
+ * Definition of a \ref hg_hash_table_iter.
+ */
+
+struct hg_hash_table_iter {
+ hg_hash_table_t * hash_table;
+ hg_hash_table_entry_t *next_entry;
+ unsigned int next_chain;
+};
+
+/**
+ * A null \ref HashTableValue.
+ */
+
+#define HG_HASH_TABLE_NULL ((void *)0)
+
+/**
+ * Hash function used to generate hash values for keys used in a hash
+ * table.
+ *
+ * \param value The value to generate a hash value for.
+ * \return The hash value.
+ */
+
+typedef unsigned int (*hg_hash_table_hash_func_t)(hg_hash_table_key_t value);
+
+/**
+ * Function used to compare two keys for equality.
+ *
+ * \return Non-zero if the two keys are equal, zero if the keys are
+ * not equal.
+ */
+
+typedef int (*hg_hash_table_equal_func_t)(hg_hash_table_key_t value1, hg_hash_table_key_t value2);
+
+/**
+ * Type of function used to free keys when entries are removed from a
+ * hash table.
+ */
+
+typedef void (*hg_hash_table_key_free_func_t)(hg_hash_table_key_t value);
+
+/**
+ * Type of function used to free values when entries are removed from a
+ * hash table.
+ */
+
+typedef void (*hg_hash_table_value_free_func_t)(hg_hash_table_value_t value);
+
+/**
+ * Create a new hash table.
+ *
+ * \param hash_func Function used to generate hash keys for the
+ * keys used in the table.
+ * \param equal_func Function used to test keys used in the table
+ * for equality.
+ * \return A new hash table structure, or NULL if it
+ * was not possible to allocate the new hash
+ * table.
+ */
+HG_UTIL_PUBLIC hg_hash_table_t *hg_hash_table_new(hg_hash_table_hash_func_t hash_func,
+ hg_hash_table_equal_func_t equal_func);
+
+/**
+ * Destroy a hash table.
+ *
+ * \param hash_table The hash table to destroy.
+ */
+HG_UTIL_PUBLIC void hg_hash_table_free(hg_hash_table_t *hash_table);
+
+/**
+ * Register functions used to free the key and value when an entry is
+ * removed from a hash table.
+ *
+ * \param hash_table The hash table.
+ * \param key_free_func Function used to free keys.
+ * \param value_free_func Function used to free values.
+ */
+HG_UTIL_PUBLIC void hg_hash_table_register_free_functions(hg_hash_table_t * hash_table,
+ hg_hash_table_key_free_func_t key_free_func,
+ hg_hash_table_value_free_func_t value_free_func);
+
+/**
+ * Insert a value into a hash table, overwriting any existing entry
+ * using the same key.
+ *
+ * \param hash_table The hash table.
+ * \param key The key for the new value.
+ * \param value The value to insert.
+ * \return Non-zero if the value was added successfully,
+ * or zero if it was not possible to allocate
+ * memory for the new entry.
+ */
+HG_UTIL_PUBLIC int hg_hash_table_insert(hg_hash_table_t *hash_table, hg_hash_table_key_t key,
+ hg_hash_table_value_t value);
+
+/**
+ * Look up a value in a hash table by key.
+ *
+ * \param hash_table The hash table.
+ * \param key The key of the value to look up.
+ * \return The value, or \ref HASH_TABLE_NULL if there
+ * is no value with that key in the hash table.
+ */
+HG_UTIL_PUBLIC hg_hash_table_value_t hg_hash_table_lookup(hg_hash_table_t * hash_table,
+ hg_hash_table_key_t key);
+
+/**
+ * Remove a value from a hash table.
+ *
+ * \param hash_table The hash table.
+ * \param key The key of the value to remove.
+ * \return Non-zero if a key was removed, or zero if the
+ * specified key was not found in the hash table.
+ */
+HG_UTIL_PUBLIC int hg_hash_table_remove(hg_hash_table_t *hash_table, hg_hash_table_key_t key);
+
+/**
+ * Retrieve the number of entries in a hash table.
+ *
+ * \param hash_table The hash table.
+ * \return The number of entries in the hash table.
+ */
+HG_UTIL_PUBLIC unsigned int hg_hash_table_num_entries(hg_hash_table_t *hash_table);
+
+/**
+ * Initialise a \ref HashTableIterator to iterate over a hash table.
+ *
+ * \param hash_table The hash table.
+ * \param iter Pointer to an iterator structure to
+ * initialise.
+ */
+HG_UTIL_PUBLIC void hg_hash_table_iterate(hg_hash_table_t *hash_table, hg_hash_table_iter_t *iter);
+
+/**
+ * Determine if there are more keys in the hash table to iterate over.
+ *
+ * \param iterator The hash table iterator.
+ * \return Zero if there are no more values to iterate
+ * over, non-zero if there are more values to
+ * iterate over.
+ */
+HG_UTIL_PUBLIC int hg_hash_table_iter_has_more(hg_hash_table_iter_t *iterator);
+
+/**
+ * Using a hash table iterator, retrieve the next key.
+ *
+ * \param iterator The hash table iterator.
+ * \return The next key from the hash table, or
+ * \ref HG_HASH_TABLE_NULL if there are no more
+ * keys to iterate over.
+ */
+HG_UTIL_PUBLIC hg_hash_table_value_t hg_hash_table_iter_next(hg_hash_table_iter_t *iterator);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HG_HASH_TABLE_H */
diff --git a/src/mercury/include/mercury_header.h b/src/mercury/include/mercury_header.h
new file mode 100644
index 0000000..801ec69
--- /dev/null
+++ b/src/mercury/include/mercury_header.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_HEADER_H
+#define MERCURY_HEADER_H
+
+#include "mercury_core_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#if defined(__GNUC__) || defined(_WIN32)
+#pragma pack(push, 1)
+#else
+#warning "Proc header struct padding may not be consistent across platforms."
+#endif
+#ifdef HG_HAS_CHECKSUMS
+struct hg_header_hash {
+ hg_uint32_t payload; /* Payload checksum (32-bits checksum) */
+};
+#endif
+
+struct hg_header_input {
+#ifdef HG_HAS_CHECKSUMS
+ struct hg_header_hash hash; /* Hash */
+#else
+ hg_uint32_t pad;
+#endif
+ /* 160 bits here */
+};
+
+struct hg_header_output {
+#ifdef HG_HAS_CHECKSUMS
+ struct hg_header_hash hash; /* Hash */
+#endif
+ hg_uint32_t pad;
+ /* 128/64 bits here */
+};
+#if defined(__GNUC__) || defined(_WIN32)
+#pragma pack(pop)
+#endif
+
+/* Common header struct input/output */
+struct hg_header {
+ union {
+ struct hg_header_input input;
+ struct hg_header_output output;
+ } msg; /* Header message */
+ hg_op_t op; /* Header operation type */
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static HG_INLINE size_t hg_header_get_size(hg_op_t op);
+
+/**
+ * Get size reserved for header (separate user data stored in payload).
+ *
+ * \return Non-negative size value
+ */
+static HG_INLINE size_t
+hg_header_get_size(hg_op_t op)
+{
+ hg_size_t ret = 0;
+
+ switch (op) {
+ case HG_INPUT:
+ ret = sizeof(struct hg_header_input);
+ break;
+ case HG_OUTPUT:
+ ret = sizeof(struct hg_header_output);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * Initialize RPC header.
+ *
+ * \param hg_header [IN/OUT] pointer to header structure
+ * \param op [IN] HG operation type: HG_INPUT / HG_OUTPUT
+ */
+HG_PRIVATE void hg_header_init(struct hg_header *hg_header, hg_op_t op);
+
+/**
+ * Finalize RPC header.
+ *
+ * \param hg_header [IN/OUT] pointer to header structure
+ */
+HG_PRIVATE void hg_header_finalize(struct hg_header *hg_header);
+
+/**
+ * Reset RPC header.
+ *
+ * \param hg_header [IN/OUT] pointer to header structure
+ * \param op [IN] HG operation type: HG_INPUT / HG_OUTPUT
+ */
+HG_PRIVATE void hg_header_reset(struct hg_header *hg_header, hg_op_t op);
+
+/**
+ * Process private information for sending/receiving RPC.
+ *
+ * \param op [IN] operation type: HG_ENCODE / HG_DECODE
+ * \param buf [IN/OUT] buffer
+ * \param buf_size [IN] buffer size
+ * \param hg_header [IN/OUT] pointer to header structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PRIVATE hg_return_t hg_header_proc(hg_proc_op_t op, void *buf, size_t buf_size,
+ struct hg_header *hg_header);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_HEADER_H */
diff --git a/src/mercury/include/mercury_hl.h b/src/mercury/include/mercury_hl.h
new file mode 100644
index 0000000..c6d5b10
--- /dev/null
+++ b/src/mercury/include/mercury_hl.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_HL_H
+#define MERCURY_HL_H
+
+#include "mercury.h"
+#include "mercury_bulk.h"
+#include "mercury_request.h"
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/**
+ * Define macros so that default classes/contexts can be easily renamed
+ * if we ever need to. Users should use macros and not global variables
+ * directly.
+ */
+#define HG_CLASS_DEFAULT hg_class_default_g
+#define HG_CONTEXT_DEFAULT hg_context_default_g
+#define HG_REQUEST_CLASS_DEFAULT hg_request_class_default_g
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/********************/
+/* Public Variables */
+/********************/
+
+/* HG default */
+extern HG_PUBLIC hg_class_t *HG_CLASS_DEFAULT;
+extern HG_PUBLIC hg_context_t *HG_CONTEXT_DEFAULT;
+extern HG_PUBLIC hg_request_class_t *HG_REQUEST_CLASS_DEFAULT;
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+/**
+ * Initialize Mercury high-level layer and create default classes/contexts.
+ * If no info_string is passed, the HG HL layer will attempt to initialize
+ * NA by using the value contained in the environment variable called
+ * MERCURY_PORT_NAME.
+ * \remark HG_Hl_finalize() is registered with atexit() so that default
+ * classes/contexts are freed at process termination.
+ *
+ * \param na_info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param na_listen [IN] listen for incoming connections
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Hl_init(const char *na_info_string, hg_bool_t na_listen);
+
+/**
+ * Initialize Mercury high-level layer with options provided by init_info.
+ * Must be finalized with HG_Hl_finalize().
+ * \remark HG_Hl_finalize() is registered with atexit() so that default
+ * classes/contexts are freed at process termination.
+ * \remark HG_Hl_init_opt() may become HG_Hl_init() in the future.
+ *
+ * \param na_info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param na_listen [IN] listen for incoming connections
+ * \param hg_init_info [IN] (Optional) HG init info, NULL if no info
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Hl_init_opt(const char *na_info_string, hg_bool_t na_listen,
+ const struct hg_init_info *hg_init_info);
+
+/**
+ * Finalize Mercury high-level layer.
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Hl_finalize(void);
+
+/**
+ * Lookup an address and wait for its completion. Address must be freed
+ * using HG_Addr_free().
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Hl_addr_lookup_wait(hg_context_t *context, hg_request_class_t *request_class,
+ const char *name, hg_addr_t *addr, unsigned int timeout);
+
+/**
+ * Forward a call and wait for its completion. A HG handle must have been
+ * previously created. Output can be queried using HG_Get_output() and freed
+ * using HG_Free_output().
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Hl_forward_wait(hg_request_class_t *request_class, hg_handle_t handle,
+ void *in_struct, unsigned int timeout);
+
+/**
+ * Initiate a bulk data transfer and wait for its completion.
+ *
+ * \param context [IN] pointer to HG context
+ * \param op [IN] transfer operation:
+ * - HG_BULK_PUSH
+ * - HG_BULK_PULL
+ * \param origin_addr [IN] abstract address of origin
+ * \param origin_handle [IN] abstract bulk handle
+ * \param origin_offset [IN] offset
+ * \param local_handle [IN] abstract bulk handle
+ * \param local_offset [IN] offset
+ * \param size [IN] size of data to be transferred
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t HG_Hl_bulk_transfer_wait(hg_context_t *context, hg_request_class_t *request_class,
+ hg_bulk_op_t op, hg_addr_t origin_addr,
+ hg_bulk_t origin_handle, hg_size_t origin_offset,
+ hg_bulk_t local_handle, hg_size_t local_offset, hg_size_t size,
+ unsigned int timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_HL_H */
diff --git a/src/mercury/include/mercury_hl_macros.h b/src/mercury/include/mercury_hl_macros.h
new file mode 100644
index 0000000..6c9135b
--- /dev/null
+++ b/src/mercury/include/mercury_hl_macros.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_HL_MACROS_H
+#define MERCURY_HL_MACROS_H
+
+#include "mercury_hl.h"
+#include "mercury_macros.h"
+
+/**
+ * The purpose of these macros is to generate boilerplate code in order
+ * to send and execute HG RPC calls.
+ * Since these macros make use of the mercury high-level interface, applications
+ * using these macros must link to the mercury_hl library.
+ * HG_XXX macros are private macros / MERCURY_XXX are public macros.
+ * Macros defined in this file are:
+ * - MERCURY_GEN_LOG_MESSAGE
+ * - MERCURY_GEN_RPC_STUB
+ * - MERCURY_GEN_CALLBACK_STUB
+ */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Return parameter with fixed name */
+#define HG_GEN_RET_PARAM(ret_type) ((ret_type)(ret))
+
+/* Generate ((param) (datai)) element */
+#define HG_GEN_PARAM_NAME(r, prefix, i, param) ((param)(BOOST_PP_CAT(prefix, i)))
+
+/* Generate parameter names and ((type) (name)) sequence */
+#define HG_GEN_PARAM_NAME_SEQ(prefix, type_seq) BOOST_PP_SEQ_FOR_EACH_I(HG_GEN_PARAM_NAME, prefix, type_seq)
+
+/* Extract parameter (type name) element */
+#define HG_GEN_DECL_FUNC_PARAM(r, is_ref, param) \
+ (HG_GEN_GET_TYPE(param) BOOST_PP_IF(is_ref, *, BOOST_PP_EMPTY()) HG_GEN_GET_NAME(param))
+
+/* Extract (type name) sequence */
+#define HG_GEN_DECL_FUNC_PARAM_SEQ(is_ref, param_seq) \
+ BOOST_PP_SEQ_FOR_EACH(HG_GEN_DECL_FUNC_PARAM, is_ref, param_seq)
+
+/* Extract function parameter declarations */
+#define HG_GEN_DECL_FUNC_PARAMS(with_input, in_params, extra_in_params, with_output, out_params, \
+ extra_out_params) \
+ BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_IF( \
+ BOOST_PP_OR(with_input, with_output), \
+ HG_GEN_DECL_FUNC_PARAM_SEQ(0, in_params) HG_GEN_DECL_FUNC_PARAM_SEQ(0, extra_in_params) \
+ HG_GEN_DECL_FUNC_PARAM_SEQ(1, out_params) HG_GEN_DECL_FUNC_PARAM_SEQ(1, extra_out_params), \
+ (void)))
+
+/* Extract parameter (get_name(param)) element */
+#define HG_GEN_FUNC_PARAM(r, is_ref, param) (BOOST_PP_IF(is_ref, &, BOOST_PP_EMPTY()) HG_GEN_GET_NAME(param))
+
+/* Extract (name) sequence */
+#define HG_GEN_FUNC_PARAM_SEQ(is_ref, param_seq) BOOST_PP_SEQ_FOR_EACH(HG_GEN_FUNC_PARAM, is_ref, param_seq)
+
+/* Extract function parameters */
+#define HG_GEN_FUNC_PARAMS(with_input, in_params, extra_in_params, with_output, out_params, \
+ extra_out_params) \
+ BOOST_PP_SEQ_TO_TUPLE( \
+ BOOST_PP_IF(BOOST_PP_OR(with_input, with_output), \
+ HG_GEN_FUNC_PARAM_SEQ(0, in_params) HG_GEN_FUNC_PARAM_SEQ(0, extra_in_params) \
+ HG_GEN_FUNC_PARAM_SEQ(1, out_params) HG_GEN_FUNC_PARAM_SEQ(1, extra_out_params), \
+ ()))
+
+/* Generate declaration of parameters --> type name; */
+#define HG_GEN_DECL_PARAMS(param_seq) BOOST_PP_SEQ_FOR_EACH(HG_GEN_STRUCT_FIELD, , param_seq)
+
+/* Assign param to struct field ( e.g., struct_name.param_1 = param_1; ) */
+#define HG_SET_STRUCT_PARAM(r, struct_name, param) \
+ struct_name.HG_GEN_GET_NAME(param) = HG_GEN_GET_NAME(param);
+
+/* Assign param ((type) (name)) sequence to struct_name */
+#define HG_SET_STRUCT_PARAMS(struct_name, params) \
+ BOOST_PP_SEQ_FOR_EACH(HG_SET_STRUCT_PARAM, struct_name, params)
+
+/* Assign struct_name field to param ( e.g., param_1 = struct_name.param_1; ) */
+#define HG_GET_STRUCT_PARAM(r, struct_name, param) \
+ HG_GEN_GET_NAME(param) = struct_name.HG_GEN_GET_NAME(param);
+
+/* Assign struct_name fields to param ((type) (name)) sequence */
+#define HG_GET_STRUCT_PARAMS(struct_name, params) \
+ BOOST_PP_SEQ_FOR_EACH(HG_GET_STRUCT_PARAM, struct_name, params)
+
+/* Assign struct_name field to out param ( e.g., *param_1 = struct_name.param_1;
+ * ) */
+#define HG_GET_OUT_STRUCT_PARAM(r, struct_name, param) \
+ *HG_GEN_GET_NAME(param) = struct_name.HG_GEN_GET_NAME(param);
+
+/* Assign struct_name fields to out parame ((type) (name)) sequence */
+#define HG_GET_OUT_STRUCT_PARAMS(struct_name, params) \
+ BOOST_PP_SEQ_FOR_EACH(HG_GET_OUT_STRUCT_PARAM, struct_name, params)
+
+/**
+ * Get/free output boilerplate code
+ */
+
+/* Get output */
+#define HG_GET_OUTPUT(with_ret, ret_fail) \
+ hg_ret = HG_Get_output(handle, &out_struct); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
+ goto done; \
+ }
+
+/* Free output */
+#define HG_FREE_OUTPUT(with_ret, ret_fail) \
+ hg_ret = HG_Free_output(handle, &out_struct); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
+ goto done; \
+ }
+
+/**
+ * Bulk data support boilerplate code
+ */
+
+/* Extra input parameters for bulk data */
+#define HG_BULK_CONST_BUF ((const void *)(bulk_buf))
+#define HG_BULK_BUF ((void *)(bulk_buf))
+#define HG_BULK_COUNT ((hg_uint64_t)(bulk_count))
+#define HG_BULK_EXTRA_IN_PARAM HG_BULK_BUF HG_BULK_COUNT
+
+/* Bulk handle parameter */
+#define HG_BULK_PARAM ((hg_bulk_t)(bulk_handle))
+
+/* Local bulk handle parameter */
+#define HG_BULK_LOCAL_PARAM ((hg_bulk_t)(local_bulk_handle))
+
+/* Create bulk handle */
+#define HG_BULK_REGISTER(handle, bulk_handle, with_ret, fail_ret, bulk_read) \
+ hg_ret = HG_Bulk_create(HG_Get_info(handle)->hg_bulk_class, 1, \
+ &HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BUF)), \
+ &HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_COUNT)), \
+ BOOST_PP_IF(bulk_read, HG_BULK_READ_ONLY, HG_BULK_READWRITE), &bulk_handle); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = fail_ret;, BOOST_PP_EMPTY()) \
+ goto done; \
+ }
+
+/* Free bulk handle */
+#define HG_BULK_FREE(bulk_handle, with_ret, fail_ret) \
+ hg_ret = HG_Bulk_free(bulk_handle); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = fail_ret;, BOOST_PP_EMPTY()) \
+ goto done; \
+ }
+
+/* Declare variables required for bulk transfers */
+#define HG_GEN_DECL_BULK_PARAMS HG_GEN_DECL_PARAMS(HG_BULK_PARAM HG_BULK_LOCAL_PARAM HG_BULK_EXTRA_IN_PARAM)
+
+/* Allocate memory and create local bulk handle */
+#define HG_BULK_LOCAL_ALLOCATE(origin_bulk_handle, local_bulk_handle) \
+ HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_COUNT)) = HG_Bulk_get_size(origin_bulk_handle); \
+ HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BUF)) = \
+ malloc(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_COUNT))); \
+ HG_Bulk_create(HG_Get_info(handle)->hg_bulk_class, 1, &HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BUF)), \
+ &HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_COUNT)), HG_BULK_READWRITE, \
+ &local_bulk_handle);
+
+/* Free memory and local handle */
+#define HG_BULK_LOCAL_FREE(local_bulk_handle) \
+ hg_ret = HG_Bulk_free(local_bulk_handle); \
+ if (hg_ret != HG_SUCCESS) { \
+ goto done; \
+ } \
+ free(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BUF)));
+
+/* Transfer bulk data using origin/local bulk handles (pull or push) */
+#define HG_BULK_TRANSFER(handle, origin_bulk_handle, local_bulk_handle, bulk_read) \
+ hg_ret = HG_Hl_bulk_transfer_wait( \
+ HG_Get_info(handle)->bulk_context, BOOST_PP_IF(bulk_read, HG_BULK_PULL, HG_BULK_PUSH), \
+ HG_Get_info(handle)->addr, HG_Get_info(handle)->target_id, origin_bulk_handle, 0, local_bulk_handle, \
+ 0, HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_COUNT))); \
+ if (hg_ret != HG_SUCCESS) { \
+ goto done; \
+ }
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/**
+ * Advanced BOOST macros:
+ * - MERCURY_GEN_RPC_STUB
+ * - MERCURY_GEN_CALLBACK_STUB
+ */
+
+/* Custom function that applications can define for log purposes (none by
+ * default) */
+#ifndef MERCURY_GEN_LOG_MESSAGE
+#define MERCURY_GEN_LOG_MESSAGE(x)
+#endif
+
+/* Booleans for MERCURY_GEN_MACROS */
+#define MERCURY_GEN_FALSE 0
+#define MERCURY_GEN_TRUE 1
+
+/* Generate RPC stub */
+#define MERCURY_GEN_RPC_STUB(gen_func_name, func_name, with_ret, ret_type_name, ret_fail, with_input, \
+ in_struct_type_name, in_params, with_output, out_struct_type_name, out_params, \
+ with_bulk, bulk_read) \
+ BOOST_PP_IF(with_ret, ret_type_name, void) \
+ gen_func_name HG_GEN_DECL_FUNC_PARAMS(with_input, in_params, \
+ BOOST_PP_IF(with_bulk, HG_BULK_EXTRA_IN_PARAM, BOOST_PP_EMPTY()), \
+ with_output, out_params, ) \
+ { \
+ BOOST_PP_IF(with_input, in_struct_type_name in_struct;, BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), out_struct_type_name out_struct;, BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_ret, ret_type_name ret;, BOOST_PP_EMPTY()) \
+ hg_id_t id; \
+ hg_handle_t handle; \
+ BOOST_PP_IF(with_bulk, HG_GEN_DECL_PARAMS(HG_BULK_PARAM), BOOST_PP_EMPTY()) \
+ hg_bool_t func_registered; \
+ hg_return_t hg_ret; \
+ \
+ /* Init stack if not initialized */ \
+ HG_Hl_init(NULL, 0); \
+ \
+ /* Check whether call has already been registered or not */ \
+ HG_Registered_rpc(HG_CLASS_DEFAULT, BOOST_PP_STRINGIZE(func_name), &func_registered, &id); \
+ if (!func_registered) { \
+ id = MERCURY_REGISTER( \
+ HG_CLASS_DEFAULT, BOOST_PP_STRINGIZE(func_name), \
+ BOOST_PP_IF(with_input, in_struct_type_name, void), \
+ BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), out_struct_type_name, void), NULL); \
+ } \
+ \
+ /* Create HG handle */ \
+ hg_ret = HG_Create(HG_CLASS_DEFAULT, HG_CONTEXT_DEFAULT, NA_ADDR_DEFAULT, id, &handle); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
+ goto done; \
+ } \
+ \
+ /* Create bulk handle */ \
+ BOOST_PP_IF(with_bulk, \
+ HG_BULK_REGISTER(handle, HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM)), with_ret, \
+ ret_fail, bulk_read), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Fill input structure */ \
+ BOOST_PP_IF(with_input, \
+ HG_SET_STRUCT_PARAMS(in_struct, \
+ in_params BOOST_PP_IF(with_bulk, HG_BULK_PARAM, BOOST_PP_EMPTY())), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Forward call to default target */ \
+ hg_ret = HG_Hl_forward_wait(handle, BOOST_PP_IF(with_input, &in_struct, NULL)); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
+ goto done; \
+ } \
+ \
+ /* Free bulk handle */ \
+ BOOST_PP_IF(with_bulk, \
+ HG_BULK_FREE(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM)), with_ret, ret_fail), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Get output */ \
+ BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), HG_GET_OUTPUT(with_ret, ret_fail), BOOST_PP_EMPTY()) \
+ \
+ /* Get output parameters */ \
+ BOOST_PP_IF(with_ret, HG_GET_STRUCT_PARAMS(out_struct, ((ret_type)(ret))), BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_output, HG_GET_OUT_STRUCT_PARAMS(out_struct, out_params), BOOST_PP_EMPTY()) \
+ \
+ /* Free output */ \
+ BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), HG_FREE_OUTPUT(with_ret, ret_fail), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Destroy handle */ \
+ hg_ret = HG_Destroy(handle); \
+ if (hg_ret != HG_SUCCESS) { \
+ BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
+ goto done; \
+ } \
+ \
+done: \
+ \
+ return BOOST_PP_IF(with_ret, ret, BOOST_PP_EMPTY()); \
+ }
+
+/* Generate callback stub */
+#define MERCURY_GEN_CALLBACK_STUB(gen_func_name, func_name, with_ret, ret_type, with_input, \
+ in_struct_type_name, in_params, with_output, out_struct_type_name, \
+ out_params, with_bulk, bulk_read, with_thread, thread_pool) \
+ static BOOST_PP_IF(with_thread, HG_THREAD_RETURN_TYPE BOOST_PP_CAT(gen_func_name, _thread), \
+ hg_return_t gen_func_name)(BOOST_PP_IF(with_thread, void *arg, hg_handle_t handle)) \
+ { \
+ BOOST_PP_IF(with_thread, hg_handle_t handle = (hg_handle_t)arg; \
+ hg_thread_ret_t thread_ret = (hg_thread_ret_t)0;, BOOST_PP_EMPTY()) \
+ hg_return_t hg_ret = HG_SUCCESS; \
+ BOOST_PP_IF(with_input, in_struct_type_name in_struct;, BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), out_struct_type_name out_struct;, BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_input, HG_GEN_DECL_PARAMS(in_params), BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_output, HG_GEN_DECL_PARAMS(out_params), BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_ret, ret_type ret;, BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_bulk, HG_GEN_DECL_BULK_PARAMS, BOOST_PP_EMPTY()) \
+ \
+ /* Get input */ \
+ BOOST_PP_IF( \
+ with_input, hg_ret = HG_Get_input(handle, &in_struct); \
+ if (hg_ret != HG_SUCCESS) { goto done; } \
+ \
+ /* Get parameters */ \
+ HG_GET_STRUCT_PARAMS(in_struct, \
+ in_params BOOST_PP_IF(with_bulk, HG_BULK_PARAM, BOOST_PP_EMPTY())), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Allocate bulk handle */ \
+ BOOST_PP_IF(with_bulk, \
+ HG_BULK_LOCAL_ALLOCATE(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM)), \
+ HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_LOCAL_PARAM))), \
+ BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_bulk, \
+ BOOST_PP_IF(bulk_read, \
+ HG_BULK_TRANSFER(handle, HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM)), \
+ HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_LOCAL_PARAM)), \
+ bulk_read), \
+ BOOST_PP_EMPTY()), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Call function */ \
+ MERCURY_GEN_LOG_MESSAGE(BOOST_PP_STRINGIZE(func_name)); \
+ BOOST_PP_IF(with_ret, ret =, BOOST_PP_EMPTY()) \
+ func_name HG_GEN_FUNC_PARAMS(with_input, in_params, \
+ BOOST_PP_IF(with_bulk, HG_BULK_EXTRA_IN_PARAM, BOOST_PP_EMPTY()), \
+ with_output, out_params, ); \
+ \
+ BOOST_PP_IF(with_bulk, \
+ BOOST_PP_IF(bulk_read, BOOST_PP_EMPTY(), \
+ HG_BULK_TRANSFER(handle, HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM)), \
+ HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_LOCAL_PARAM)), \
+ bulk_read)), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Free bulk handle */ \
+ BOOST_PP_IF(with_bulk, HG_BULK_LOCAL_FREE(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_LOCAL_PARAM))), \
+ BOOST_PP_EMPTY()) \
+ \
+ /* Fill output structure */ \
+ BOOST_PP_IF(with_ret, HG_SET_STRUCT_PARAMS(out_struct, ((ret_type)(ret))), BOOST_PP_EMPTY()) \
+ BOOST_PP_IF(with_output, HG_SET_STRUCT_PARAMS(out_struct, out_params), BOOST_PP_EMPTY()) \
+ \
+ /* Respond back */ \
+ hg_ret = HG_Respond(handle, NULL, NULL, \
+ BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), &out_struct, NULL)); \
+ if (hg_ret != HG_SUCCESS) { \
+ goto done; \
+ } \
+ \
+ /* Free input */ \
+ BOOST_PP_IF( \
+ with_input, hg_ret = HG_Free_input(handle, &in_struct); \
+ if (hg_ret != HG_SUCCESS) { goto done; }, BOOST_PP_EMPTY()) \
+ \
+ /* Destroy handle */ \
+ hg_ret = HG_Destroy(handle); \
+ if (hg_ret != HG_SUCCESS) { \
+ goto done; \
+ } \
+ \
+done: \
+ \
+ BOOST_PP_IF(with_thread, return thread_ret;, return hg_ret;) \
+ } \
+ BOOST_PP_IF( \
+ with_thread, \
+ static hg_return_t gen_func_name(hg_handle_t handle) { \
+ hg_return_t ret = HG_SUCCESS; \
+ hg_thread_pool_post(thread_pool, &BOOST_PP_CAT(gen_func_name, _thread), handle); \
+ return ret; \
+ }, \
+ BOOST_PP_EMPTY())
+
+#endif /* MERCURY_HL_MACROS_H */
diff --git a/src/mercury/include/mercury_list.h b/src/mercury/include/mercury_list.h
new file mode 100644
index 0000000..18ce93a
--- /dev/null
+++ b/src/mercury/include/mercury_list.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Code below is derived from sys/queue.h which follows the below notice:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef MERCURY_LIST_H
+#define MERCURY_LIST_H
+
+#define HG_LIST_HEAD_INITIALIZER(name) \
+ { \
+ NULL \
+ }
+
+#define HG_LIST_HEAD_INIT(struct_head_name, var_name) \
+ struct struct_head_name var_name = HG_LIST_HEAD_INITIALIZER(var_name)
+
+#define HG_LIST_HEAD_DECL(struct_head_name, struct_entry_name) \
+ struct struct_head_name { \
+ struct struct_entry_name *head; \
+ }
+
+#define HG_LIST_HEAD(struct_entry_name) \
+ struct { \
+ struct struct_entry_name *head; \
+ }
+
+#define HG_LIST_ENTRY(struct_entry_name) \
+ struct { \
+ struct struct_entry_name * next; \
+ struct struct_entry_name **prev; \
+ }
+
+#define HG_LIST_INIT(head_ptr) \
+ do { \
+ (head_ptr)->head = NULL; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_IS_EMPTY(head_ptr) ((head_ptr)->head == NULL)
+
+#define HG_LIST_FIRST(head_ptr) ((head_ptr)->head)
+
+#define HG_LIST_NEXT(entry_ptr, entry_field_name) ((entry_ptr)->entry_field_name.next)
+
+#define HG_LIST_INSERT_AFTER(list_entry_ptr, entry_ptr, entry_field_name) \
+ do { \
+ if (((entry_ptr)->entry_field_name.next = (list_entry_ptr)->entry_field_name.next) != NULL) \
+ (list_entry_ptr)->entry_field_name.next->entry_field_name.prev = \
+ &(entry_ptr)->entry_field_name.next; \
+ (list_entry_ptr)->entry_field_name.next = (entry_ptr); \
+ (entry_ptr)->entry_field_name.prev = &(list_entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_INSERT_BEFORE(list_entry_ptr, entry_ptr, entry_field_name) \
+ do { \
+ (entry_ptr)->entry_field_name.prev = (list_entry_ptr)->entry_field_name.prev; \
+ (entry_ptr)->entry_field_name.next = (list_entry_ptr); \
+ *(list_entry_ptr)->entry_field_name.prev = (entry_ptr); \
+ (list_entry_ptr)->entry_field_name.prev = &(entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_INSERT_HEAD(head_ptr, entry_ptr, entry_field_name) \
+ do { \
+ if (((entry_ptr)->entry_field_name.next = (head_ptr)->head) != NULL) \
+ (head_ptr)->head->entry_field_name.prev = &(entry_ptr)->entry_field_name.next; \
+ (head_ptr)->head = (entry_ptr); \
+ (entry_ptr)->entry_field_name.prev = &(head_ptr)->head; \
+ } while (/*CONSTCOND*/ 0)
+
+/* TODO would be nice to not have any condition */
+#define HG_LIST_REMOVE(entry_ptr, entry_field_name) \
+ do { \
+ if ((entry_ptr)->entry_field_name.next != NULL) \
+ (entry_ptr)->entry_field_name.next->entry_field_name.prev = (entry_ptr)->entry_field_name.prev; \
+ *(entry_ptr)->entry_field_name.prev = (entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_FOREACH(var, head_ptr, entry_field_name) \
+ for ((var) = ((head_ptr)->head); (var); (var) = ((var)->entry_field_name.next))
+
+#endif /* MERCURY_LIST_H */
diff --git a/src/mercury/include/mercury_log.h b/src/mercury/include/mercury_log.h
new file mode 100644
index 0000000..0e98710
--- /dev/null
+++ b/src/mercury/include/mercury_log.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/*
+ * Copyright (c) 2004, 2005, 2006, 2007 David Young. All rights reserved.
+ *
+ * Copyright (c) 2004 Urbana-Champaign Independent Media Center.
+ * All rights reserved.
+ *
+ *
+ * Portions of hlog are Copyright (c) David Young. The applicable copyright
+ * notice and licensing terms are reproduced here:
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 David Young. All rights reserved.
+ *
+ * This file contains code contributed by David Young.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * -----------------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
+ *
+ * Portions of hlog are Copyright (c) Urbana-Champaign Independent Media Center.
+ * The applicable copyright notice and licensing terms are reproduced here:
+ *
+ * Copyright (c) 2004 Urbana-Champaign Independent Media Center.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MERCURY_LOG_H
+#define MERCURY_LOG_H
+
+#include "mercury_dlog.h"
+#include "mercury_queue.h"
+#include "mercury_util_config.h"
+
+#include <stdio.h>
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* For compatibility */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)
+#if defined(__GNUC__) && (__GNUC__ >= 2)
+#define __func__ __FUNCTION__
+#else
+#define __func__ "<unknown>"
+#endif
+#elif defined(_WIN32)
+#define __func__ __FUNCTION__
+#endif
+
+/* Cat macro */
+#define HG_UTIL_CAT(x, y) x##y
+
+/* Stringify macro */
+#define HG_UTIL_STRINGIFY(x) #x
+
+/* Constructor (used to initialize log outlets) */
+#define HG_UTIL_CONSTRUCTOR __attribute__((constructor))
+
+/* Available log levels, additional log levels should be added to that list by
+ * order of verbosity. Format is:
+ * - enum type
+ * - level name
+ * - default output
+ *
+ * error: print error level logs
+ * warning: print warning level logs
+ * min_debug: store minimal debug information and defer printing until error
+ * debug: print debug level logs
+ */
+#define HG_LOG_LEVELS \
+ X(HG_LOG_LEVEL_NONE, "", NULL) /*!< no log */ \
+ X(HG_LOG_LEVEL_ERROR, "error", &stderr) /*!< error log type */ \
+ X(HG_LOG_LEVEL_WARNING, "warning", &stdout) /*!< warning log type */ \
+ X(HG_LOG_LEVEL_MIN_DEBUG, "min_debug", &stdout) /*!< debug log type */ \
+ X(HG_LOG_LEVEL_DEBUG, "debug", &stdout) /*!< debug log type */ \
+ X(HG_LOG_LEVEL_MAX, "", NULL)
+
+/* HG_LOG_OUTLET: global variable name of log outlet. */
+#define HG_LOG_OUTLET(name) HG_UTIL_CAT(name, _log_outlet_g)
+
+/* HG_LOG_OUTLET_DECL: declare an outlet. */
+#define HG_LOG_OUTLET_DECL(name) struct hg_log_outlet HG_LOG_OUTLET(name)
+
+/*
+ * HG_LOG_OUTLET_INITIALIZER: initializer for a log in a global variable.
+ * (parent and debug_log are optional and can be set to NULL)
+ */
+#define HG_LOG_OUTLET_INITIALIZER(name, state, parent, debug_log) \
+ { \
+ HG_UTIL_STRINGIFY(name), state, HG_LOG_LEVEL_NONE, parent, debug_log, { NULL } \
+ }
+
+/* HG_LOG_OUTLET_SUBSYS_INITIALIZER: initializer for a sub-system log. */
+#define HG_LOG_OUTLET_SUBSYS_INITIALIZER(name, parent_name) \
+ HG_LOG_OUTLET_INITIALIZER(name, HG_LOG_PASS, &HG_LOG_OUTLET(parent_name), NULL)
+
+/* HG_LOG_OUTLET_SUBSYS_STATE_INITIALIZER: initializer for a sub-system log with
+ * a defined state. */
+#define HG_LOG_OUTLET_SUBSYS_STATE_INITIALIZER(name, parent_name, state) \
+ HG_LOG_OUTLET_INITIALIZER(name, state, &HG_LOG_OUTLET(parent_name), NULL)
+
+/* HG_LOG_SUBSYS_REGISTER: register a name */
+#define HG_LOG_SUBSYS_REGISTER(name) \
+ static void HG_UTIL_CAT(hg_log_outlet_, name)(void) HG_UTIL_CONSTRUCTOR; \
+ static void HG_UTIL_CAT(hg_log_outlet_, name)(void) { hg_log_outlet_register(&HG_LOG_OUTLET(name)); } \
+ /* Keep unused prototype to use semicolon at end of macro */ \
+ void hg_log_outlet_##name##_unused(void)
+
+/* HG_LOG_SUBSYS_DECL_REGISTER: declare and register a log outlet. */
+#define HG_LOG_SUBSYS_DECL_REGISTER(name, parent_name) \
+ struct hg_log_outlet HG_LOG_OUTLET(name) = HG_LOG_OUTLET_SUBSYS_INITIALIZER(name, parent_name); \
+ HG_LOG_SUBSYS_REGISTER(name)
+
+/* HG_LOG_SUBSYS_DECL_STATE_REGISTER: declare and register a log outlet and
+ * enforce an init state. */
+#define HG_LOG_SUBSYS_DECL_STATE_REGISTER(name, parent_name, state) \
+ struct hg_log_outlet HG_LOG_OUTLET(name) = \
+ HG_LOG_OUTLET_SUBSYS_STATE_INITIALIZER(name, parent_name, state); \
+ HG_LOG_SUBSYS_REGISTER(name)
+
+/* Log macro */
+#define HG_LOG_WRITE(name, log_level, ...) \
+ do { \
+ if (HG_LOG_OUTLET(name).level < log_level) \
+ break; \
+ hg_log_write(&HG_LOG_OUTLET(name), log_level, __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } while (0)
+
+/* Log macro */
+#define HG_LOG_WRITE_DEBUG(name, debug_func, ...) \
+ do { \
+ if (HG_LOG_OUTLET(name).level < HG_LOG_LEVEL_MIN_DEBUG) \
+ break; \
+ if (HG_LOG_OUTLET(name).level >= HG_LOG_LEVEL_MIN_DEBUG && HG_LOG_OUTLET(name).debug_log) \
+ hg_dlog_addlog(HG_LOG_OUTLET(name).debug_log, __FILE__, __LINE__, __func__, NULL, NULL); \
+ if (HG_LOG_OUTLET(name).level == HG_LOG_LEVEL_DEBUG) { \
+ hg_log_write(&HG_LOG_OUTLET(name), HG_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __func__, \
+ __VA_ARGS__); \
+ debug_func; \
+ } \
+ } while (0)
+
+/**
+ * Additional macros for debug log support.
+ */
+
+/* HG_LOG_DEBUG_DLOG: global variable name of debug log. */
+#define HG_LOG_DEBUG_DLOG(name) HG_UTIL_CAT(name, _dlog_g)
+
+/* HG_LOG_DEBUG_LE: global variable name of debug log entries. */
+#define HG_LOG_DEBUG_LE(name) HG_UTIL_CAT(name, _dlog_entries_g)
+
+/* HG_LOG_DEBUG_DECL_DLOG: declare new debug log. */
+#define HG_LOG_DEBUG_DECL_DLOG(name) struct hg_dlog HG_LOG_DEBUG_DLOG(name)
+
+/* HG_LOG_DEBUG_DECL_LE: declare array of debug log entries. */
+#define HG_LOG_DEBUG_DECL_LE(name, size) struct hg_dlog_entry HG_LOG_DEBUG_LE(name)[size]
+
+/* HG_LOG_DLOG_INITIALIZER: initializer for a debug log */
+#define HG_LOG_DLOG_INITIALIZER(name, size) \
+ HG_DLOG_INITIALIZER(HG_UTIL_STRINGIFY(name), HG_LOG_DEBUG_LE(name), size, 1)
+
+/* HG_LOG_OUTLET_SUBSYS_DLOG_INITIALIZER: initializer for a sub-system with
+ * debug log. */
+#define HG_LOG_OUTLET_SUBSYS_DLOG_INITIALIZER(name, parent_name) \
+ HG_LOG_OUTLET_INITIALIZER(name, HG_LOG_PASS, &HG_LOG_OUTLET(parent_name), &HG_LOG_DEBUG_DLOG(name))
+
+/* HG_LOG_SUBSYS_DLOG_DECL_REGISTER: declare and register a log outlet with
+ * debug log. */
+#define HG_LOG_SUBSYS_DLOG_DECL_REGISTER(name, parent_name) \
+ struct hg_log_outlet HG_LOG_OUTLET(name) = HG_LOG_OUTLET_SUBSYS_DLOG_INITIALIZER(name, parent_name); \
+ HG_LOG_SUBSYS_REGISTER(name)
+
+/* HG_LOG_ADD_COUNTER32: add 32-bit debug log counter */
+#define HG_LOG_ADD_COUNTER32(name, counter_ptr, counter_name, counter_desc) \
+ hg_dlog_mkcount32(HG_LOG_OUTLET(name).debug_log, counter_ptr, counter_name, counter_desc)
+
+/* HG_LOG_ADD_COUNTER64: add 64-bit debug log counter */
+#define HG_LOG_ADD_COUNTER64(name, counter_ptr, counter_name, counter_desc) \
+ hg_dlog_mkcount64(HG_LOG_OUTLET(name)->debug_log, counter_ptr, counter_name, counter_desc)
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#define X(a, b, c) a,
+/* Log levels */
+enum hg_log_level { HG_LOG_LEVELS };
+#undef X
+
+/* Log states */
+enum hg_log_state { HG_LOG_PASS, HG_LOG_OFF, HG_LOG_ON };
+
+/* Log outlet */
+struct hg_log_outlet {
+ const char * name; /* Name of outlet */
+ enum hg_log_state state; /* Init state of outlet */
+ enum hg_log_level level; /* Level of outlet */
+ struct hg_log_outlet *parent; /* Parent of outlet */
+ struct hg_dlog * debug_log; /* Debug log to use */
+ HG_QUEUE_ENTRY(hg_log_outlet) entry; /* List entry */
+};
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Set the global log level.
+ *
+ * \param log_level [IN] enum log level type
+ */
+HG_UTIL_PUBLIC void hg_log_set_level(enum hg_log_level log_level);
+
+/**
+ * Get the global log level.
+ *
+ * \return global log_level
+ */
+HG_UTIL_PUBLIC enum hg_log_level hg_log_get_level(void);
+
+/**
+ * Set the log subsystems from a string. Format is: subsys1,subsys2,...
+ * Subsys can also be forced to be disabled with "~", e.g., ~subsys1
+ *
+ * \param log_level [IN] null terminated string
+ */
+HG_UTIL_PUBLIC void hg_log_set_subsys(const char *log_subsys);
+
+/**
+ * Get the log subsystems as a string. Format is similar to hg_log_set_subsys().
+ * Buffer returned is static.
+ *
+ * \return string of enabled log subsystems
+ */
+HG_UTIL_PUBLIC const char *hg_log_get_subsys(void);
+
+/**
+ * Set a specific subsystem's log level.
+ */
+HG_UTIL_PUBLIC void hg_log_set_subsys_level(const char *subsys, enum hg_log_level log_level);
+
+/**
+ * Get the log level from a string.
+ *
+ * \param log_level [IN] null terminated string
+ *
+ * \return log type enum value
+ */
+HG_UTIL_PUBLIC enum hg_log_level hg_log_name_to_level(const char *log_level);
+
+/**
+ * Set the logging function.
+ *
+ * \param log_func [IN] pointer to function
+ */
+HG_UTIL_PUBLIC void hg_log_set_func(int (*log_func)(FILE *stream, const char *format, ...));
+
+/**
+ * Set the stream for error output.
+ *
+ * \param stream [IN/OUT] pointer to stream
+ */
+HG_UTIL_PUBLIC void hg_log_set_stream_error(FILE *stream);
+
+/**
+ * Get the stream for error output.
+ *
+ * \return pointer to stream
+ */
+HG_UTIL_PUBLIC FILE *hg_log_get_stream_error(void);
+
+/**
+ * Set the stream for warning output.
+ *
+ * \param stream [IN/OUT] pointer to stream
+ */
+HG_UTIL_PUBLIC void hg_log_set_stream_warning(FILE *stream);
+
+/**
+ * Get the stream for warning output.
+ *
+ * \return pointer to stream
+ */
+HG_UTIL_PUBLIC FILE *hg_log_get_stream_warning(void);
+
+/**
+ * Set the stream for debug output.
+ *
+ * \param stream [IN/OUT] pointer to stream
+ */
+HG_UTIL_PUBLIC void hg_log_set_stream_debug(FILE *stream);
+
+/**
+ * Get the stream for debug output.
+ *
+ * \return pointer to stream
+ */
+HG_UTIL_PUBLIC FILE *hg_log_get_stream_debug(void);
+
+/**
+ * Register log outlet.
+ *
+ * \param outlet [IN] log outlet
+ */
+HG_UTIL_PUBLIC void hg_log_outlet_register(struct hg_log_outlet *outlet);
+
+/**
+ * Write log.
+ *
+ * \param outlet [IN] log outlet
+ * \param log_level [IN] log level
+ * \param file [IN] file name
+ * \param line [IN] line number
+ * \param func [IN] function name
+ * \param format [IN] string format
+ */
+HG_UTIL_PUBLIC void hg_log_write(struct hg_log_outlet *outlet, enum hg_log_level log_level, const char *file,
+ unsigned int line, const char *func, const char *format, ...)
+ HG_UTIL_PRINTF_LIKE(6, 7);
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+/* Top error outlet */
+extern HG_UTIL_PUBLIC HG_LOG_OUTLET_DECL(hg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_LOG_H */
diff --git a/src/mercury/include/mercury_macros.h b/src/mercury/include/mercury_macros.h
new file mode 100644
index 0000000..5950679
--- /dev/null
+++ b/src/mercury/include/mercury_macros.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_MACROS_H
+#define MERCURY_MACROS_H
+
+#include "mercury.h"
+#include "mercury_bulk.h"
+#include "mercury_proc.h"
+#include "mercury_proc_bulk.h"
+
+#ifdef HG_HAS_BOOST
+#include <boost/preprocessor.hpp>
+
+/**
+ * The purpose of these macros is to facilitate generation of encoding/decoding
+ * procs as well as the registration of new routines to an existing HG class.
+ * HG_XXX macros are private macros / MERCURY_XXX are public macros.
+ * Macros defined in this file are:
+ * - MERCURY_REGISTER
+ * - MERCURY_GEN_PROC
+ * - MERCURY_GEN_STRUCT_PROC
+ */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Get type / name */
+#define HG_GEN_GET_TYPE(field) BOOST_PP_SEQ_HEAD(field)
+#define HG_GEN_GET_NAME(field) BOOST_PP_SEQ_CAT(BOOST_PP_SEQ_TAIL(field))
+
+/* Get struct field */
+#define HG_GEN_STRUCT_FIELD(r, data, param) HG_GEN_GET_TYPE(param) HG_GEN_GET_NAME(param);
+
+/* Generate structure */
+#define HG_GEN_STRUCT(struct_type_name, fields) \
+ typedef struct { \
+ BOOST_PP_SEQ_FOR_EACH(HG_GEN_STRUCT_FIELD, , fields) \
+ \
+ } struct_type_name;
+
+/* Generate proc for struct field */
+#define HG_GEN_PROC(r, struct_name, field) \
+ ret = BOOST_PP_CAT(hg_proc_, HG_GEN_GET_TYPE(field)(proc, &struct_name->HG_GEN_GET_NAME(field))); \
+ if (unlikely(ret != HG_SUCCESS)) { \
+ return ret; \
+ }
+
+/* Generate proc for struct */
+#define HG_GEN_STRUCT_PROC(struct_type_name, fields) \
+ static HG_INLINE hg_return_t BOOST_PP_CAT(hg_proc_, struct_type_name)(hg_proc_t proc, void *data) \
+ { \
+ hg_return_t ret = HG_SUCCESS; \
+ struct_type_name *struct_data = (struct_type_name *)data; \
+ \
+ BOOST_PP_SEQ_FOR_EACH(HG_GEN_PROC, struct_data, fields) \
+ \
+ return ret; \
+ }
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Register func_name */
+#define MERCURY_REGISTER(hg_class, func_name, in_struct_type_name, out_struct_type_name, rpc_cb) \
+ HG_Register_name(hg_class, func_name, BOOST_PP_CAT(hg_proc_, in_struct_type_name), \
+ BOOST_PP_CAT(hg_proc_, out_struct_type_name), rpc_cb)
+
+/* Generate struct and corresponding struct proc */
+#define MERCURY_GEN_PROC(struct_type_name, fields) \
+ HG_GEN_STRUCT(struct_type_name, fields) \
+ HG_GEN_STRUCT_PROC(struct_type_name, fields)
+
+/* In the case of user defined structures / MERCURY_GEN_STRUCT_PROC can be
+ * used to generate the corresponding proc routine.
+ * E.g., if user defined struct:
+ * typedef struct {
+ * uint64_t cookie;
+ * } bla_handle_t;
+ * MERCURY_GEN_STRUCT_PROC( struct_type_name, field sequence ):
+ * MERCURY_GEN_STRUCT_PROC( bla_handle_t, ((uint64_t)(cookie)) )
+ */
+#define MERCURY_GEN_STRUCT_PROC(struct_type_name, fields) HG_GEN_STRUCT_PROC(struct_type_name, fields)
+
+#else /* HG_HAS_BOOST */
+
+/* Register func_name */
+#define MERCURY_REGISTER(hg_class, func_name, in_struct_type_name, out_struct_type_name, rpc_cb) \
+ HG_Register_name(hg_class, func_name, hg_proc_##in_struct_type_name, hg_proc_##out_struct_type_name, \
+ rpc_cb)
+
+#endif /* HG_HAS_BOOST */
+
+/* If no input args or output args, a void type can be
+ * passed to MERCURY_REGISTER
+ */
+#define hg_proc_void NULL
+
+#endif /* MERCURY_MACROS_H */
diff --git a/src/mercury/include/mercury_mem.h b/src/mercury/include/mercury_mem.h
new file mode 100644
index 0000000..3c15c01
--- /dev/null
+++ b/src/mercury/include/mercury_mem.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_MEM_H
+#define MERCURY_MEM_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+#define HG_MEM_CACHE_LINE_SIZE 64
+#define HG_MEM_PAGE_SIZE 4096
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get system default page size.
+ *
+ * \return page size on success or negative on failure
+ */
+HG_UTIL_PUBLIC long hg_mem_get_page_size(void);
+
+/**
+ * Allocate size bytes and return a pointer to the allocated memory.
+ * The memory address will be a multiple of alignment, which must be a power of
+ * two, and size should be a multiple of alignment.
+ *
+ * \param alignment [IN] alignment size
+ * \param size [IN] total requested size
+ *
+ * \return a pointer to the allocated memory, or NULL in case of failure
+ */
+HG_UTIL_PUBLIC void *hg_mem_aligned_alloc(size_t alignment, size_t size);
+
+/**
+ * Free memory allocated from hg_aligned_alloc().
+ *
+ * \param mem_ptr [IN] pointer to allocated memory
+ */
+HG_UTIL_PUBLIC void hg_mem_aligned_free(void *mem_ptr);
+
+/**
+ * Allocate a buffer with a `size`-bytes, `alignment`-aligned payload
+ * preceded by a `header_size` header, padding the allocation with up
+ * to `alignment - 1` bytes to ensure that the payload is properly aligned.
+ *
+ * If `alignment` is 0, do not try to align the payload. It's ok if
+ * `size` is 0, however, behavior is undefined if both `header_size`
+ * and `size` are 0.
+ *
+ * \param header_size [IN] size of header
+ * \param alignment [IN] alignment size
+ * \param size [IN] requested payload size
+ *
+ * \return a pointer to the payload or NULL on failure
+ */
+HG_UTIL_PUBLIC void *hg_mem_header_alloc(size_t header_size, size_t alignment, size_t size);
+
+/**
+ * Free the memory that was returned previously by a call to
+ * `hg_mem_header_alloc()`.
+ *
+ * \param header_size [IN] size of header
+ * \param alignment [IN] alignment size
+ * \param mem_ptr [IN] memory pointer
+ */
+HG_UTIL_PUBLIC void hg_mem_header_free(size_t header_size, size_t alignment, void *mem_ptr);
+
+/**
+ * Create/open a shared-memory mapped file of size \size with name \name.
+ *
+ * \param name [IN] name of mapped file
+ * \param size [IN] total requested size
+ * \param create [IN] create file if not existing
+ *
+ * \return a pointer to the mapped memory region, or NULL in case of failure
+ */
+HG_UTIL_PUBLIC void *hg_mem_shm_map(const char *name, size_t size, hg_util_bool_t create);
+
+/**
+ * Unmap a previously mapped region and close the file.
+ *
+ * \param name [IN] name of mapped file
+ * \param mem_ptr [IN] pointer to mapped memory region
+ * \param size [IN] size range of the mapped region
+ *
+ * \return non-negative on success, or negative in case of failure
+ */
+HG_UTIL_PUBLIC int hg_mem_shm_unmap(const char *name, void *mem_ptr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_MEM_H */
diff --git a/src/mercury/include/mercury_mem_pool.h b/src/mercury/include/mercury_mem_pool.h
new file mode 100644
index 0000000..d2acfdd
--- /dev/null
+++ b/src/mercury/include/mercury_mem_pool.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_MEM_POOL_H
+#define MERCURY_MEM_POOL_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/**
+ * Register memory block.
+ *
+ * \param buf [IN] pointer to buffer
+ * \param size [IN] buffer size
+ * \param handle [OUT] handle
+ * \param arg [IN/OUT] optional arguments
+ *
+ * \return HG_UTIL_SUCCESS if successful / error code otherwise
+ */
+typedef int (*hg_mem_pool_register_func_t)(const void *buf, size_t size, void **handle, void *arg);
+
+/**
+ * Deregister memory block.
+ *
+ * \param handle [IN/OUT] handle
+ * \param arg [IN/OUT] optional arguments
+ *
+ * \return HG_UTIL_SUCCESS if successful / error code otherwise
+ */
+typedef int (*hg_mem_pool_deregister_func_t)(void *handle, void *arg);
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a memory pool with \block_count of size \chunk_count x \chunk_size
+ * bytes. Optionally register and deregister memory for each block using
+ * \register_func and \deregister_func respectively.
+ *
+ * \param chunk_size [IN] size of chunks
+ * \param chunk_count [IN] number of chunks
+ * \param block_count [IN] number of blocks
+ * \param register_func [IN] pointer to register function
+ * \param deregister_func [IN] pointer to deregister function
+ * \param arg [IN/OUT] optional arguments passed to register functions
+ *
+ * \return HG_UTIL_SUCCESS if successful / error code otherwise
+ */
+HG_UTIL_PUBLIC struct hg_mem_pool *hg_mem_pool_create(size_t chunk_size, size_t chunk_count,
+ size_t block_count,
+ hg_mem_pool_register_func_t register_func,
+ hg_mem_pool_deregister_func_t deregister_func,
+ void * arg);
+
+/**
+ * Destroy a memory pool.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ *
+ */
+HG_UTIL_PUBLIC void hg_mem_pool_destroy(struct hg_mem_pool *hg_mem_pool);
+
+/**
+ * Allocate \size bytes and optionally return a memory handle
+ * \mr_handle if registration functions were provided.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ * \param size [IN] requested size
+ * \param mr_handle [OUT] pointer to memory handle
+ *
+ * \return pointer to memory block
+ */
+HG_UTIL_PUBLIC void *hg_mem_pool_alloc(struct hg_mem_pool *hg_mem_pool, size_t size, void **mr_handle);
+
+/**
+ * Release memory at address \mem_ptr.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ * \param mem_ptr [IN] pointer to memory
+ * \param mr_handle [INT] pointer to memory handle
+ *
+ */
+HG_UTIL_PUBLIC void hg_mem_pool_free(struct hg_mem_pool *hg_mem_pool, void *mem_ptr, void *mr_handle);
+
+/**
+ * Retrieve chunk offset relative to the address used for registering
+ * the memory block it belongs to.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ * \param mem_ptr [IN] pointer to memory
+ * \param mr_handle [INT] pointer to memory handle
+ *
+ * \return offset within registered block.
+ */
+HG_UTIL_PUBLIC size_t hg_mem_pool_chunk_offset(struct hg_mem_pool *hg_mem_pool, void *mem_ptr,
+ void *mr_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_MEM_POOL_H */
diff --git a/src/mercury/include/mercury_poll.h b/src/mercury/include/mercury_poll.h
new file mode 100644
index 0000000..f4072a5
--- /dev/null
+++ b/src/mercury/include/mercury_poll.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_POLL_H
+#define MERCURY_POLL_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_poll_set hg_poll_set_t;
+
+typedef union hg_poll_data {
+ void * ptr;
+ int fd;
+ hg_util_uint32_t u32;
+ hg_util_uint64_t u64;
+} hg_poll_data_t;
+
+struct hg_poll_event {
+ hg_util_uint32_t events; /* Poll events */
+ hg_poll_data_t data; /* User data variable */
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/**
+ * Polling events.
+ */
+#define HG_POLLIN (1 << 0) /* There is data to read. */
+#define HG_POLLOUT (1 << 1) /* Writing now will not block. */
+#define HG_POLLERR (1 << 2) /* Error condition. */
+#define HG_POLLHUP (1 << 3) /* Hung up. */
+#define HG_POLLINTR (1 << 4) /* Interrupted. */
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a new poll set.
+ *
+ * \return Pointer to poll set or NULL in case of failure
+ */
+HG_UTIL_PUBLIC hg_poll_set_t *hg_poll_create(void);
+
+/**
+ * Destroy a poll set.
+ *
+ * \param poll_set [IN/OUT] pointer to poll set
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_destroy(hg_poll_set_t *poll_set);
+
+/**
+ * Get a file descriptor from an existing poll set.
+ *
+ * \param poll_set [IN] pointer to poll set
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_get_fd(hg_poll_set_t *poll_set);
+
+/**
+ * Add file descriptor to poll set.
+ *
+ * \param poll_set [IN] pointer to poll set
+ * \param fd [IN] file descriptor
+ * \param event [IN] pointer to event struct
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_add(hg_poll_set_t *poll_set, int fd, struct hg_poll_event *event);
+
+/**
+ * Remove file descriptor from poll set.
+ *
+ * \param poll_set [IN] pointer to poll set
+ * \param fd [IN] file descriptor
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_remove(hg_poll_set_t *poll_set, int fd);
+
+/**
+ * Wait on a poll set for timeout ms, and return at most max_events.
+ *
+ * \param poll_set [IN] pointer to poll set
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param max_events [IN] max number of events
+ * \param events [IN/OUT] array of events to be returned
+ * \param actual_events [OUT] actual number of events returned
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_wait(hg_poll_set_t *poll_set, unsigned int timeout, unsigned int max_events,
+ struct hg_poll_event events[], unsigned int *actual_events);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_POLL_H */
diff --git a/src/mercury/include/mercury_proc.h b/src/mercury/include/mercury_proc.h
new file mode 100644
index 0000000..f142634
--- /dev/null
+++ b/src/mercury/include/mercury_proc.h
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_PROC_H
+#define MERCURY_PROC_H
+
+#include "mercury_types.h"
+
+#include <string.h>
+#ifdef HG_HAS_XDR
+#include <limits.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#ifdef __APPLE__
+#define xdr_int8_t xdr_char
+#define xdr_uint8_t xdr_u_char
+#define xdr_uint16_t xdr_u_int16_t
+#define xdr_uint32_t xdr_u_int32_t
+#define xdr_uint64_t xdr_u_int64_t
+#endif
+#define xdr_hg_int8_t xdr_int8_t
+#define xdr_hg_uint8_t xdr_uint8_t
+#define xdr_hg_int16_t xdr_int16_t
+#define xdr_hg_uint16_t xdr_uint16_t
+#define xdr_hg_int32_t xdr_int32_t
+#define xdr_hg_uint32_t xdr_uint32_t
+#define xdr_hg_int64_t xdr_int64_t
+#define xdr_hg_uint64_t xdr_uint64_t
+#endif
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/**
+ * Hash methods available for proc.
+ */
+typedef enum { HG_CRC16, HG_CRC32, HG_CRC64, HG_NOHASH } hg_proc_hash_t;
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Encode/decode version number into uint32 */
+#define HG_GET_MAJOR(value) ((value >> 24) & 0xFF)
+#define HG_GET_MINOR(value) ((value >> 16) & 0xFF)
+#define HG_GET_PATCH(value) (value & 0xFFFF)
+#define HG_VERSION ((HG_VERSION_MAJOR << 24) | (HG_VERSION_MINOR << 16) | HG_VERSION_PATCH)
+
+/**
+ * Operation flags.
+ */
+#define HG_PROC_SM (1 << 0)
+#define HG_PROC_BULK_EAGER (1 << 1)
+
+/* Branch predictor hints */
+#ifndef _WIN32
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+/* Check whether size exceeds current proc size left */
+#ifdef HG_HAS_XDR
+#define HG_PROC_CHECK_SIZE(proc, size, label, ret) \
+ do { \
+ if (unlikely(((struct hg_proc *)proc)->current_buf->size_left < size)) { \
+ ret = HG_OVERFLOW; \
+ goto label; \
+ } \
+ } while (0)
+#else
+#define HG_PROC_CHECK_SIZE(proc, size, label, ret) \
+ do { \
+ if (unlikely(((struct hg_proc *)proc)->current_buf->size_left < size)) { \
+ ret = hg_proc_set_size(proc, hg_proc_get_size(proc) + size); \
+ if (ret != HG_SUCCESS) \
+ goto label; \
+ } \
+ } while (0)
+#endif
+
+/* Encode type */
+#define HG_PROC_TYPE_ENCODE(proc, data, size) \
+ memcpy(((struct hg_proc *)proc)->current_buf->buf_ptr, data, size)
+
+/* Decode type */
+#define HG_PROC_TYPE_DECODE(proc, data, size) \
+ memcpy(data, ((struct hg_proc *)proc)->current_buf->buf_ptr, size)
+
+/* Update proc pointers */
+#define HG_PROC_UPDATE(proc, size) \
+ do { \
+ ((struct hg_proc *)proc)->current_buf->buf_ptr = \
+ (char *)((struct hg_proc *)proc)->current_buf->buf_ptr + size; \
+ ((struct hg_proc *)proc)->current_buf->size_left -= size; \
+ } while (0)
+
+/* Update checksum */
+#ifdef HG_HAS_CHECKSUMS
+#define HG_PROC_CHECKSUM_UPDATE(proc, data, size) hg_proc_checksum_update(proc, data, size)
+#else
+#define HG_PROC_CHECKSUM_UPDATE(proc, data, size)
+#endif
+
+/* Base proc function */
+#ifdef HG_HAS_XDR
+#define HG_PROC_TYPE(proc, type, data, label, ret) \
+ do { \
+ HG_PROC_CHECK_SIZE(proc, sizeof(type), label, ret); \
+ \
+ if (xdr_##type(hg_proc_get_xdr_ptr(proc), data) == 0) { \
+ ret = HG_PROTOCOL_ERROR; \
+ goto label; \
+ } \
+ \
+ HG_PROC_UPDATE(proc, sizeof(type)); \
+ HG_PROC_CHECKSUM_UPDATE(proc, data, sizeof(type)); \
+ } while (0)
+#else
+#define HG_PROC_TYPE(proc, type, data, label, ret) \
+ do { \
+ /* Do nothing in HG_FREE for basic types */ \
+ if (hg_proc_get_op(proc) == HG_FREE) \
+ goto label; \
+ \
+ /* If not enough space allocate extra space if encoding or just */ \
+ /* get extra buffer if decoding */ \
+ HG_PROC_CHECK_SIZE(proc, sizeof(type), label, ret); \
+ \
+ /* Encode, decode type */ \
+ if (hg_proc_get_op(proc) == HG_ENCODE) \
+ HG_PROC_TYPE_ENCODE(proc, data, sizeof(type)); \
+ else \
+ HG_PROC_TYPE_DECODE(proc, data, sizeof(type)); \
+ \
+ /* Update proc pointers etc */ \
+ HG_PROC_UPDATE(proc, sizeof(type)); \
+ HG_PROC_CHECKSUM_UPDATE(proc, data, sizeof(type)); \
+ } while (0)
+#endif
+
+/* Base proc function */
+#ifdef HG_HAS_XDR
+#define HG_PROC_BYTES(proc, data, size, label, ret) \
+ do { \
+ HG_PROC_CHECK_SIZE(proc, size, label, ret); \
+ \
+ if (xdr_bytes(hg_proc_get_xdr_ptr(proc), (char **)&data, (u_int *)&size, UINT_MAX) == 0) { \
+ ret = HG_PROTOCOL_ERROR; \
+ goto label; \
+ } \
+ \
+ HG_PROC_UPDATE(proc, size); \
+ HG_PROC_CHECKSUM_UPDATE(proc, data, size); \
+ } while (0)
+#else
+#define HG_PROC_BYTES(proc, data, size, label, ret) \
+ do { \
+ /* Do nothing in HG_FREE for basic types */ \
+ if (hg_proc_get_op(proc) == HG_FREE) \
+ goto label; \
+ \
+ /* If not enough space allocate extra space if encoding or just */ \
+ /* get extra buffer if decoding */ \
+ HG_PROC_CHECK_SIZE(proc, size, label, ret); \
+ \
+ /* Encode, decode type */ \
+ if (hg_proc_get_op(proc) == HG_ENCODE) \
+ HG_PROC_TYPE_ENCODE(proc, data, size); \
+ else \
+ HG_PROC_TYPE_DECODE(proc, data, size); \
+ \
+ /* Update proc pointers etc */ \
+ HG_PROC_UPDATE(proc, size); \
+ HG_PROC_CHECKSUM_UPDATE(proc, data, size); \
+ } while (0)
+#endif
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a new encoding/decoding processor.
+ *
+ * \param hg_class [IN] HG class
+ * \param hash [IN] hash method used for computing checksum
+ * (if NULL, checksum is not computed)
+ * hash method: HG_CRC16, HG_CRC64, HG_NOHASH
+ * \param proc [OUT] pointer to abstract processor object
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_create(hg_class_t *hg_class, hg_proc_hash_t hash, hg_proc_t *proc);
+
+/**
+ * Create a new encoding/decoding processor.
+ *
+ * \param hg_class [IN] HG class
+ * \param buf [IN] pointer to buffer that will be used for
+ * serialization/deserialization
+ * \param buf_size [IN] buffer size
+ * \param op [IN] operation type: HG_ENCODE / HG_DECODE /
+ * HG_FREE \param hash [IN] hash method used for computing
+ * checksum (if NULL, checksum is not computed) hash method: HG_CRC16,
+ * HG_CRC64, HG_NOHASH \param proc [OUT] pointer to abstract
+ * processor object
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_create_set(hg_class_t *hg_class, void *buf, hg_size_t buf_size, hg_proc_op_t op,
+ hg_proc_hash_t hash, hg_proc_t *proc);
+
+/**
+ * Free the processor.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_free(hg_proc_t proc);
+
+/**
+ * Reset the processor.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param buf [IN] pointer to buffer that will be used for
+ * serialization/deserialization
+ * \param buf_size [IN] buffer size
+ * \param op [IN] operation type: HG_ENCODE / HG_DECODE /
+ * HG_FREE
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_reset(hg_proc_t proc, void *buf, hg_size_t buf_size, hg_proc_op_t op);
+
+/**
+ * Get the HG class associated to the processor.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return HG class
+ */
+static HG_INLINE hg_class_t *hg_proc_get_class(hg_proc_t proc);
+
+/**
+ * Get the operation type associated to the processor.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Operation type
+ */
+static HG_INLINE hg_proc_op_t hg_proc_get_op(hg_proc_t proc);
+
+/**
+ * Set flags to be associated with the processor.
+ * Flags are reset after a call to hg_proc_reset().
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Non-negative flag value
+ */
+static HG_INLINE void hg_proc_set_flags(hg_proc_t proc, hg_uint8_t flags);
+
+/**
+ * Get the flags associated to the processor.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Non-negative flag value
+ */
+static HG_INLINE hg_uint8_t hg_proc_get_flags(hg_proc_t proc);
+
+/**
+ * Get buffer size available for processing.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Non-negative size value
+ */
+static HG_INLINE hg_size_t hg_proc_get_size(hg_proc_t proc);
+
+/**
+ * Get amount of buffer space that has actually been consumed
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Non-negative size value
+ */
+static HG_INLINE hg_size_t hg_proc_get_size_used(hg_proc_t proc);
+
+/**
+ * Request a new buffer size. This will modify the size of the buffer
+ * attached to the processor or create an extra processing buffer.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param buf_size [IN] buffer size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_set_size(hg_proc_t proc, hg_size_t buf_size);
+
+/**
+ * Get size left for processing.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Non-negative size value
+ */
+static HG_INLINE hg_size_t hg_proc_get_size_left(hg_proc_t proc);
+
+/**
+ * Get pointer to current buffer. Will reserve data_size for manual
+ * encoding.
+ *
+ * \param proc [IN] abstract processor object
+ * \param data_size [IN] data size
+ *
+ * \return Buffer pointer
+ */
+HG_PUBLIC void *hg_proc_save_ptr(hg_proc_t proc, hg_size_t data_size);
+
+/**
+ * Restore pointer from current buffer.
+ *
+ * \param proc [IN] abstract processor object
+ * \param data [IN] pointer to data
+ * \param data_size [IN] data size
+ *
+ * \return Buffer pointer
+ */
+HG_PUBLIC hg_return_t hg_proc_restore_ptr(hg_proc_t proc, void *data, hg_size_t data_size);
+
+#ifdef HG_HAS_XDR
+/**
+ * Get pointer to current XDR stream (for manual encoding).
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return XDR stream pointer
+ */
+static HG_INLINE XDR *hg_proc_get_xdr_ptr(hg_proc_t proc);
+#endif
+
+/**
+ * Get eventual extra buffer used by processor.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Pointer to buffer or NULL if no extra buffer has been used
+ */
+static HG_INLINE void *hg_proc_get_extra_buf(hg_proc_t proc);
+
+/**
+ * Get eventual size of the extra buffer used by processor.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return Size of buffer or 0 if no extra buffer has been used
+ */
+static HG_INLINE hg_size_t hg_proc_get_extra_size(hg_proc_t proc);
+
+/**
+ * Set extra buffer to mine (if other calls mine, buffer is no longer freed
+ * after hg_proc_free())
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_set_extra_buf_is_mine(hg_proc_t proc, hg_bool_t mine);
+
+/**
+ * Flush the proc after data has been encoded or decoded and finalize
+ * internal checksum if checksum of data processed was initially requested.
+ *
+ * \param proc [IN] abstract processor object
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_flush(hg_proc_t proc);
+
+#ifdef HG_HAS_CHECKSUMS
+/**
+ * Retrieve internal proc checksum hash.
+ * \remark Must be used after hg_proc_flush() has been called so that the
+ * internally computed checksum is in a finalized state.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param hash [IN/OUT] pointer to hash
+ * \param hash_size [IN] hash size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_checksum_get(hg_proc_t proc, void *hash, hg_size_t hash_size);
+
+/**
+ * Verify that the hash passed matches the internal proc checksum.
+ * \remark Must be used after hg_proc_flush() has been called so that the
+ * internally computed checksum is in a finalized state.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param hash [IN] pointer to hash
+ * \param hash_size [IN] hash size
+ *
+ * \return HG_SUCCESS if matches or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_checksum_verify(hg_proc_t proc, const void *hash, hg_size_t hash_size);
+#endif
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_int8_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_uint8_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_int16_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_uint16_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_int32_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_uint32_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_int64_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_uint64_t(hg_proc_t proc, void *data);
+
+/* Note: float types are not supported but can be built on top of the existing
+ * proc routines; encoding floats using XDR could modify checksum */
+
+/**
+ * Generic processing routine for encoding stream of bytes.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ * \param data_size [IN] data size
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_bytes(hg_proc_t proc, void *data, hg_size_t data_size);
+
+/**
+ * For convenience map stdint types to hg types
+ */
+#define hg_proc_int8_t hg_proc_hg_int8_t
+#define hg_proc_uint8_t hg_proc_hg_uint8_t
+#define hg_proc_int16_t hg_proc_hg_int16_t
+#define hg_proc_uint16_t hg_proc_hg_uint16_t
+#define hg_proc_int32_t hg_proc_hg_int32_t
+#define hg_proc_uint32_t hg_proc_hg_uint32_t
+#define hg_proc_int64_t hg_proc_hg_int64_t
+#define hg_proc_uint64_t hg_proc_hg_uint64_t
+
+/* Map mercury common types */
+#define hg_proc_hg_bool_t hg_proc_hg_uint8_t
+#define hg_proc_hg_ptr_t hg_proc_hg_uint64_t
+#define hg_proc_hg_size_t hg_proc_hg_uint64_t
+#define hg_proc_hg_id_t hg_proc_hg_uint32_t
+
+/* Map hg_proc_raw/hg_proc_memcpy to hg_proc_bytes */
+#define hg_proc_memcpy hg_proc_raw
+#define hg_proc_raw hg_proc_bytes
+
+/* Update checksum */
+#ifdef HG_HAS_CHECKSUMS
+HG_PUBLIC void hg_proc_checksum_update(hg_proc_t proc, void *data, hg_size_t data_size);
+#endif
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/* HG proc buf */
+struct hg_proc_buf {
+ void * buf; /* Pointer to allocated buffer */
+ void * buf_ptr; /* Pointer to current position */
+ hg_size_t size; /* Total buffer size */
+ hg_size_t size_left; /* Available size for user */
+ hg_bool_t is_mine;
+#ifdef HG_HAS_XDR
+ XDR xdr;
+#endif
+};
+
+/* HG proc */
+struct hg_proc {
+ struct hg_proc_buf proc_buf;
+ struct hg_proc_buf extra_buf;
+ hg_class_t * hg_class; /* HG class */
+ struct hg_proc_buf *current_buf;
+#ifdef HG_HAS_CHECKSUMS
+ void * checksum; /* Checksum */
+ void * checksum_hash; /* Base checksum buf */
+ size_t checksum_size; /* Checksum size */
+#endif
+ hg_proc_op_t op;
+ hg_uint8_t flags;
+};
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_class_t *
+ hg_proc_get_class(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->hg_class;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_proc_op_t
+hg_proc_get_op(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->op;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void
+hg_proc_set_flags(hg_proc_t proc, hg_uint8_t flags)
+{
+ ((struct hg_proc *)proc)->flags = flags;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_uint8_t
+hg_proc_get_flags(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->flags;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+hg_proc_get_size(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->proc_buf.size + ((struct hg_proc *)proc)->extra_buf.size;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+hg_proc_get_size_used(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->current_buf->size - ((struct hg_proc *)proc)->current_buf->size_left;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+hg_proc_get_size_left(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->current_buf->size_left;
+}
+
+/*---------------------------------------------------------------------------*/
+#ifdef HG_HAS_XDR
+static HG_INLINE XDR *
+ hg_proc_get_xdr_ptr(hg_proc_t proc)
+{
+ return &((struct hg_proc *)proc)->current_buf->xdr;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE void *
+hg_proc_get_extra_buf(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->extra_buf.buf;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_size_t
+hg_proc_get_extra_size(hg_proc_t proc)
+{
+ return ((struct hg_proc *)proc)->extra_buf.size;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_int8_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_int8_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_uint8_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_uint8_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_int16_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_int16_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_uint16_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_uint16_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_int32_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_int32_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_uint32_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_uint32_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_int64_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_int64_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_uint64_t(hg_proc_t proc, void *data)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_TYPE(proc, hg_uint64_t, data, done, ret);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_bytes(hg_proc_t proc, void *data, hg_size_t data_size)
+{
+ hg_return_t ret = HG_SUCCESS;
+
+ HG_PROC_BYTES(proc, data, data_size, done, ret);
+
+done:
+ return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_PROC_H */
diff --git a/src/mercury/include/mercury_proc_bulk.h b/src/mercury/include/mercury_proc_bulk.h
new file mode 100644
index 0000000..f89face
--- /dev/null
+++ b/src/mercury/include/mercury_proc_bulk.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_PROC_BULK_H
+#define MERCURY_PROC_BULK_H
+
+#include "mercury_proc.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param handle [IN/OUT] pointer to bulk handle
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_hg_bulk_t(hg_proc_t proc, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_PROC_BULK_H */
diff --git a/src/mercury/include/mercury_proc_string.h b/src/mercury/include/mercury_proc_string.h
new file mode 100644
index 0000000..764eb20
--- /dev/null
+++ b/src/mercury/include/mercury_proc_string.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_PROC_STRING_H
+#define MERCURY_PROC_STRING_H
+
+#include "mercury_proc.h"
+#include "mercury_string_object.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef const char *hg_const_string_t;
+typedef char * hg_string_t;
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_const_string_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param data [IN/OUT] pointer to data
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+static HG_INLINE hg_return_t hg_proc_hg_string_t(hg_proc_t proc, void *data);
+
+/**
+ * Generic processing routine.
+ *
+ * \param proc [IN/OUT] abstract processor object
+ * \param string [IN/OUT] pointer to string
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_proc_hg_string_object_t(hg_proc_t proc, void *string);
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_const_string_t(hg_proc_t proc, void *data)
+{
+ hg_string_object_t string;
+ hg_const_string_t *strdata = (hg_const_string_t *)data;
+ hg_return_t ret = HG_SUCCESS;
+
+ switch (hg_proc_get_op(proc)) {
+ case HG_ENCODE:
+ hg_string_object_init_const_char(&string, *strdata, 0);
+ ret = hg_proc_hg_string_object_t(proc, &string);
+ if (ret != HG_SUCCESS)
+ goto done;
+ hg_string_object_free(&string);
+ break;
+ case HG_DECODE:
+ ret = hg_proc_hg_string_object_t(proc, &string);
+ if (ret != HG_SUCCESS)
+ goto done;
+ *strdata = hg_string_object_swap(&string, 0);
+ hg_string_object_free(&string);
+ break;
+ case HG_FREE:
+ hg_string_object_init_const_char(&string, *strdata, 1);
+ ret = hg_proc_hg_string_object_t(proc, &string);
+ if (ret != HG_SUCCESS)
+ goto done;
+ break;
+ default:
+ break;
+ }
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_INLINE hg_return_t
+hg_proc_hg_string_t(hg_proc_t proc, void *data)
+{
+ hg_string_object_t string;
+ hg_string_t * strdata = (hg_string_t *)data;
+ hg_return_t ret = HG_SUCCESS;
+
+ switch (hg_proc_get_op(proc)) {
+ case HG_ENCODE:
+ hg_string_object_init_char(&string, *strdata, 0);
+ ret = hg_proc_hg_string_object_t(proc, &string);
+ if (ret != HG_SUCCESS)
+ goto done;
+ hg_string_object_free(&string);
+ break;
+ case HG_DECODE:
+ ret = hg_proc_hg_string_object_t(proc, &string);
+ if (ret != HG_SUCCESS)
+ goto done;
+ *strdata = hg_string_object_swap(&string, 0);
+ hg_string_object_free(&string);
+ break;
+ case HG_FREE:
+ hg_string_object_init_char(&string, *strdata, 1);
+ ret = hg_proc_hg_string_object_t(proc, &string);
+ if (ret != HG_SUCCESS)
+ goto done;
+ break;
+ default:
+ break;
+ }
+
+done:
+ return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_PROC_STRING_H */
diff --git a/src/mercury/include/mercury_queue.h b/src/mercury/include/mercury_queue.h
new file mode 100644
index 0000000..116a209
--- /dev/null
+++ b/src/mercury/include/mercury_queue.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Code below is derived from sys/queue.h which follows the below notice:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef MERCURY_QUEUE_H
+#define MERCURY_QUEUE_H
+
+#define HG_QUEUE_HEAD_INITIALIZER(name) \
+ { \
+ NULL, &(name).head \
+ }
+
+#define HG_QUEUE_HEAD_INIT(struct_head_name, var_name) \
+ struct struct_head_name var_name = HG_QUEUE_HEAD_INITIALIZER(var_name)
+
+#define HG_QUEUE_HEAD_DECL(struct_head_name, struct_entry_name) \
+ struct struct_head_name { \
+ struct struct_entry_name * head; \
+ struct struct_entry_name **tail; \
+ }
+
+#define HG_QUEUE_HEAD(struct_entry_name) \
+ struct { \
+ struct struct_entry_name * head; \
+ struct struct_entry_name **tail; \
+ }
+
+#define HG_QUEUE_ENTRY(struct_entry_name) \
+ struct { \
+ struct struct_entry_name *next; \
+ }
+
+#define HG_QUEUE_INIT(head_ptr) \
+ do { \
+ (head_ptr)->head = NULL; \
+ (head_ptr)->tail = &(head_ptr)->head; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_QUEUE_IS_EMPTY(head_ptr) ((head_ptr)->head == NULL)
+
+#define HG_QUEUE_FIRST(head_ptr) ((head_ptr)->head)
+
+#define HG_QUEUE_NEXT(entry_ptr, entry_field_name) ((entry_ptr)->entry_field_name.next)
+
+#define HG_QUEUE_PUSH_TAIL(head_ptr, entry_ptr, entry_field_name) \
+ do { \
+ (entry_ptr)->entry_field_name.next = NULL; \
+ *(head_ptr)->tail = (entry_ptr); \
+ (head_ptr)->tail = &(entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+/* TODO would be nice to not have any condition */
+#define HG_QUEUE_POP_HEAD(head_ptr, entry_field_name) \
+ do { \
+ if ((head_ptr)->head && ((head_ptr)->head = (head_ptr)->head->entry_field_name.next) == NULL) \
+ (head_ptr)->tail = &(head_ptr)->head; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_QUEUE_FOREACH(var, head_ptr, entry_field_name) \
+ for ((var) = ((head_ptr)->head); (var); (var) = ((var)->entry_field_name.next))
+
+/**
+ * Avoid using those for performance reasons or use mercury_list.h instead
+ */
+
+#define HG_QUEUE_REMOVE(head_ptr, entry_ptr, type, entry_field_name) \
+ do { \
+ if ((head_ptr)->head == (entry_ptr)) { \
+ HG_QUEUE_POP_HEAD((head_ptr), entry_field_name); \
+ } \
+ else { \
+ struct type *curelm = (head_ptr)->head; \
+ while (curelm->entry_field_name.next != (entry_ptr)) \
+ curelm = curelm->entry_field_name.next; \
+ if ((curelm->entry_field_name.next = curelm->entry_field_name.next->entry_field_name.next) == \
+ NULL) \
+ (head_ptr)->tail = &(curelm)->entry_field_name.next; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+#endif /* MERCURY_QUEUE_H */
diff --git a/src/mercury/include/mercury_request.h b/src/mercury/include/mercury_request.h
new file mode 100644
index 0000000..4d7fdf8
--- /dev/null
+++ b/src/mercury/include/mercury_request.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_REQUEST_H
+#define MERCURY_REQUEST_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_atomic.h"
+
+/**
+ * Purpose: define a request emulation library on top of the callback model
+ * that uses progress/trigger functions. Note that this library can not be
+ * safely used within RPCs in most cases - calling hg_request_wait causes
+ * deadlock when the caller function was triggered by HG_Trigger
+ * (or HG_Bulk_trigger).
+ */
+
+typedef struct hg_request_class hg_request_class_t; /* Opaque request class */
+typedef struct hg_request hg_request_t; /* Opaque request object */
+
+struct hg_request {
+ hg_request_class_t *request_class;
+ void * data;
+ hg_atomic_int32_t completed;
+};
+
+/**
+ * Progress callback, arg can be used to pass extra parameters required by
+ * underlying API.
+ *
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return HG_UTIL_SUCCESS if any completion has occurred / error code otherwise
+ */
+typedef int (*hg_request_progress_func_t)(unsigned int timeout, void *arg);
+
+/**
+ * Trigger callback, arg can be used to pass extra parameters required by
+ * underlying API.
+ *
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param flag [OUT] 1 if callback has been triggered, 0 otherwise
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return HG_UTIL_SUCCESS or corresponding error code
+ */
+typedef int (*hg_request_trigger_func_t)(unsigned int timeout, unsigned int *flag, void *arg);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the request class with the specific progress/trigger functions
+ * that will be called on hg_request_wait().
+ * arg can be used to pass extra parameters required by underlying API.
+ *
+ * \param progress [IN] progress function
+ * \param trigger [IN] trigger function
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return Pointer to request class or NULL in case of failure
+ */
+HG_UTIL_PUBLIC hg_request_class_t *hg_request_init(hg_request_progress_func_t progress,
+ hg_request_trigger_func_t trigger, void *arg);
+
+/**
+ * Finalize the request class. User args that were passed through
+ * hg_request_init() can be retrieved through the \a arg parameter.
+ *
+ * \param request_class [IN] pointer to request class
+ * \param arg [IN/OUT] pointer to init args
+ */
+HG_UTIL_PUBLIC void hg_request_finalize(hg_request_class_t *request_class, void **arg);
+
+/**
+ * Create a new request from a specified request class. The progress function
+ * explicitly makes progress and may insert the completed operation into a
+ * completion queue. The operation gets triggered after a call to the trigger
+ * function.
+ *
+ * \param request_class [IN] pointer to request class
+ *
+ * \return Pointer to request or NULL in case of failure
+ */
+HG_UTIL_PUBLIC hg_request_t *hg_request_create(hg_request_class_t *request_class);
+
+/**
+ * Destroy the request, freeing the resources.
+ *
+ * \param request [IN/OUT] pointer to request
+ */
+HG_UTIL_PUBLIC void hg_request_destroy(hg_request_t *request);
+
+/**
+ * Reset an existing request so that it can be safely re-used.
+ *
+ * \param request [IN/OUT] pointer to request
+ */
+static HG_UTIL_INLINE void hg_request_reset(hg_request_t *request);
+
+/**
+ * Mark the request as completed. (most likely called by a callback triggered
+ * after a call to trigger)
+ *
+ * \param request [IN/OUT] pointer to request
+ */
+static HG_UTIL_INLINE void hg_request_complete(hg_request_t *request);
+
+/**
+ * Wait timeout ms for the specified request to complete.
+ *
+ * \param request [IN/OUT] pointer to request
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param flag [OUT] 1 if request has completed, 0 otherwise
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_request_wait(hg_request_t *request, unsigned int timeout, unsigned int *flag);
+
+/**
+ * Wait timeout ms for all the specified request to complete.
+ *
+ * \param count [IN] number of requests
+ * \param request [IN/OUT] arrays of requests
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param flag [OUT] 1 if all requests have completed, 0 otherwise
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_request_waitall(int count, hg_request_t *request[], unsigned int timeout,
+ unsigned int *flag);
+
+/**
+ * Attach user data to a specified request.
+ *
+ * \param request [IN/OUT] pointer to request
+ * \param data [IN] pointer to data
+ */
+static HG_UTIL_INLINE void hg_request_set_data(hg_request_t *request, void *data);
+
+/**
+ * Get user data from a specified request.
+ *
+ * \param request [IN/OUT] pointer to request
+ *
+ * \return Pointer to data or NULL if nothing was attached by user
+ */
+static HG_UTIL_INLINE void *hg_request_get_data(hg_request_t *request);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_request_reset(hg_request_t *request)
+{
+ hg_atomic_set32(&request->completed, HG_UTIL_FALSE);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_request_complete(hg_request_t *request)
+{
+ hg_atomic_set32(&request->completed, HG_UTIL_TRUE);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_request_waitall(int count, hg_request_t *request[], unsigned int timeout, unsigned int *flag)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ hg_request_wait(request[i], timeout, flag);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_request_set_data(hg_request_t *request, void *data)
+{
+ request->data = data;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_request_get_data(hg_request_t *request)
+{
+ return request->data;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_REQUEST_H */
diff --git a/src/mercury/include/mercury_string_object.h b/src/mercury/include/mercury_string_object.h
new file mode 100644
index 0000000..5a7492a
--- /dev/null
+++ b/src/mercury/include/mercury_string_object.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_STRING_OBJECT_H
+#define MERCURY_STRING_OBJECT_H
+
+#include "mercury_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_string_object {
+ char * data;
+ hg_bool_t is_const;
+ hg_bool_t is_owned;
+} hg_string_object_t;
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize a string object.
+ *
+ * \param string [OUT] pointer to string structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_string_object_init(hg_string_object_t *string);
+
+/**
+ * Initialize a string object from the string pointed to by s.
+ *
+ * \param string [OUT] pointer to string structure
+ * \param s [IN] pointer to string
+ * \param is_owned [IN] boolean
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_string_object_init_char(hg_string_object_t *string, char *s, hg_bool_t is_owned);
+
+/**
+ * Initialize a string object from the const string pointed to by s.
+ *
+ * \param string [OUT] pointer to string structure
+ * \param s [IN] pointer to string
+ * \param is_owned [IN] boolean
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_string_object_init_const_char(hg_string_object_t *string, const char *s,
+ hg_bool_t is_owned);
+
+/**
+ * Free a string object.
+ *
+ * \param string [IN/OUT] pointer to string structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_string_object_free(hg_string_object_t *string);
+
+/**
+ * Duplicate a string object.
+ *
+ * \param string [IN] pointer to string structure
+ * \param new_string [OUT] pointer to string structure
+ *
+ * \return HG_SUCCESS or corresponding HG error code
+ */
+HG_PUBLIC hg_return_t hg_string_object_dup(hg_string_object_t string, hg_string_object_t *new_string);
+
+/**
+ * Exchange the content of the string structure by the content of s.
+ *
+ * \param string [IN/OUT] pointer to string structure
+ *
+ * \return Pointer to string contained by string before the swap
+ */
+HG_PUBLIC char *hg_string_object_swap(hg_string_object_t *string, char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_STRING_OBJECT_H */
diff --git a/src/mercury/include/mercury_thread.h b/src/mercury/include/mercury_thread.h
new file mode 100644
index 0000000..3317c41
--- /dev/null
+++ b/src/mercury/include/mercury_thread.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_H
+#define MERCURY_THREAD_H
+
+#if !defined(_WIN32) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#include "mercury_util_config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+typedef HANDLE hg_thread_t;
+typedef LPTHREAD_START_ROUTINE hg_thread_func_t;
+typedef DWORD hg_thread_ret_t;
+#define HG_THREAD_RETURN_TYPE hg_thread_ret_t WINAPI
+typedef DWORD hg_thread_key_t;
+typedef DWORD_PTR hg_cpu_set_t;
+#else
+#include <pthread.h>
+typedef pthread_t hg_thread_t;
+typedef void *(*hg_thread_func_t)(void *);
+typedef void * hg_thread_ret_t;
+#define HG_THREAD_RETURN_TYPE hg_thread_ret_t
+typedef pthread_key_t hg_thread_key_t;
+#ifdef __APPLE__
+/* Size definition for CPU sets. */
+#define HG_CPU_SETSIZE 1024
+#define HG_NCPUBITS (8 * sizeof(hg_cpu_mask_t))
+/* Type for array elements in 'cpu_set_t'. */
+typedef hg_util_uint64_t hg_cpu_mask_t;
+typedef struct {
+ hg_cpu_mask_t bits[HG_CPU_SETSIZE / HG_NCPUBITS];
+} hg_cpu_set_t;
+#else
+typedef cpu_set_t hg_cpu_set_t;
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the thread.
+ *
+ * \param thread [IN/OUT] pointer to thread object
+ */
+HG_UTIL_PUBLIC void hg_thread_init(hg_thread_t *thread);
+
+/**
+ * Create a new thread for the given function.
+ *
+ * \param thread [IN/OUT] pointer to thread object
+ * \param f [IN] pointer to function
+ * \param data [IN] pointer to data than be passed to function f
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_create(hg_thread_t *thread, hg_thread_func_t f, void *data);
+
+/**
+ * Ends the calling thread.
+ *
+ * \param ret [IN] exit code for the thread
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC void hg_thread_exit(hg_thread_ret_t ret);
+
+/**
+ * Wait for thread completion.
+ *
+ * \param thread [IN] thread object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_join(hg_thread_t thread);
+
+/**
+ * Terminate the thread.
+ *
+ * \param thread [IN] thread object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_cancel(hg_thread_t thread);
+
+/**
+ * Yield the processor.
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_yield(void);
+
+/**
+ * Obtain handle of the calling thread.
+ *
+ * \return
+ */
+static HG_UTIL_INLINE hg_thread_t hg_thread_self(void);
+
+/**
+ * Compare thread IDs.
+ *
+ * \return Non-zero if equal, zero if not equal
+ */
+static HG_UTIL_INLINE int hg_thread_equal(hg_thread_t t1, hg_thread_t t2);
+
+/**
+ * Create a thread-specific data key visible to all threads in the process.
+ *
+ * \param key [OUT] pointer to thread key object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_key_create(hg_thread_key_t *key);
+
+/**
+ * Delete a thread-specific data key previously returned by
+ * hg_thread_key_create().
+ *
+ * \param key [IN] thread key object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_key_delete(hg_thread_key_t key);
+
+/**
+ * Get value from specified key.
+ *
+ * \param key [IN] thread key object
+ *
+ * \return Pointer to data associated to the key
+ */
+static HG_UTIL_INLINE void *hg_thread_getspecific(hg_thread_key_t key);
+
+/**
+ * Set value to specified key.
+ *
+ * \param key [IN] thread key object
+ * \param value [IN] pointer to data that will be associated
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_setspecific(hg_thread_key_t key, const void *value);
+
+/**
+ * Get affinity mask.
+ *
+ * \param thread [IN] thread object
+ * \param cpu_mask [IN/OUT] cpu mask
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_getaffinity(hg_thread_t thread, hg_cpu_set_t *cpu_mask);
+
+/**
+ * Set affinity mask.
+ *
+ * \param thread [IN] thread object
+ * \param cpu_mask [IN] cpu mask
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_setaffinity(hg_thread_t thread, const hg_cpu_set_t *cpu_mask);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_thread_t
+hg_thread_self(void)
+{
+#ifdef _WIN32
+ return GetCurrentThread();
+#else
+ return pthread_self();
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_equal(hg_thread_t t1, hg_thread_t t2)
+{
+#ifdef _WIN32
+ return GetThreadId(t1) == GetThreadId(t2);
+#else
+ return pthread_equal(t1, t2);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_thread_getspecific(hg_thread_key_t key)
+{
+#ifdef _WIN32
+ return TlsGetValue(key);
+#else
+ return pthread_getspecific(key);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_setspecific(hg_thread_key_t key, const void *value)
+{
+#ifdef _WIN32
+ if (!TlsSetValue(key, (LPVOID)value))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_setspecific(key, value))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_H */
diff --git a/src/mercury/include/mercury_thread_annotation.h b/src/mercury/include/mercury_thread_annotation.h
new file mode 100644
index 0000000..f8613a4
--- /dev/null
+++ b/src/mercury/include/mercury_thread_annotation.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_ANNOTATION_H
+#define MERCURY_THREAD_ANNOTATION_H
+
+/* Enable thread safety attributes only with clang.
+ * The attributes can be safely erased when compiling with other compilers. */
+#if defined(__clang__) && (__clang_major__ > 3)
+#define HG_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define HG_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+#define HG_LOCK_CAPABILITY(x) HG_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define HG_LOCK_ACQUIRE(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define HG_LOCK_ACQUIRE_SHARED(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define HG_LOCK_RELEASE(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define HG_LOCK_RELEASE_SHARED(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define HG_LOCK_TRY_ACQUIRE(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define HG_LOCK_TRY_ACQUIRE_SHARED(...) \
+ HG_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define HG_LOCK_NO_THREAD_SAFETY_ANALYSIS HG_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+#endif /* MERCURY_THREAD_ANNOTATION_H */
diff --git a/src/mercury/include/mercury_thread_condition.h b/src/mercury/include/mercury_thread_condition.h
new file mode 100644
index 0000000..c1a3d61
--- /dev/null
+++ b/src/mercury/include/mercury_thread_condition.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_CONDITION_H
+#define MERCURY_THREAD_CONDITION_H
+
+#include "mercury_thread_mutex.h"
+
+#ifdef _WIN32
+typedef CONDITION_VARIABLE hg_thread_cond_t;
+#else
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+#include <time.h>
+#elif defined(HG_UTIL_HAS_SYSTIME_H)
+#include <sys/time.h>
+#endif
+#include <stdlib.h>
+typedef pthread_cond_t hg_thread_cond_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the condition.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_cond_init(hg_thread_cond_t *cond);
+
+/**
+ * Destroy the condition.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_cond_destroy(hg_thread_cond_t *cond);
+
+/**
+ * Wake one thread waiting for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_signal(hg_thread_cond_t *cond);
+
+/**
+ * Wake all the threads waiting for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_broadcast(hg_thread_cond_t *cond);
+
+/**
+ * Wait for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex);
+
+/**
+ * Wait timeout ms for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ * \param mutex [IN/OUT] pointer to mutex object
+ * \param timeout [IN] timeout (in milliseconds)
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex,
+ unsigned int timeout);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_signal(hg_thread_cond_t *cond)
+{
+#ifdef _WIN32
+ WakeConditionVariable(cond);
+#else
+ if (pthread_cond_signal(cond))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_broadcast(hg_thread_cond_t *cond)
+{
+#ifdef _WIN32
+ WakeAllConditionVariable(cond);
+#else
+ if (pthread_cond_broadcast(cond))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ if (!SleepConditionVariableCS(cond, mutex, INFINITE))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_cond_wait(cond, mutex))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex, unsigned int timeout)
+{
+#ifdef _WIN32
+ if (!SleepConditionVariableCS(cond, mutex, timeout))
+ return HG_UTIL_FAIL;
+#else
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ struct timespec now;
+#else
+ struct timeval now;
+#endif
+ struct timespec abs_timeout;
+ ldiv_t ld;
+
+ /* Need to convert timeout (ms) to absolute time */
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+
+ /* Get sec / nsec */
+ ld = ldiv(now.tv_nsec + timeout * 1000000L, 1000000000L);
+ abs_timeout.tv_nsec = ld.rem;
+#elif defined(HG_UTIL_HAS_SYSTIME_H)
+ gettimeofday(&now, NULL);
+
+ /* Get sec / usec */
+ ld = ldiv(now.tv_usec + timeout * 1000L, 1000000L);
+ abs_timeout.tv_nsec = ld.rem * 1000L;
+#endif
+ abs_timeout.tv_sec = now.tv_sec + ld.quot;
+
+ if (pthread_cond_timedwait(cond, mutex, &abs_timeout))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_CONDITION_H */
diff --git a/src/mercury/include/mercury_thread_mutex.h b/src/mercury/include/mercury_thread_mutex.h
new file mode 100644
index 0000000..b400952
--- /dev/null
+++ b/src/mercury/include/mercury_thread_mutex.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_MUTEX_H
+#define MERCURY_THREAD_MUTEX_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#define HG_THREAD_MUTEX_INITIALIZER NULL
+typedef CRITICAL_SECTION hg_thread_mutex_t;
+#else
+#include <pthread.h>
+#define HG_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+typedef pthread_mutex_t HG_LOCK_CAPABILITY("mutex") hg_thread_mutex_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_mutex_init(hg_thread_mutex_t *mutex);
+
+/**
+ * Initialize the mutex, asking for "fast" mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_mutex_init_fast(hg_thread_mutex_t *mutex);
+
+/**
+ * Destroy the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_mutex_destroy(hg_thread_mutex_t *mutex);
+
+/**
+ * Lock the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ */
+static HG_UTIL_INLINE void hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_ACQUIRE(*mutex);
+
+/**
+ * Try locking the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex)
+ HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *mutex);
+
+/**
+ * Unlock the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ */
+static HG_UTIL_INLINE void hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_RELEASE(*mutex);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ EnterCriticalSection(mutex);
+#else
+ (void)pthread_mutex_lock(mutex);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ if (!TryEnterCriticalSection(mutex))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_mutex_trylock(mutex))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ LeaveCriticalSection(mutex);
+#else
+ (void)pthread_mutex_unlock(mutex);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_MUTEX_H */
diff --git a/src/mercury/include/mercury_thread_pool.h b/src/mercury/include/mercury_thread_pool.h
new file mode 100644
index 0000000..db973d1
--- /dev/null
+++ b/src/mercury/include/mercury_thread_pool.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_POOL_H
+#define MERCURY_THREAD_POOL_H
+
+#include "mercury_queue.h"
+#include "mercury_thread.h"
+#include "mercury_thread_condition.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_thread_pool hg_thread_pool_t;
+
+struct hg_thread_pool {
+ unsigned int sleeping_worker_count;
+ HG_QUEUE_HEAD(hg_thread_work) queue;
+ int shutdown;
+ hg_thread_mutex_t mutex;
+ hg_thread_cond_t cond;
+};
+
+struct hg_thread_work {
+ hg_thread_func_t func;
+ void * args;
+ HG_QUEUE_ENTRY(hg_thread_work) entry; /* Internal */
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the thread pool.
+ *
+ * \param thread_count [IN] number of threads that will be created at
+ * initialization
+ * \param pool [OUT] pointer to pool object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_pool_init(unsigned int thread_count, hg_thread_pool_t **pool);
+
+/**
+ * Destroy the thread pool.
+ *
+ * \param pool [IN/OUT] pointer to pool object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_pool_destroy(hg_thread_pool_t *pool);
+
+/**
+ * Post work to the pool. Note that the operation may be queued depending on
+ * the number of threads and number of tasks already running.
+ *
+ * \param pool [IN/OUT] pointer to pool object
+ * \param work [IN] pointer to work struct
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+ if (!pool || !work)
+ return HG_UTIL_FAIL;
+
+ if (!work->func)
+ return HG_UTIL_FAIL;
+
+ hg_thread_mutex_lock(&pool->mutex);
+
+ /* Are we shutting down ? */
+ if (pool->shutdown) {
+ ret = HG_UTIL_FAIL;
+ goto unlock;
+ }
+
+ /* Add task to task queue */
+ HG_QUEUE_PUSH_TAIL(&pool->queue, work, entry);
+
+ /* Wake up sleeping worker */
+ if (pool->sleeping_worker_count && (hg_thread_cond_signal(&pool->cond) != HG_UTIL_SUCCESS))
+ ret = HG_UTIL_FAIL;
+
+unlock:
+ hg_thread_mutex_unlock(&pool->mutex);
+
+ return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_POOL_H */
diff --git a/src/mercury/include/mercury_thread_rwlock.h b/src/mercury/include/mercury_thread_rwlock.h
new file mode 100644
index 0000000..f03d2aa
--- /dev/null
+++ b/src/mercury/include/mercury_thread_rwlock.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Copyright (C) 2017 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted for any purpose (including commercial purposes)
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the
+ * documentation and/or materials provided with the distribution.
+ *
+ * 3. In addition, redistributions of modified forms of the source or binary
+ * code must carry prominent notices stating that the original code was
+ * changed and the date of the change.
+ *
+ * 4. All publications or advertising materials mentioning features or use of
+ * this software are asked, but not required, to acknowledge that it was
+ * developed by Intel Corporation and credit the contributors.
+ *
+ * 5. Neither the name of Intel Corporation, nor the name of any Contributor
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MERCURY_THREAD_RWLOCK_H
+#define MERCURY_THREAD_RWLOCK_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#ifdef _WIN32
+#include <windows.h>
+typedef PSRWLOCK hg_thread_rwlock_t;
+#else
+#include <pthread.h>
+typedef pthread_rwlock_t HG_LOCK_CAPABILITY("rwlock") hg_thread_rwlock_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_rwlock_init(hg_thread_rwlock_t *rwlock);
+
+/**
+ * Destroy the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_rwlock_destroy(hg_thread_rwlock_t *rwlock);
+
+/**
+ * Take a read lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_rdlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_ACQUIRE_SHARED(*rwlock);
+
+/**
+ * Try to take a read lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_rwlock_try_rdlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_TRY_ACQUIRE_SHARED(HG_UTIL_SUCCESS, *rwlock);
+
+/**
+ * Release the read lock of the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_release_rdlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_RELEASE_SHARED(*rwlock);
+
+/**
+ * Take a write lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_ACQUIRE(*rwlock);
+
+/**
+ * Try to take a write lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_rwlock_try_wrlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *rwlock);
+
+/**
+ * Release the write lock of the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_release_wrlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_RELEASE(*rwlock);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_rdlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ AcquireSRWLockShared(rwlock);
+#else
+ (void)pthread_rwlock_rdlock(rwlock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_rwlock_try_rdlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ if (TryAcquireSRWLockShared(rwlock) == 0)
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_rwlock_tryrdlock(rwlock))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_release_rdlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ ReleaseSRWLockShared(rwlock);
+#else
+ (void)pthread_rwlock_unlock(rwlock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ ReleaseSRWLockExclusive(rwlock);
+#else
+ (void)pthread_rwlock_wrlock(rwlock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_rwlock_try_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ if (TryAcquireSRWLockExclusive(rwlock) == 0)
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_rwlock_trywrlock(rwlock))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_release_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ ReleaseSRWLockExclusive(rwlock);
+#else
+ (void)pthread_rwlock_unlock(rwlock);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_RWLOCK_H */
diff --git a/src/mercury/include/mercury_thread_spin.h b/src/mercury/include/mercury_thread_spin.h
new file mode 100644
index 0000000..36ce5f8
--- /dev/null
+++ b/src/mercury/include/mercury_thread_spin.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_SPIN_H
+#define MERCURY_THREAD_SPIN_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+typedef volatile LONG hg_thread_spin_t;
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+#include <pthread.h>
+typedef pthread_spinlock_t HG_LOCK_CAPABILITY("spin") hg_thread_spin_t;
+#else
+/* Default to hg_thread_mutex_t if pthread_spinlock_t is not supported */
+#include "mercury_thread_mutex.h"
+typedef hg_thread_mutex_t HG_LOCK_CAPABILITY("mutex") hg_thread_spin_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the spin lock.
+ *
+ * \param lock [IN/OUT] pointer to lock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_spin_init(hg_thread_spin_t *lock);
+
+/**
+ * Destroy the spin lock.
+ *
+ * \param lock [IN/OUT] pointer to lock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_spin_destroy(hg_thread_spin_t *lock);
+
+/**
+ * Lock the spin lock.
+ *
+ * \param lock [IN/OUT] pointer to lock object
+ */
+static HG_UTIL_INLINE void hg_thread_spin_lock(hg_thread_spin_t *lock) HG_LOCK_ACQUIRE(*lock);
+
+/**
+ * Try locking the spin lock.
+ *
+ * \param mutex [IN/OUT] pointer to lock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_spin_try_lock(hg_thread_spin_t *lock)
+ HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *lock);
+
+/**
+ * Unlock the spin lock.
+ *
+ * \param mutex [IN/OUT] pointer to lock object
+ */
+static HG_UTIL_INLINE void hg_thread_spin_unlock(hg_thread_spin_t *lock) HG_LOCK_RELEASE(*lock);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_spin_lock(hg_thread_spin_t *lock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#if defined(_WIN32)
+ while (InterlockedExchange(lock, EBUSY)) {
+ /* Don't lock while waiting */
+ while (*lock) {
+ YieldProcessor();
+
+ /* Compiler barrier. Prevent caching of *lock */
+ MemoryBarrier();
+ }
+ }
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ (void)pthread_spin_lock(lock);
+#else
+ hg_thread_mutex_lock(lock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_spin_try_lock(hg_thread_spin_t *lock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#if defined(_WIN32)
+ return InterlockedExchange(lock, EBUSY);
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ if (pthread_spin_trylock(lock))
+ return HG_UTIL_FAIL;
+
+ return HG_UTIL_SUCCESS;
+#else
+ return hg_thread_mutex_try_lock(lock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_spin_unlock(hg_thread_spin_t *lock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#if defined(_WIN32)
+ /* Compiler barrier. The store below acts with release semantics */
+ MemoryBarrier();
+ *lock = 0;
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ (void)pthread_spin_unlock(lock);
+#else
+ hg_thread_mutex_unlock(lock);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_SPIN_H */
diff --git a/src/mercury/include/mercury_time.h b/src/mercury/include/mercury_time.h
new file mode 100644
index 0000000..f158638
--- /dev/null
+++ b/src/mercury/include/mercury_time.h
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_TIME_H
+#define MERCURY_TIME_H
+
+#include "mercury_util_config.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+#include <time.h>
+#elif defined(__APPLE__) && defined(HG_UTIL_HAS_SYSTIME_H)
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#else
+#include <stdio.h>
+#include <unistd.h>
+#if defined(HG_UTIL_HAS_SYSTIME_H)
+#include <sys/time.h>
+#else
+#error "Not supported on this platform."
+#endif
+#endif
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+typedef struct timespec hg_time_t;
+#else
+typedef struct hg_time hg_time_t;
+
+struct hg_time {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get an elapsed time on the calling processor.
+ *
+ * \param tv [OUT] pointer to returned time structure
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_time_get_current(hg_time_t *tv);
+
+/**
+ * Get an elapsed time on the calling processor (resolution is ms).
+ *
+ * \param tv [OUT] pointer to returned time structure
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_time_get_current_ms(hg_time_t *tv);
+
+/**
+ * Convert hg_time_t to double.
+ *
+ * \param tv [IN] time structure
+ *
+ * \return Converted time in seconds
+ */
+static HG_UTIL_INLINE double hg_time_to_double(hg_time_t tv);
+
+/**
+ * Convert double to hg_time_t.
+ *
+ * \param d [IN] time in seconds
+ *
+ * \return Converted time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_from_double(double d);
+
+/**
+ * Convert (integer) milliseconds to hg_time_t.
+ *
+ * \param ms [IN] time in milliseconds
+ *
+ * \return Converted time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_from_ms(unsigned int ms);
+
+/**
+ * Convert hg_time_t to (integer) milliseconds.
+ *
+ * \param tv [IN] time structure
+ *
+ * \return Time in milliseconds
+ */
+static HG_UTIL_INLINE unsigned int hg_time_to_ms(hg_time_t tv);
+
+/**
+ * Compare time values.
+ *
+ * \param in1 [IN] time structure
+ * \param in2 [IN] time structure
+ *
+ * \return 1 if in1 < in2, 0 otherwise
+ */
+static HG_UTIL_INLINE int hg_time_less(hg_time_t in1, hg_time_t in2);
+
+/**
+ * Diff time values and return the number of seconds elapsed between
+ * time \in2 and time \in1.
+ *
+ * \param in2 [IN] time structure
+ * \param in1 [IN] time structure
+ *
+ * \return Subtracted time
+ */
+static HG_UTIL_INLINE double hg_time_diff(hg_time_t in2, hg_time_t in1);
+
+/**
+ * Add time values.
+ *
+ * \param in1 [IN] time structure
+ * \param in2 [IN] time structure
+ *
+ * \return Summed time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_add(hg_time_t in1, hg_time_t in2);
+
+/**
+ * Subtract time values.
+ *
+ * \param in1 [IN] time structure
+ * \param in2 [IN] time structure
+ *
+ * \return Subtracted time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_subtract(hg_time_t in1, hg_time_t in2);
+
+/**
+ * Sleep until the time specified in rqt has elapsed.
+ *
+ * \param reqt [IN] time structure
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_time_sleep(const hg_time_t rqt);
+
+/**
+ * Get a string containing current time/date stamp.
+ *
+ * \return Valid string or NULL on failure
+ */
+static HG_UTIL_INLINE char *hg_time_stamp(void);
+
+/*---------------------------------------------------------------------------*/
+#ifdef _WIN32
+static HG_UTIL_INLINE LARGE_INTEGER
+get_FILETIME_offset(void)
+{
+ SYSTEMTIME s;
+ FILETIME f;
+ LARGE_INTEGER t;
+
+ s.wYear = 1970;
+ s.wMonth = 1;
+ s.wDay = 1;
+ s.wHour = 0;
+ s.wMinute = 0;
+ s.wSecond = 0;
+ s.wMilliseconds = 0;
+ SystemTimeToFileTime(&s, &f);
+ t.QuadPart = f.dwHighDateTime;
+ t.QuadPart <<= 32;
+ t.QuadPart |= f.dwLowDateTime;
+
+ return t;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ LARGE_INTEGER t;
+ FILETIME f;
+ double t_usec;
+ static LARGE_INTEGER offset;
+ static double freq_to_usec;
+ static int initialized = 0;
+ static BOOL use_perf_counter = 0;
+
+ if (!initialized) {
+ LARGE_INTEGER perf_freq;
+ initialized = 1;
+ use_perf_counter = QueryPerformanceFrequency(&perf_freq);
+ if (use_perf_counter) {
+ QueryPerformanceCounter(&offset);
+ freq_to_usec = (double)perf_freq.QuadPart / 1000000.;
+ }
+ else {
+ offset = get_FILETIME_offset();
+ freq_to_usec = 10.;
+ }
+ }
+ if (use_perf_counter) {
+ QueryPerformanceCounter(&t);
+ }
+ else {
+ GetSystemTimeAsFileTime(&f);
+ t.QuadPart = f.dwHighDateTime;
+ t.QuadPart <<= 32;
+ t.QuadPart |= f.dwLowDateTime;
+ }
+
+ t.QuadPart -= offset.QuadPart;
+ t_usec = (double)t.QuadPart / freq_to_usec;
+ t.QuadPart = t_usec;
+ tv->tv_sec = t.QuadPart / 1000000;
+ tv->tv_usec = t.QuadPart % 1000000;
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+ return hg_time_get_current(tv);
+}
+
+/*---------------------------------------------------------------------------*/
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ clock_gettime(CLOCK_MONOTONIC, tv);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+/* ppc/32 and ppc/64 do not support CLOCK_MONOTONIC_COARSE in vdso */
+#if defined(__ppc64__) || defined(__ppc__) || defined(__PPC64__) || defined(__PPC__) || \
+ !defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ clock_gettime(CLOCK_MONOTONIC, tv);
+#else
+ /* We don't need fine grain time stamps, _COARSE resolution is 1ms */
+ clock_gettime(CLOCK_MONOTONIC_COARSE, tv);
+#endif
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+#elif defined(__APPLE__) && defined(HG_UTIL_HAS_SYSTIME_H)
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ static uint64_t monotonic_timebase_factor = 0;
+ uint64_t monotonic_nsec;
+
+ if (monotonic_timebase_factor == 0) {
+ mach_timebase_info_data_t timebase_info;
+
+ (void)mach_timebase_info(&timebase_info);
+ monotonic_timebase_factor = timebase_info.numer / timebase_info.denom;
+ }
+ monotonic_nsec = (mach_absolute_time() * monotonic_timebase_factor);
+ tv->tv_sec = (long)(monotonic_nsec / 1000000000);
+ tv->tv_usec = (long)((monotonic_nsec - (uint64_t)tv->tv_sec) / 1000);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+ return hg_time_get_current(tv);
+}
+
+#else
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ gettimeofday((struct timeval *)tv, NULL);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+ return hg_time_get_current(tv);
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE double
+hg_time_to_double(hg_time_t tv)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return (double)tv.tv_sec + (double)(tv.tv_nsec) * 0.000000001;
+#else
+ return (double)tv.tv_sec + (double)(tv.tv_usec) * 0.000001;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_from_double(double d)
+{
+ hg_time_t tv;
+
+ tv.tv_sec = (long)d;
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ tv.tv_nsec = (long)((d - (double)(tv.tv_sec)) * 1000000000);
+#else
+ tv.tv_usec = (long)((d - (double)(tv.tv_sec)) * 1000000);
+#endif
+
+ return tv;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE unsigned int
+hg_time_to_ms(hg_time_t tv)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return (unsigned int)(tv.tv_sec * 1000 + tv.tv_nsec / 1000000);
+#else
+ return (unsigned int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_from_ms(unsigned int ms)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return (hg_time_t){.tv_sec = ms / 1000, .tv_nsec = (ms - (ms / 1000) * 1000) * 1000000};
+#else
+ return (hg_time_t){.tv_sec = ms / 1000, .tv_usec = (ms - (ms / 1000) * 1000) * 1000};
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_less(hg_time_t in1, hg_time_t in2)
+{
+ return ((in1.tv_sec < in2.tv_sec) || ((in1.tv_sec == in2.tv_sec) &&
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ (in1.tv_nsec < in2.tv_nsec)));
+#else
+ (in1.tv_usec < in2.tv_usec)));
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE double
+hg_time_diff(hg_time_t in2, hg_time_t in1)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return ((double)in2.tv_sec + (double)(in2.tv_nsec) * 0.000000001) -
+ ((double)in1.tv_sec + (double)(in1.tv_nsec) * 0.000000001);
+#else
+ return ((double)in2.tv_sec + (double)(in2.tv_usec) * 0.000001) -
+ ((double)in1.tv_sec + (double)(in1.tv_usec) * 0.000001);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_add(hg_time_t in1, hg_time_t in2)
+{
+ hg_time_t out;
+
+ out.tv_sec = in1.tv_sec + in2.tv_sec;
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ out.tv_nsec = in1.tv_nsec + in2.tv_nsec;
+ if (out.tv_nsec > 1000000000) {
+ out.tv_nsec -= 1000000000;
+ out.tv_sec += 1;
+ }
+#else
+ out.tv_usec = in1.tv_usec + in2.tv_usec;
+ if (out.tv_usec > 1000000) {
+ out.tv_usec -= 1000000;
+ out.tv_sec += 1;
+ }
+#endif
+
+ return out;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_subtract(hg_time_t in1, hg_time_t in2)
+{
+ hg_time_t out;
+
+ out.tv_sec = in1.tv_sec - in2.tv_sec;
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ out.tv_nsec = in1.tv_nsec - in2.tv_nsec;
+ if (out.tv_nsec < 0) {
+ out.tv_nsec += 1000000000;
+ out.tv_sec -= 1;
+ }
+#else
+ out.tv_usec = in1.tv_usec - in2.tv_usec;
+ if (out.tv_usec < 0) {
+ out.tv_usec += 1000000;
+ out.tv_sec -= 1;
+ }
+#endif
+
+ return out;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_sleep(const hg_time_t rqt)
+{
+#ifdef _WIN32
+ DWORD dwMilliseconds = (DWORD)(hg_time_to_double(rqt) / 1000);
+
+ Sleep(dwMilliseconds);
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ if (nanosleep(&rqt, NULL))
+ return HG_UTIL_FAIL;
+#else
+ useconds_t usec = (useconds_t)rqt.tv_sec * 1000000 + (useconds_t)rqt.tv_usec;
+
+ if (usleep(usec))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+#define HG_UTIL_STAMP_MAX 128
+static HG_UTIL_INLINE char *
+hg_time_stamp(void)
+{
+ static char buf[HG_UTIL_STAMP_MAX] = {'\0'};
+
+#if defined(_WIN32)
+ /* TODO not implemented */
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ struct tm *local_time;
+ time_t t;
+
+ t = time(NULL);
+ local_time = localtime(&t);
+ if (local_time == NULL)
+ return NULL;
+
+ if (strftime(buf, HG_UTIL_STAMP_MAX, "%a, %d %b %Y %T %Z", local_time) == 0)
+ return NULL;
+#else
+ struct timeval tv;
+ struct timezone tz;
+ unsigned long days, hours, minutes, seconds;
+
+ gettimeofday(&tv, &tz);
+ days = (unsigned long)tv.tv_sec / (3600 * 24);
+ hours = ((unsigned long)tv.tv_sec - days * 24 * 3600) / 3600;
+ minutes = ((unsigned long)tv.tv_sec - days * 24 * 3600 - hours * 3600) / 60;
+ seconds = (unsigned long)tv.tv_sec - days * 24 * 3600 - hours * 3600 - minutes * 60;
+ hours -= (unsigned long)tz.tz_minuteswest / 60;
+
+ snprintf(buf, HG_UTIL_STAMP_MAX, "%02lu:%02lu:%02lu (GMT-%d)", hours, minutes, seconds,
+ tz.tz_minuteswest / 60);
+#endif
+
+ return buf;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_TIME_H */
diff --git a/src/mercury/include/mercury_types.h b/src/mercury/include/mercury_types.h
new file mode 100644
index 0000000..7ea6b17
--- /dev/null
+++ b/src/mercury/include/mercury_types.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_TYPES_H
+#define MERCURY_TYPES_H
+
+#include "mercury_core_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_class hg_class_t; /* Opaque HG class */
+typedef struct hg_context hg_context_t; /* Opaque HG context */
+typedef struct hg_addr * hg_addr_t; /* Abstract HG address */
+typedef struct hg_handle *hg_handle_t; /* Abstract RPC handle */
+typedef struct hg_bulk * hg_bulk_t; /* Abstract bulk data handle */
+typedef struct hg_proc * hg_proc_t; /* Abstract serialization processor */
+typedef struct hg_op_id * hg_op_id_t; /* Abstract operation id */
+
+/* HG info struct */
+struct hg_info {
+ hg_class_t * hg_class; /* HG class */
+ hg_context_t *context; /* HG context */
+ hg_addr_t addr; /* HG address at target/origin */
+ hg_id_t id; /* RPC ID */
+ hg_uint8_t context_id; /* Context ID at target/origin */
+};
+
+/**
+ * Bulk transfer operators.
+ */
+typedef enum {
+ HG_BULK_PUSH, /*!< push data to origin */
+ HG_BULK_PULL /*!< pull data from origin */
+} hg_bulk_op_t;
+
+/* Callback info structs */
+struct hg_cb_info_lookup {
+ hg_addr_t addr; /* HG address */
+};
+
+struct hg_cb_info_forward {
+ hg_handle_t handle; /* HG handle */
+};
+
+struct hg_cb_info_respond {
+ hg_handle_t handle; /* HG handle */
+};
+
+struct hg_cb_info_bulk {
+ hg_bulk_t origin_handle; /* HG Bulk origin handle */
+ hg_bulk_t local_handle; /* HG Bulk local handle */
+ hg_bulk_op_t op; /* Operation type */
+ hg_size_t size; /* Total size transferred */
+};
+
+struct hg_cb_info {
+ union { /* Union of callback info structures */
+ struct hg_cb_info_lookup lookup;
+ struct hg_cb_info_forward forward;
+ struct hg_cb_info_respond respond;
+ struct hg_cb_info_bulk bulk;
+ } info;
+ void * arg; /* User data */
+ hg_cb_type_t type; /* Callback type */
+ hg_return_t ret; /* Return value */
+};
+
+/* RPC / HG callbacks */
+typedef hg_return_t (*hg_rpc_cb_t)(hg_handle_t handle);
+typedef hg_return_t (*hg_cb_t)(const struct hg_cb_info *callback_info);
+
+/* Proc callback for serializing/deserializing parameters */
+typedef hg_return_t (*hg_proc_cb_t)(hg_proc_t proc, void *data);
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Constant values */
+#define HG_ADDR_NULL ((hg_addr_t)0)
+#define HG_HANDLE_NULL ((hg_handle_t)0)
+#define HG_BULK_NULL ((hg_bulk_t)0)
+#define HG_PROC_NULL ((hg_proc_t)0)
+#define HG_OP_ID_NULL ((hg_op_id_t)0)
+#define HG_OP_ID_IGNORE ((hg_op_id_t *)1)
+
+#endif /* MERCURY_TYPES_H */
diff --git a/src/mercury/include/mercury_util.h b/src/mercury/include/mercury_util.h
new file mode 100644
index 0000000..1e36e26
--- /dev/null
+++ b/src/mercury/include/mercury_util.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_UTIL_LOG_H
+#define MERCURY_UTIL_LOG_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Set the log level for HG util. That setting is valid for all HG classes.
+ *
+ * \param level [IN] level string, valid values are:
+ * "none", "error", "warning", "debug"
+ */
+HG_UTIL_PUBLIC void HG_Util_set_log_level(const char *level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_UTIL_LOG_H */
diff --git a/src/mercury/include/mercury_util_config.h b/src/mercury/include/mercury_util_config.h
new file mode 100644
index 0000000..8237b4d
--- /dev/null
+++ b/src/mercury/include/mercury_util_config.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Generated file. Only edit mercury_util_config.h.in. */
+
+#ifndef MERCURY_UTIL_CONFIG_H
+#define MERCURY_UTIL_CONFIG_H
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* Type definitions */
+#ifdef _WIN32
+typedef signed __int64 hg_util_int64_t;
+typedef signed __int32 hg_util_int32_t;
+typedef signed __int16 hg_util_int16_t;
+typedef signed __int8 hg_util_int8_t;
+typedef unsigned __int64 hg_util_uint64_t;
+typedef unsigned __int32 hg_util_uint32_t;
+typedef unsigned __int16 hg_util_uint16_t;
+typedef unsigned __int8 hg_util_uint8_t;
+#else
+#include <stddef.h>
+#include <stdint.h>
+typedef int64_t hg_util_int64_t;
+typedef int32_t hg_util_int32_t;
+typedef int16_t hg_util_int16_t;
+typedef int8_t hg_util_int8_t;
+typedef uint64_t hg_util_uint64_t;
+typedef uint32_t hg_util_uint32_t;
+typedef uint16_t hg_util_uint16_t;
+typedef uint8_t hg_util_uint8_t;
+#endif
+typedef hg_util_uint8_t hg_util_bool_t;
+typedef hg_util_uint64_t hg_util_ptr_t;
+
+/* True / false */
+#define HG_UTIL_TRUE 1
+#define HG_UTIL_FALSE 0
+
+/* Return codes */
+#define HG_UTIL_SUCCESS 0
+#define HG_UTIL_FAIL -1
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Visibility of symbols */
+#if defined(_WIN32)
+#define HG_UTIL_ABI_IMPORT __declspec(dllimport)
+#define HG_UTIL_ABI_EXPORT __declspec(dllexport)
+#define HG_UTIL_ABI_HIDDEN
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+#define HG_UTIL_ABI_IMPORT __attribute__((visibility("default")))
+#define HG_UTIL_ABI_EXPORT __attribute__((visibility("default")))
+#define HG_UTIL_ABI_HIDDEN __attribute__((visibility("hidden")))
+#else
+#define HG_UTIL_ABI_IMPORT
+#define HG_UTIL_ABI_EXPORT
+#define HG_UTIL_ABI_HIDDEN
+#endif
+
+/* Inline macro */
+#ifdef _WIN32
+#define HG_UTIL_INLINE __inline
+#else
+#define HG_UTIL_INLINE __inline__
+#endif
+
+/* Check format arguments */
+#if defined(__GNUC__)
+#define HG_UTIL_PRINTF_LIKE(_fmt, _firstarg) __attribute__((format(printf, _fmt, _firstarg)))
+#else
+#define HG_UTIL_PRINTF_LIKE(_fmt, _firstarg)
+#endif
+
+/* Shared libraries */
+/* #undef HG_UTIL_BUILD_SHARED_LIBS */
+#ifdef HG_UTIL_BUILD_SHARED_LIBS
+#ifdef mercury_util_EXPORTS
+#define HG_UTIL_PUBLIC HG_UTIL_ABI_EXPORT
+#else
+#define HG_UTIL_PUBLIC HG_UTIL_ABI_IMPORT
+#endif
+#define HG_UTIL_PRIVATE HG_UTIL_ABI_HIDDEN
+#else
+#define HG_UTIL_PUBLIC
+#define HG_UTIL_PRIVATE
+#endif
+
+/* Define if has __attribute__((constructor)) */
+#define HG_UTIL_HAS_ATTR_CONSTRUCTOR
+
+/* Define if has __attribute__((constructor(priority))) */
+#define HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+
+/* Define if has 'clock_gettime()' */
+#define HG_UTIL_HAS_CLOCK_GETTIME
+
+/* Define if has CLOCK_MONOTONIC_COARSE */
+#define HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE
+
+/* Define is has debug */
+/* #undef HG_UTIL_HAS_DEBUG */
+
+/* Define if has eventfd_t type */
+#define HG_UTIL_HAS_EVENTFD_T
+
+/* Define if has colored output */
+/* #undef HG_UTIL_HAS_LOG_COLOR */
+
+/* Define if has <opa_primitives.h> */
+/* #undef HG_UTIL_HAS_OPA_PRIMITIVES_H */
+
+/* Define if has 'pthread_condattr_setclock()' */
+#define HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK
+
+/* Define if has PTHREAD_MUTEX_ADAPTIVE_NP */
+#define HG_UTIL_HAS_PTHREAD_MUTEX_ADAPTIVE_NP
+
+/* Define if has pthread_spinlock_t type */
+#define HG_UTIL_HAS_PTHREAD_SPINLOCK_T
+
+/* Define if has <stdatomic.h> */
+#define HG_UTIL_HAS_STDATOMIC_H
+
+/* Define type size of atomic_long */
+#define HG_UTIL_ATOMIC_LONG_WIDTH 8
+
+/* Define if has <sys/epoll.h> */
+#define HG_UTIL_HAS_SYSEPOLL_H
+
+/* Define if has <sys/event.h> */
+/* #undef HG_UTIL_HAS_SYSEVENT_H */
+
+/* Define if has <sys/eventfd.h> */
+#define HG_UTIL_HAS_SYSEVENTFD_H
+
+/* Define if has <sys/time.h> */
+#define HG_UTIL_HAS_SYSTIME_H
+
+/* Define if has <time.h> */
+#define HG_UTIL_HAS_TIME_H
+
+#endif /* MERCURY_UTIL_CONFIG_H */
diff --git a/src/mercury/include/na.h b/src/mercury/include/na.h
new file mode 100644
index 0000000..88b97f8
--- /dev/null
+++ b/src/mercury/include/na.h
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef NA_H
+#define NA_H
+
+#include "na_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* See na_types.h */
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* See na_types.h */
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the network abstraction layer.
+ * Must be finalized with NA_Finalize().
+ *
+ * \param info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param listen [IN] listen for incoming connections
+ *
+ * \return Pointer to NA class or NULL in case of failure
+ */
+NA_PUBLIC na_class_t *NA_Initialize(const char *info_string, na_bool_t listen) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Initialize the network abstraction layer with options provided by init_info.
+ * Must be finalized with NA_Finalize().
+ *
+ * \param info_string [IN] host address with port number (e.g.,
+ * "tcp://localhost:3344" or
+ * "bmi+tcp://localhost:3344")
+ * \param listen [IN] listen for incoming connections
+ * \param na_init_info [IN] (Optional) NA init info, NULL if no info
+ *
+ * \return Pointer to NA class or NULL in case of failure
+ */
+NA_PUBLIC na_class_t *NA_Initialize_opt(const char *info_string, na_bool_t listen,
+ const struct na_init_info *na_init_info) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Finalize the network abstraction layer.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Finalize(na_class_t *na_class);
+
+/**
+ * Clean up all temporary files that were created in previous NA instances.
+ * While temporary resources (e.g., tmp files) are cleaned up on a call
+ * to NA_Finalize(), this routine gives a chance to programs that terminate
+ * abnormally to easily clean up those resources. This includes instances
+ * from all plugins.
+ */
+NA_PUBLIC void NA_Cleanup(void);
+
+/**
+ * Set the log level for NA. That setting is valid for all NA classes.
+ *
+ * \param level [IN] level string, valid values are:
+ * "none", "error", "warning", "debug"
+ */
+NA_PUBLIC void NA_Set_log_level(const char *level);
+
+/**
+ * Return the name of the NA class.
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Pointer to NA class name or NULL in case of failure
+ */
+static NA_INLINE const char *NA_Get_class_name(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Return the protocol of the NA class.
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Pointer to NA class protocol or NULL in case of failure
+ */
+static NA_INLINE const char *NA_Get_class_protocol(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Test whether class is listening or not.
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return NA_TRUE if listening or NA_FALSE if not
+ */
+static NA_INLINE na_bool_t NA_Is_listening(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Create a new context.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ *
+ * \return Pointer to NA context or NULL in case of failure
+ */
+NA_PUBLIC na_context_t *NA_Context_create(na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Create a new context with a specific ID.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param id [IN] context ID
+ *
+ * \return Pointer to NA context or NULL in case of failure
+ */
+NA_PUBLIC na_context_t *NA_Context_create_id(na_class_t *na_class, na_uint8_t id) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Destroy a context created by using NA_Context_create().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Context_destroy(na_class_t *na_class, na_context_t *context);
+
+/**
+ * Allocate an operation ID for the higher level layer to save and
+ * pass back to the NA layer rather than have the NA layer allocate operation
+ * IDs all the time.
+ * Allocating an operation ID gives ownership of that ID to the higher level
+ * layer, hence it must be explicitly released with NA_Op_destroy() when it
+ * is no longer needed.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ *
+ * \return valid pointer to operation ID or NULL
+ */
+NA_PUBLIC na_op_id_t *NA_Op_create(na_class_t *na_class);
+
+/**
+ * Destroy operation ID created with NA_Op_create().
+ * Reference counting prevents involuntary free.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param op_id [IN] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Op_destroy(na_class_t *na_class, na_op_id_t *op_id);
+
+/**
+ * Lookup an addr from a peer address/name. Addresses need to be
+ * freed by calling NA_Addr_free().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param name [IN] lookup name
+ * \param addr [OUT] pointer to abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_lookup(na_class_t *na_class, const char *name, na_addr_t *addr);
+
+/**
+ * Free the addr from the list of peers.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [IN] abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_free(na_class_t *na_class, na_addr_t addr);
+
+/**
+ * Hint that the address is no longer valid. This may happen if the peer is
+ * no longer responding. This can be used to force removal of the
+ * peer address from the list of the peers, before freeing it and reclaim
+ * resources.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [IN] abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_set_remove(na_class_t *na_class, na_addr_t addr);
+
+/**
+ * Access self address.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [OUT] pointer to abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_self(na_class_t *na_class, na_addr_t *addr);
+
+/**
+ * Duplicate an existing NA abstract address. The duplicated address can be
+ * stored for later use and the origin address be freed safely. The duplicated
+ * address must be freed with NA_Addr_free().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [IN] abstract address
+ * \param new_addr [OUT] pointer to abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_dup(na_class_t *na_class, na_addr_t addr, na_addr_t *new_addr);
+
+/**
+ * Compare two addresses.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr1 [IN] abstract address
+ * \param addr2 [IN] abstract address
+ *
+ * \return NA_TRUE if addresses are determined to be equal, NA_FALSE otherwise
+ */
+NA_PUBLIC na_bool_t NA_Addr_cmp(na_class_t *na_class, na_addr_t addr1, na_addr_t addr2);
+
+/**
+ * Test whether address is self or not.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [IN] abstract address
+ *
+ * \return NA_TRUE if self or NA_FALSE if not
+ */
+static NA_INLINE na_bool_t NA_Addr_is_self(na_class_t *na_class, na_addr_t addr);
+
+/**
+ * Convert an addr to a string (returned string includes the terminating
+ * null byte '\0'). If buf is NULL, the address is not converted and only
+ * the required size of the buffer is returned. If the input value passed
+ * through buf_size is too small, NA_OVERFLOW is returned and the buf_size
+ * output is set to the minimum size required.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN/OUT] pointer to destination buffer
+ * \param buf_size [IN/OUT] pointer to buffer size
+ * \param addr [IN] abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_to_string(na_class_t *na_class, char *buf, na_size_t *buf_size, na_addr_t addr);
+
+/**
+ * Get size required to serialize address.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [IN] abstract address
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Addr_get_serialize_size(na_class_t *na_class,
+ na_addr_t addr) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Serialize address into a buffer.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN/OUT] pointer to buffer used for serialization
+ * \param buf_size [IN] buffer size
+ * \param addr [IN] abstract address
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_serialize(na_class_t *na_class, void *buf, na_size_t buf_size, na_addr_t addr);
+
+/**
+ * Deserialize address from a buffer. The returned address must be freed with
+ * NA_Addr_free().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param addr [OUT] pointer to abstract address
+ * \param buf [IN] pointer to buffer used for deserialization
+ * \param buf_size [IN] buffer size
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Addr_deserialize(na_class_t *na_class, na_addr_t *addr, const void *buf,
+ na_size_t buf_size);
+
+/**
+ * Get the maximum size of messages supported by unexpected send/recv.
+ * Small message size.
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Msg_get_max_unexpected_size(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Get the maximum size of messages supported by expected send/recv.
+ * Small message size that may differ from the unexpected message size.
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Msg_get_max_expected_size(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Get the header size for unexpected messages. Plugins may use that header
+ * to encode specific information (such as source addr, etc).
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Msg_get_unexpected_header_size(const na_class_t *na_class)
+ NA_WARN_UNUSED_RESULT;
+
+/**
+ * Get the header size for expected messages. Plugins may use that header
+ * to encode specific information.
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Msg_get_expected_header_size(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Get the maximum tag value that can be used by send/recv (both expected and
+ * unexpected).
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_tag_t NA_Msg_get_max_tag(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Allocate buf_size bytes and return a pointer to the allocated memory.
+ * If size is 0, NA_Msg_buf_alloc() returns NULL. The plugin_data output
+ * parameter can be used by the underlying plugin implementation to store
+ * internal memory information.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf_size [IN] buffer size
+ * \param plugin_data [OUT] pointer to internal plugin data
+ *
+ * \return Pointer to allocated memory or NULL in case of failure
+ */
+NA_PUBLIC void *NA_Msg_buf_alloc(na_class_t *na_class, na_size_t buf_size,
+ void **plugin_data) NA_WARN_UNUSED_RESULT;
+
+/**
+ * The NA_Msg_buf_free() function releases the memory space pointed to by buf,
+ * which must have been returned by a previous call to NA_Msg_buf_alloc().
+ * If buf is NULL, no operation is performed.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN] pointer to buffer
+ * \param plugin_data [IN] pointer to internal plugin data
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Msg_buf_free(na_class_t *na_class, void *buf, void *plugin_data);
+
+/**
+ * Initialize a buffer so that it can be safely passed to the
+ * NA_Msg_send_unexpected() call. In the case the underlying plugin adds its
+ * own header to that buffer, the header will be written at this time and the
+ * usable buffer payload will be buf + NA_Msg_get_unexpected_header_size().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN] pointer to buffer
+ * \param buf_size [IN] buffer size
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Msg_init_unexpected(na_class_t *na_class, void *buf, na_size_t buf_size);
+
+/**
+ * Send an unexpected message to dest_addr. Unexpected sends do not require a
+ * matching receive to complete. After completion, the user callback is
+ * placed into the context completion queue and can be triggered using
+ * NA_Trigger().
+ * The plugin_data parameter returned from the NA_Msg_buf_alloc() call must
+ * be passed along with the buffer, it allows plugins to store and retrieve
+ * additional buffer information such as memory descriptors.
+ * \remark Note also that unexpected messages do not require an unexpected
+ * receive to be posted at the destination before sending the message and the
+ * destination is allowed to drop the message without notification. However,
+ * in general, NA plugins are encouraged to remain reliable to avoid unnecessary
+ * timeouts and cancelations.
+ *
+ * Users must manually create an operation ID through NA_Op_create() and pass
+ * it through op_id for future use and prevent multiple ID creation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param buf [IN] pointer to send buffer
+ * \param buf_size [IN] buffer size
+ * \param plugin_data [IN] pointer to internal plugin data
+ * \param dest_addr [IN] abstract address of destination
+ * \param dest_id [IN] destination context ID
+ * \param tag [IN] tag attached to message
+ * \param op_id [IN/OUT] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+static NA_INLINE na_return_t NA_Msg_send_unexpected(na_class_t *na_class, na_context_t *context,
+ na_cb_t callback, void *arg, const void *buf,
+ na_size_t buf_size, void *plugin_data,
+ na_addr_t dest_addr, na_uint8_t dest_id, na_tag_t tag,
+ na_op_id_t *op_id);
+
+/**
+ * Receive an unexpected message. Unexpected receives may wait on any tag and
+ * any source depending on the implementation. After completion, the user
+ * callback parameter is placed into the context completion queue and can be
+ * triggered using NA_Trigger().
+ * The plugin_data parameter returned from the NA_Msg_buf_alloc() call must
+ * be passed along with the buffer, it allows plugins to store and retrieve
+ * additional buffer information such as memory descriptors.
+ *
+ * Users must manually create an operation ID through NA_Op_create() and pass
+ * it through op_id for future use and prevent multiple ID creation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param buf [IN] pointer to send buffer
+ * \param buf_size [IN] buffer size
+ * \param plugin_data [IN] pointer to internal plugin data
+ * \param op_id [IN/OUT] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+static NA_INLINE na_return_t NA_Msg_recv_unexpected(na_class_t *na_class, na_context_t *context,
+ na_cb_t callback, void *arg, void *buf,
+ na_size_t buf_size, void *plugin_data, na_op_id_t *op_id);
+
+/**
+ * Initialize a buffer so that it can be safely passed to the
+ * NA_Msg_send_expected() call. In the case the underlying plugin adds its
+ * own header to that buffer, the header will be written at this time and the
+ * usable buffer payload will be buf + NA_Msg_get_expected_header_size().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN] pointer to buffer
+ * \param buf_size [IN] buffer size
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Msg_init_expected(na_class_t *na_class, void *buf, na_size_t buf_size);
+
+/**
+ * Send an expected message to dest_addr. After completion, the user callback is
+ * placed into the context completion queue and can be triggered using
+ * NA_Trigger().
+ * The plugin_data parameter returned from the NA_Msg_buf_alloc() call must
+ * be passed along with the buffer, it allows plugins to store and retrieve
+ * additional buffer information such as memory descriptors.
+ * \remark Note that expected messages require an expected receive to be posted
+ * at the destination before sending the message, otherwise the destination is
+ * allowed to drop the message without notification.
+ *
+ * Users must manually create an operation ID through NA_Op_create() and pass
+ * it through op_id for future use and prevent multiple ID creation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param buf [IN] pointer to send buffer
+ * \param buf_size [IN] buffer size
+ * \param plugin_data [IN] pointer to internal plugin data
+ * \param dest_addr [IN] abstract address of destination
+ * \param dest_id [IN] destination context ID
+ * \param tag [IN] tag attached to message
+ * \param op_id [IN/OUT] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+static NA_INLINE na_return_t NA_Msg_send_expected(na_class_t *na_class, na_context_t *context,
+ na_cb_t callback, void *arg, const void *buf,
+ na_size_t buf_size, void *plugin_data, na_addr_t dest_addr,
+ na_uint8_t dest_id, na_tag_t tag, na_op_id_t *op_id);
+
+/**
+ * Receive an expected message from source_addr. After completion, the user
+ * callback is placed into the context completion queue and can be triggered
+ * using NA_Trigger().
+ * The plugin_data parameter returned from the NA_Msg_buf_alloc() call must
+ * be passed along with the buffer, it allows plugins to store and retrieve
+ * additional buffer information such as memory descriptors.
+ *
+ * Users must manually create an operation ID through NA_Op_create() and pass
+ * it through op_id for future use and prevent multiple ID creation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param buf [IN] pointer to receive buffer
+ * \param buf_size [IN] buffer size
+ * \param plugin_data [IN] pointer to internal plugin data
+ * \param source_addr [IN] abstract address of source
+ * \param source_id [IN] source context ID
+ * \param tag [IN] matching tag used to receive message
+ * \param op_id [IN/OUT] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+static NA_INLINE na_return_t NA_Msg_recv_expected(na_class_t *na_class, na_context_t *context,
+ na_cb_t callback, void *arg, void *buf, na_size_t buf_size,
+ void *plugin_data, na_addr_t source_addr,
+ na_uint8_t source_id, na_tag_t tag, na_op_id_t *op_id);
+
+/**
+ * Create memory handle for RMA operations.
+ * For non-contiguous memory, use NA_Mem_handle_create_segments() instead.
+ *
+ * \remark Note to plugin developers: NA_Mem_handle_create() may be called
+ * multiple times on the same memory region.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN] pointer to buffer that needs to be registered
+ * \param buf_size [IN] buffer size
+ * \param flags [IN] permission flag:
+ * - NA_MEM_READWRITE
+ * - NA_MEM_READ_ONLY
+ * \param mem_handle [OUT] pointer to returned abstract memory handle
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_handle_create(na_class_t *na_class, void *buf, na_size_t buf_size,
+ unsigned long flags, na_mem_handle_t *mem_handle);
+
+/**
+ * Create memory handle for RMA operations.
+ * Create_segments can be used to register scatter-gather lists and get a single
+ * memory handle.
+ * \remark Implemented only if the network transport or hardware supports it.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param segments [IN] pointer to array of segments composed of:
+ * - address of the segment that needs to be
+ * registered
+ * - size of the segment in bytes
+ * \param segment_count [IN] segment count
+ * \param flags [IN] permission flag:
+ * - NA_MEM_READWRITE
+ * - NA_MEM_READ_ONLY
+ * \param mem_handle [OUT] pointer to returned abstract memory handle
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_handle_create_segments(na_class_t *na_class, struct na_segment *segments,
+ na_size_t segment_count, unsigned long flags,
+ na_mem_handle_t *mem_handle);
+
+/**
+ * Free memory handle.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param mem_handle [IN] abstract memory handle
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_handle_free(na_class_t *na_class, na_mem_handle_t mem_handle);
+
+/**
+ * Get the maximum segment count that can be passed to
+ * NA_Mem_handle_create_segments().
+ *
+ * \param na_class [IN] pointer to NA class
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Mem_handle_get_max_segments(const na_class_t *na_class) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Register memory for RMA operations.
+ * Memory pieces must be registered before one-sided transfers can be
+ * initiated.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param mem_handle [IN] pointer to abstract memory handle
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_register(na_class_t *na_class, na_mem_handle_t mem_handle);
+
+/**
+ * Unregister memory.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param mem_handle [IN] abstract memory handle
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_deregister(na_class_t *na_class, na_mem_handle_t mem_handle);
+
+/**
+ * Get size required to serialize handle.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param mem_handle [IN] abstract memory handle
+ *
+ * \return Non-negative value
+ */
+static NA_INLINE na_size_t NA_Mem_handle_get_serialize_size(na_class_t * na_class,
+ na_mem_handle_t mem_handle) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Serialize memory handle into a buffer.
+ * One-sided transfers require prior exchange of memory handles between
+ * peers, serialization callbacks can be used to "pack" a memory handle and
+ * send it across the network.
+ * \remark Memory handles can be variable size, therefore the space required
+ * to serialize a handle into a buffer can be obtained using
+ * NA_Mem_handle_get_serialize_size().
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param buf [IN/OUT] pointer to buffer used for serialization
+ * \param buf_size [IN] buffer size
+ * \param mem_handle [IN] abstract memory handle
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_handle_serialize(na_class_t *na_class, void *buf, na_size_t buf_size,
+ na_mem_handle_t mem_handle);
+
+/**
+ * Deserialize memory handle from buffer.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param mem_handle [OUT] pointer to abstract memory handle
+ * \param buf [IN] pointer to buffer used for deserialization
+ * \param buf_size [IN] buffer size
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Mem_handle_deserialize(na_class_t *na_class, na_mem_handle_t *mem_handle,
+ const void *buf, na_size_t buf_size);
+
+/**
+ * Put data to remote address.
+ * Initiate a put to the registered memory regions with the given offset/size.
+ * After completion, the user callback is placed into a completion queue and
+ * can be triggered using NA_Trigger().
+ * \remark Memory must be registered and handles exchanged between peers.
+ *
+ * Users must manually create an operation ID through NA_Op_create() and pass
+ * it through op_id for future use and prevent multiple ID creation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param local_mem_handle [IN] abstract local memory handle
+ * \param local_offset [IN] local offset
+ * \param remote_mem_handle [IN] abstract remote memory handle
+ * \param remote_offset [IN] remote offset
+ * \param data_size [IN] size of data that needs to be transferred
+ * \param remote_addr [IN] abstract address of remote destination
+ * \param remote_id [IN] target ID of remote destination
+ * \param op_id [IN/OUT] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+static NA_INLINE na_return_t NA_Put(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ na_mem_handle_t local_mem_handle, na_offset_t local_offset,
+ na_mem_handle_t remote_mem_handle, na_offset_t remote_offset,
+ na_size_t data_size, na_addr_t remote_addr, na_uint8_t remote_id,
+ na_op_id_t *op_id);
+
+/**
+ * Get data from remote address.
+ * Initiate a get to the registered memory regions with the given offset/size.
+ * After completion, the user callback is placed into a completion queue and
+ * can be triggered using NA_Trigger().
+ *
+ * Users must manually create an operation ID through NA_Op_create() and pass
+ * it through op_id for future use and prevent multiple ID creation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param callback [IN] pointer to function callback
+ * \param arg [IN] pointer to data passed to callback
+ * \param local_mem_handle [IN] abstract local memory handle
+ * \param local_offset [IN] local offset
+ * \param remote_mem_handle [IN] abstract remote memory handle
+ * \param remote_offset [IN] remote offset
+ * \param data_size [IN] size of data that needs to be transferred
+ * \param remote_addr [IN] abstract address of remote source
+ * \param remote_id [IN] target ID of remote source
+ * \param op_id [IN/OUT] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+static NA_INLINE na_return_t NA_Get(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ na_mem_handle_t local_mem_handle, na_offset_t local_offset,
+ na_mem_handle_t remote_mem_handle, na_offset_t remote_offset,
+ na_size_t data_size, na_addr_t remote_addr, na_uint8_t remote_id,
+ na_op_id_t *op_id);
+
+/**
+ * Retrieve file descriptor from NA plugin when supported. The descriptor
+ * can be used by upper layers for manual polling through the usual
+ * OS select/poll/epoll calls.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ *
+ * \return Non-negative integer if supported, 0 if not implemented and negative
+ * in case of error.
+ */
+static NA_INLINE int NA_Poll_get_fd(na_class_t *na_class, na_context_t *context) NA_WARN_UNUSED_RESULT;
+
+/**
+ * Used to signal when it is safe to block on the class/context poll descriptor
+ * or if there is already work that can be progressed.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ *
+ * \return NA_TRUE if it is safe to block or NA_FALSE otherwise
+ */
+NA_PUBLIC na_bool_t NA_Poll_try_wait(na_class_t *na_class, na_context_t *context);
+
+/**
+ * Try to progress communication for at most timeout until timeout is reached or
+ * any completion has occurred.
+ * Progress should not be considered as wait, in the sense that it cannot be
+ * assumed that completion of a specific operation will occur only when
+ * progress is called.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param timeout [IN] timeout (in milliseconds)
+ *
+ * \return NA_SUCCESS if any completion has occurred / NA error code otherwise
+ */
+NA_PUBLIC na_return_t NA_Progress(na_class_t *na_class, na_context_t *context, unsigned int timeout);
+
+/**
+ * Execute at most max_count callbacks. If timeout is non-zero, wait up to
+ * timeout before returning. Function can return when at least one or more
+ * callbacks are triggered (at most max_count).
+ *
+ * \param context [IN/OUT] pointer to context of execution
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param max_count [IN] maximum number of callbacks triggered
+ * \param callback_ret [IN/OUT] array of callback return values
+ * \param actual_count [OUT] actual number of callbacks triggered
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Trigger(na_context_t *context, unsigned int timeout, unsigned int max_count,
+ int callback_ret[], unsigned int *actual_count);
+
+/**
+ * Cancel an ongoing operation.
+ *
+ * \param na_class [IN/OUT] pointer to NA class
+ * \param context [IN/OUT] pointer to context of execution
+ * \param op_id [IN] pointer to operation ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_Cancel(na_class_t *na_class, na_context_t *context, na_op_id_t *op_id);
+
+/**
+ * Convert error return code to string (null terminated).
+ *
+ * \param errnum [IN] error return code
+ *
+ * \return String
+ */
+NA_PUBLIC const char *NA_Error_to_string(na_return_t errnum) NA_WARN_UNUSED_RESULT;
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/* NA info definition */
+struct na_info {
+ char *class_name; /* Class name (e.g., bmi) */
+ char *protocol_name; /* Protocol (e.g., tcp, ib) */
+ char *host_name; /* Host (may be NULL in anonymous mode) */
+ /* Additional init info (NULL if no info) */
+ const struct na_init_info *na_init_info;
+};
+
+/* NA class definition */
+struct na_class {
+ const struct na_class_ops *ops; /* Class operations */
+ void * plugin_class; /* Plugin private class */
+ char * protocol_name; /* Name of protocol */
+ na_uint32_t progress_mode; /* NA progress mode */
+ na_bool_t listen; /* Listen for connections */
+};
+
+/* NA context definition */
+struct na_context {
+ void *plugin_context; /* Plugin private context */
+};
+
+/* NA plugin callbacks */
+struct na_class_ops {
+ const char *class_name;
+ na_bool_t (*check_protocol)(const char *protocol_name);
+ na_return_t (*initialize)(na_class_t *na_class, const struct na_info *na_info, na_bool_t listen);
+ na_return_t (*finalize)(na_class_t *na_class);
+ void (*cleanup)(void);
+ na_return_t (*context_create)(na_class_t *na_class, void **plugin_context, na_uint8_t id);
+ na_return_t (*context_destroy)(na_class_t *na_class, void *plugin_context);
+ na_op_id_t *(*op_create)(na_class_t *na_class);
+ na_return_t (*op_destroy)(na_class_t *na_class, na_op_id_t *op_id);
+ na_return_t (*addr_lookup)(na_class_t *na_class, const char *name, na_addr_t *addr);
+ na_return_t (*addr_free)(na_class_t *na_class, na_addr_t addr);
+ na_return_t (*addr_set_remove)(na_class_t *na_class, na_addr_t addr);
+ na_return_t (*addr_self)(na_class_t *na_class, na_addr_t *addr);
+ na_return_t (*addr_dup)(na_class_t *na_class, na_addr_t addr, na_addr_t *new_addr);
+ na_bool_t (*addr_cmp)(na_class_t *na_class, na_addr_t addr1, na_addr_t addr2);
+ na_bool_t (*addr_is_self)(na_class_t *na_class, na_addr_t addr);
+ na_return_t (*addr_to_string)(na_class_t *na_class, char *buf, na_size_t *buf_size, na_addr_t addr);
+ na_size_t (*addr_get_serialize_size)(na_class_t *na_class, na_addr_t addr);
+ na_return_t (*addr_serialize)(na_class_t *na_class, void *buf, na_size_t buf_size, na_addr_t addr);
+ na_return_t (*addr_deserialize)(na_class_t *na_class, na_addr_t *addr, const void *buf,
+ na_size_t buf_size);
+ na_size_t (*msg_get_max_unexpected_size)(const na_class_t *na_class);
+ na_size_t (*msg_get_max_expected_size)(const na_class_t *na_class);
+ na_size_t (*msg_get_unexpected_header_size)(const na_class_t *na_class);
+ na_size_t (*msg_get_expected_header_size)(const na_class_t *na_class);
+ na_tag_t (*msg_get_max_tag)(const na_class_t *na_class);
+ void *(*msg_buf_alloc)(na_class_t *na_class, na_size_t buf_size, void **plugin_data);
+ na_return_t (*msg_buf_free)(na_class_t *na_class, void *buf, void *plugin_data);
+ na_return_t (*msg_init_unexpected)(na_class_t *na_class, void *buf, na_size_t buf_size);
+ na_return_t (*msg_send_unexpected)(na_class_t *na_class, na_context_t *context, na_cb_t callback,
+ void *arg, const void *buf, na_size_t buf_size, void *plugin_data,
+ na_addr_t dest_addr, na_uint8_t dest_id, na_tag_t tag,
+ na_op_id_t *op_id);
+ na_return_t (*msg_recv_unexpected)(na_class_t *na_class, na_context_t *context, na_cb_t callback,
+ void *arg, void *buf, na_size_t buf_size, void *plugin_data,
+ na_op_id_t *op_id);
+ na_return_t (*msg_init_expected)(na_class_t *na_class, void *buf, na_size_t buf_size);
+ na_return_t (*msg_send_expected)(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ const void *buf, na_size_t buf_size, void *plugin_data,
+ na_addr_t dest_addr, na_uint8_t dest_id, na_tag_t tag,
+ na_op_id_t *op_id);
+ na_return_t (*msg_recv_expected)(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ void *buf, na_size_t buf_size, void *plugin_data, na_addr_t source_addr,
+ na_uint8_t source_id, na_tag_t tag, na_op_id_t *op_id);
+ na_return_t (*mem_handle_create)(na_class_t *na_class, void *buf, na_size_t buf_size, unsigned long flags,
+ na_mem_handle_t *mem_handle);
+ na_return_t (*mem_handle_create_segments)(na_class_t *na_class, struct na_segment *segments,
+ na_size_t segment_count, unsigned long flags,
+ na_mem_handle_t *mem_handle);
+ na_return_t (*mem_handle_free)(na_class_t *na_class, na_mem_handle_t mem_handle);
+ na_size_t (*mem_handle_get_max_segments)(const na_class_t *na_class);
+ na_return_t (*mem_register)(na_class_t *na_class, na_mem_handle_t mem_handle);
+ na_return_t (*mem_deregister)(na_class_t *na_class, na_mem_handle_t mem_handle);
+ na_size_t (*mem_handle_get_serialize_size)(na_class_t *na_class, na_mem_handle_t mem_handle);
+ na_return_t (*mem_handle_serialize)(na_class_t *na_class, void *buf, na_size_t buf_size,
+ na_mem_handle_t mem_handle);
+ na_return_t (*mem_handle_deserialize)(na_class_t *na_class, na_mem_handle_t *mem_handle, const void *buf,
+ na_size_t buf_size);
+ na_return_t (*put)(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ na_mem_handle_t local_mem_handle, na_offset_t local_offset,
+ na_mem_handle_t remote_mem_handle, na_offset_t remote_offset, na_size_t length,
+ na_addr_t remote_addr, na_uint8_t remote_id, na_op_id_t *op_id);
+ na_return_t (*get)(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ na_mem_handle_t local_mem_handle, na_offset_t local_offset,
+ na_mem_handle_t remote_mem_handle, na_offset_t remote_offset, na_size_t length,
+ na_addr_t remote_addr, na_uint8_t remote_id, na_op_id_t *op_id);
+ int (*na_poll_get_fd)(na_class_t *na_class, na_context_t *context);
+ na_bool_t (*na_poll_try_wait)(na_class_t *na_class, na_context_t *context);
+ na_return_t (*progress)(na_class_t *na_class, na_context_t *context, unsigned int timeout);
+ na_return_t (*cancel)(na_class_t *na_class, na_context_t *context, na_op_id_t *op_id);
+};
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE const char *
+NA_Get_class_name(const na_class_t *na_class)
+{
+ return na_class->ops->class_name;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE const char *
+NA_Get_class_protocol(const na_class_t *na_class)
+{
+ return na_class->protocol_name;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_bool_t
+NA_Is_listening(const na_class_t *na_class)
+{
+ return na_class->listen;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_bool_t
+NA_Addr_is_self(na_class_t *na_class, na_addr_t addr)
+{
+ return na_class->ops->addr_is_self(na_class, addr);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Addr_get_serialize_size(na_class_t *na_class, na_addr_t addr)
+{
+ return (na_class->ops->addr_get_serialize_size) ? na_class->ops->addr_get_serialize_size(na_class, addr)
+ : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Msg_get_max_unexpected_size(const na_class_t *na_class)
+{
+ return na_class->ops->msg_get_max_unexpected_size(na_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Msg_get_max_expected_size(const na_class_t *na_class)
+{
+ return na_class->ops->msg_get_max_expected_size(na_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Msg_get_unexpected_header_size(const na_class_t *na_class)
+{
+ return (na_class->ops->msg_get_unexpected_header_size)
+ ? na_class->ops->msg_get_unexpected_header_size(na_class)
+ : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Msg_get_expected_header_size(const na_class_t *na_class)
+{
+ return (na_class->ops->msg_get_expected_header_size)
+ ? na_class->ops->msg_get_expected_header_size(na_class)
+ : 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_tag_t
+NA_Msg_get_max_tag(const na_class_t *na_class)
+{
+ return na_class->ops->msg_get_max_tag(na_class);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_return_t
+NA_Msg_send_unexpected(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ const void *buf, na_size_t buf_size, void *plugin_data, na_addr_t dest_addr,
+ na_uint8_t dest_id, na_tag_t tag, na_op_id_t *op_id)
+{
+ return na_class->ops->msg_send_unexpected(na_class, context, callback, arg, buf, buf_size, plugin_data,
+ dest_addr, dest_id, tag, op_id);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_return_t
+NA_Msg_recv_unexpected(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg, void *buf,
+ na_size_t buf_size, void *plugin_data, na_op_id_t *op_id)
+{
+ return na_class->ops->msg_recv_unexpected(na_class, context, callback, arg, buf, buf_size, plugin_data,
+ op_id);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_return_t
+NA_Msg_send_expected(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ const void *buf, na_size_t buf_size, void *plugin_data, na_addr_t dest_addr,
+ na_uint8_t dest_id, na_tag_t tag, na_op_id_t *op_id)
+{
+ return na_class->ops->msg_send_expected(na_class, context, callback, arg, buf, buf_size, plugin_data,
+ dest_addr, dest_id, tag, op_id);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_return_t
+NA_Msg_recv_expected(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg, void *buf,
+ na_size_t buf_size, void *plugin_data, na_addr_t source_addr, na_uint8_t source_id,
+ na_tag_t tag, na_op_id_t *op_id)
+{
+ return na_class->ops->msg_recv_expected(na_class, context, callback, arg, buf, buf_size, plugin_data,
+ source_addr, source_id, tag, op_id);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Mem_handle_get_max_segments(const na_class_t *na_class)
+{
+ return (na_class->ops->mem_handle_get_max_segments) ? na_class->ops->mem_handle_get_max_segments(na_class)
+ : 1;
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_size_t
+NA_Mem_handle_get_serialize_size(na_class_t *na_class, na_mem_handle_t mem_handle)
+{
+ return na_class->ops->mem_handle_get_serialize_size(na_class, mem_handle);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_return_t
+NA_Put(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ na_mem_handle_t local_mem_handle, na_offset_t local_offset, na_mem_handle_t remote_mem_handle,
+ na_offset_t remote_offset, na_size_t data_size, na_addr_t remote_addr, na_uint8_t remote_id,
+ na_op_id_t *op_id)
+{
+ return na_class->ops->put(na_class, context, callback, arg, local_mem_handle, local_offset,
+ remote_mem_handle, remote_offset, data_size, remote_addr, remote_id, op_id);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE na_return_t
+NA_Get(na_class_t *na_class, na_context_t *context, na_cb_t callback, void *arg,
+ na_mem_handle_t local_mem_handle, na_offset_t local_offset, na_mem_handle_t remote_mem_handle,
+ na_offset_t remote_offset, na_size_t data_size, na_addr_t remote_addr, na_uint8_t remote_id,
+ na_op_id_t *op_id)
+{
+ return na_class->ops->get(na_class, context, callback, arg, local_mem_handle, local_offset,
+ remote_mem_handle, remote_offset, data_size, remote_addr, remote_id, op_id);
+}
+
+/*---------------------------------------------------------------------------*/
+static NA_INLINE int
+NA_Poll_get_fd(na_class_t *na_class, na_context_t *context)
+{
+ return (na_class->ops->na_poll_get_fd) ? na_class->ops->na_poll_get_fd(na_class, context) : -1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NA_H */
diff --git a/src/mercury/include/na_config.h b/src/mercury/include/na_config.h
new file mode 100644
index 0000000..579ba63
--- /dev/null
+++ b/src/mercury/include/na_config.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Generated file. Only edit na_config.h.in. */
+
+#ifndef NA_CONFIG_H
+#define NA_CONFIG_H
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* Type definitions */
+#ifdef _WIN32
+typedef signed __int64 na_int64_t;
+typedef signed __int32 na_int32_t;
+typedef signed __int16 na_int16_t;
+typedef signed __int8 na_int8_t;
+typedef unsigned __int64 na_uint64_t;
+typedef unsigned __int32 na_uint32_t;
+typedef unsigned __int16 na_uint16_t;
+typedef unsigned __int8 na_uint8_t;
+#else
+#include <stddef.h>
+#include <stdint.h>
+typedef int64_t na_int64_t;
+typedef int32_t na_int32_t;
+typedef int16_t na_int16_t;
+typedef int8_t na_int8_t;
+typedef uint64_t na_uint64_t;
+typedef uint32_t na_uint32_t;
+typedef uint16_t na_uint16_t;
+typedef uint8_t na_uint8_t;
+#endif
+typedef na_uint8_t na_bool_t;
+typedef na_uint64_t na_ptr_t;
+
+/* True / false */
+#define NA_TRUE 1
+#define NA_FALSE 0
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Visibility of symbols */
+#if defined(_WIN32)
+#define NA_ABI_IMPORT __declspec(dllimport)
+#define NA_ABI_EXPORT __declspec(dllexport)
+#define NA_ABI_HIDDEN
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+#define NA_ABI_IMPORT __attribute__((visibility("default")))
+#define NA_ABI_EXPORT __attribute__((visibility("default")))
+#define NA_ABI_HIDDEN __attribute__((visibility("hidden")))
+#else
+#define NA_ABI_IMPORT
+#define NA_ABI_EXPORT
+#define NA_ABI_HIDDEN
+#endif
+
+/* Inline macro */
+#ifdef _WIN32
+#define NA_INLINE __inline
+#else
+#define NA_INLINE __inline__
+#endif
+
+/* Unused return values */
+#if defined(__GNUC__)
+#define NA_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define NA_WARN_UNUSED_RESULT
+#endif
+
+/* Fallthrough macro */
+#if defined(__GNUC__) && (__GNUC__ >= 7)
+#define NA_FALLTHROUGH() __attribute__((fallthrough))
+#else
+#define NA_FALLTHROUGH()
+#endif
+
+/* Shared libraries */
+/* #undef NA_BUILD_SHARED_LIBS */
+#ifdef NA_BUILD_SHARED_LIBS
+#ifdef na_EXPORTS
+#define NA_PUBLIC NA_ABI_EXPORT
+#else
+#define NA_PUBLIC NA_ABI_IMPORT
+#endif
+#define NA_PRIVATE NA_ABI_HIDDEN
+#else
+#define NA_PUBLIC
+#define NA_PRIVATE
+#endif
+
+/* Build Options */
+#define NA_HAS_MULTI_PROGRESS
+/* #undef NA_HAS_DEBUG */
+
+/* BMI */
+/* #undef NA_HAS_BMI */
+
+/* MPI */
+/* #undef NA_HAS_MPI */
+/* #undef NA_MPI_HAS_GNI_SETUP */
+
+/* CCI */
+/* #undef NA_HAS_CCI */
+
+/* OFI */
+/* #undef NA_HAS_OFI */
+/* #undef NA_OFI_HAS_EXT_GNI_H */
+/* #undef NA_OFI_GNI_HAS_UDREG */
+
+/* NA SM */
+#define NA_HAS_SM
+/* #undef NA_SM_HAS_UUID */
+#define NA_SM_HAS_CMA
+#define NA_SM_SHM_PREFIX "na_sm"
+#define NA_SM_TMP_DIRECTORY "/tmp"
+
+/* UCX */
+/* #undef NA_HAS_UCX */
+/* #undef NA_UCX_HAS_LIB_QUERY */
+/* #undef NA_UCX_HAS_THREAD_MODE_NAMES */
+
+#endif /* NA_CONFIG_H */
diff --git a/src/mercury/include/na_sm.h b/src/mercury/include/na_sm.h
new file mode 100644
index 0000000..709c639
--- /dev/null
+++ b/src/mercury/include/na_sm.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef NA_SM_H
+#define NA_SM_H
+
+#include "na_types.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#ifdef NA_SM_HAS_UUID
+typedef unsigned char na_sm_id_t[16];
+#else
+typedef long na_sm_id_t;
+#endif
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* String length of Host ID */
+#ifdef NA_SM_HAS_UUID
+#define NA_SM_HOST_ID_LEN 36
+#else
+#define NA_SM_HOST_ID_LEN 11
+#endif
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get the curent host ID (generate a new one if none exists).
+ *
+ * \param id [IN/OUT] pointer to SM host ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_SM_Host_id_get(na_sm_id_t *id);
+
+/**
+ * Convert host ID to string. String size must be NA_SM_HOST_ID_LEN + 1.
+ *
+ * \param id [IN] SM host ID
+ * \param string [IN/OUT] pointer to string
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_SM_Host_id_to_string(na_sm_id_t id, char *string);
+
+/**
+ * Convert string to host ID. String size must be NA_SM_HOST_ID_LEN + 1.
+ *
+ * \param string [IN] pointer to string
+ * \param id [IN/OUT] pointer to SM host ID
+ *
+ * \return NA_SUCCESS or corresponding NA error code
+ */
+NA_PUBLIC na_return_t NA_SM_String_to_host_id(const char *string, na_sm_id_t *id);
+
+/**
+ * Copy src host ID to dst.
+ *
+ * \param dst [IN/OUT] pointer to destination SM host ID
+ * \param src [IN] source SM host ID
+ */
+NA_PUBLIC void NA_SM_Host_id_copy(na_sm_id_t *dst, na_sm_id_t src);
+
+/**
+ * Compare two host IDs.
+ *
+ * \param id1 [IN] SM host ID
+ * \param id2 [IN] SM host ID
+ *
+ * \return NA_TRUE if equal or NA_FALSE otherwise
+ */
+NA_PUBLIC na_bool_t NA_SM_Host_id_cmp(na_sm_id_t id1, na_sm_id_t id2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NA_SM_H */
diff --git a/src/mercury/include/na_types.h b/src/mercury/include/na_types.h
new file mode 100644
index 0000000..0062ebe
--- /dev/null
+++ b/src/mercury/include/na_types.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef NA_TYPES_H
+#define NA_TYPES_H
+
+#include "na_config.h"
+
+#include <limits.h>
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct na_class na_class_t; /* Opaque NA class */
+typedef struct na_context na_context_t; /* Opaque NA execution context */
+typedef struct na_addr * na_addr_t; /* Abstract NA address */
+typedef na_uint64_t na_size_t; /* Size */
+typedef na_uint32_t na_tag_t; /* Tag */
+typedef struct na_op_id na_op_id_t; /* Opaque operation id */
+
+typedef struct na_mem_handle *na_mem_handle_t; /* Abstract memory handle */
+typedef na_uint64_t na_offset_t; /* Offset */
+
+/* Init info */
+struct na_init_info {
+ /* Preferred IP subnet to use. */
+ const char *ip_subnet;
+
+ /* Authorization key that can be used for communication. All processes
+ * should use the same key in order to communicate.
+ * NB. generation of keys is done through third-party libraries. */
+ const char *auth_key;
+
+ /* Max unexpected size hint that can be passed to control the size of
+ * unexpected messages. Note that the underlying plugin library may switch
+ * to different transfer protocols depending on the message size that is
+ * used. */
+ na_size_t max_unexpected_size;
+
+ /* Max expected size hint that can be passed to control the size of
+ * expected messages. Note that the underlying plugin library may switch
+ * to different transfer protocols depending on the message size that is
+ * used. */
+ na_size_t max_expected_size;
+
+ /* Progress mode flag. Setting NA_NO_BLOCK will force busy-spin on progress
+ * and remove any wait/notification calls. */
+ na_uint32_t progress_mode;
+
+ /* Maximum number of contexts that are expected to be created. */
+ na_uint8_t max_contexts;
+
+ /* Thread mode flags can be used to relax thread-safety when it is not
+ * needed. When setting NA_THREAD_MODE_SINGLE, only a single thread should
+ * access both NA classes and contexts at a time. */
+ na_uint8_t thread_mode;
+};
+
+/* Segment */
+struct na_segment {
+ na_ptr_t base; /* Address of the segment */
+ na_size_t len; /* Size of the segment in bytes */
+};
+
+/* Return codes:
+ * Functions return 0 for success or corresponding return code */
+#define NA_RETURN_VALUES \
+ X(NA_SUCCESS) /*!< operation succeeded */ \
+ X(NA_PERMISSION) /*!< operation not permitted */ \
+ X(NA_NOENTRY) /*!< no such file or directory */ \
+ X(NA_INTERRUPT) /*!< operation interrupted */ \
+ X(NA_AGAIN) /*!< operation must be retried */ \
+ X(NA_NOMEM) /*!< out of memory */ \
+ X(NA_ACCESS) /*!< permission denied */ \
+ X(NA_FAULT) /*!< bad address */ \
+ X(NA_BUSY) /*!< device or resource busy */ \
+ X(NA_EXIST) /*!< entry already exists */ \
+ X(NA_NODEV) /*!< no such device */ \
+ X(NA_INVALID_ARG) /*!< invalid argument */ \
+ X(NA_PROTOCOL_ERROR) /*!< protocol error */ \
+ X(NA_OVERFLOW) /*!< value too large */ \
+ X(NA_MSGSIZE) /*!< message size too long */ \
+ X(NA_PROTONOSUPPORT) /*!< protocol not supported */ \
+ X(NA_OPNOTSUPPORTED) /*!< operation not supported on endpoint */ \
+ X(NA_ADDRINUSE) /*!< address already in use */ \
+ X(NA_ADDRNOTAVAIL) /*!< cannot assign requested address */ \
+ X(NA_HOSTUNREACH) /*!< cannot reach host during operation */ \
+ X(NA_TIMEOUT) /*!< operation reached timeout */ \
+ X(NA_CANCELED) /*!< operation canceled */ \
+ X(NA_RETURN_MAX)
+
+#define X(a) a,
+typedef enum na_return { NA_RETURN_VALUES } na_return_t;
+#undef X
+
+/* Callback operation type */
+#define NA_CB_TYPES \
+ X(NA_CB_SEND_UNEXPECTED) /*!< unexpected send callback */ \
+ X(NA_CB_RECV_UNEXPECTED) /*!< unexpected recv callback */ \
+ X(NA_CB_SEND_EXPECTED) /*!< expected send callback */ \
+ X(NA_CB_RECV_EXPECTED) /*!< expected recv callback */ \
+ X(NA_CB_PUT) /*!< put callback */ \
+ X(NA_CB_GET) /*!< get callback */ \
+ X(NA_CB_MAX)
+
+#define X(a) a,
+typedef enum na_cb_type { NA_CB_TYPES } na_cb_type_t;
+#undef X
+
+/* Callback info structs */
+struct na_cb_info_recv_unexpected {
+ na_size_t actual_buf_size;
+ na_addr_t source;
+ na_tag_t tag;
+};
+
+struct na_cb_info_recv_expected {
+ na_size_t actual_buf_size;
+};
+
+/* Callback info struct */
+struct na_cb_info {
+ union { /* Union of callback info structures */
+ struct na_cb_info_recv_unexpected recv_unexpected;
+ struct na_cb_info_recv_expected recv_expected;
+ } info;
+ void * arg; /* User data */
+ na_cb_type_t type; /* Callback type */
+ na_return_t ret; /* Return value */
+};
+
+/* Callback type */
+typedef int (*na_cb_t)(const struct na_cb_info *callback_info);
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Constant values */
+#define NA_ADDR_NULL ((na_addr_t)0)
+#define NA_MEM_HANDLE_NULL ((na_mem_handle_t)0)
+
+/* Max timeout */
+#define NA_MAX_IDLE_TIME (3600 * 1000)
+
+/* Context ID max value
+ * \remark This is not the user limit but only the limit imposed by the type */
+#define NA_CONTEXT_ID_MAX UINT8_MAX
+
+/* Tag max value
+ * \remark This is not the user limit but only the limit imposed by the type */
+#define NA_TAG_MAX UINT_MAX
+
+/* The memory attributes associated with the memory handle
+ * can be defined as read only, write only or read/write */
+#define NA_MEM_READ_ONLY 0x01
+#define NA_MEM_WRITE_ONLY 0x02
+#define NA_MEM_READWRITE 0x03
+
+/* Progress modes */
+#define NA_NO_BLOCK 0x01 /*!< no blocking progress */
+#define NA_NO_RETRY 0x02 /*!< no retry of operations in progress */
+
+/* Thread modes (default is thread-safe) */
+#define NA_THREAD_MODE_SINGLE_CLS (0x01) /*!< only one thread will access class */
+#define NA_THREAD_MODE_SINGLE_CTX (0x02) /*!< only one thread will access context */
+#define NA_THREAD_MODE_SINGLE (NA_THREAD_MODE_SINGLE_CLS | NA_THREAD_MODE_SINGLE_CTX)
+
+/* NA init info initializer */
+#define NA_INIT_INFO_INITIALIZER \
+ (struct na_init_info) \
+ { \
+ .ip_subnet = NULL, .auth_key = NULL, .max_unexpected_size = 0, .max_expected_size = 0, \
+ .progress_mode = 0, .max_contexts = 1, .thread_mode = 0 \
+ }
+
+#endif /* NA_TYPES_H */
diff --git a/src/mercury/src/util/.deps/.dirstamp b/src/mercury/src/util/.deps/.dirstamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/mercury/src/util/.deps/.dirstamp
diff --git a/src/mercury/src/util/.deps/mercury_atomic_queue.Plo b/src/mercury/src/util/.deps/mercury_atomic_queue.Plo
new file mode 100644
index 0000000..481e5f0
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_atomic_queue.Plo
@@ -0,0 +1,357 @@
+mercury/src/util/mercury_atomic_queue.lo: \
+ mercury/src/util/mercury_atomic_queue.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_atomic_queue.h \
+ mercury/src/util/mercury_atomic.h mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ mercury/src/util/mercury_mem.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/immintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/mmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/xmmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/mm_malloc.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/bits/types/locale_t.h \
+ /usr/include/bits/types/__locale_t.h /usr/include/sys/types.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/clockid_t.h \
+ /usr/include/bits/types/time_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/struct_timespec.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/alloca.h \
+ /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/emmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/pmmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/tmmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/smmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/popcntintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/wmmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avxintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx2intrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512fintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512erintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512pfintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512cdintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vlintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512bwintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512dqintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vlbwintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vldqintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512ifmaintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512ifmavlintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmiintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmivlintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx5124fmapsintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx5124vnniwintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vpopcntdqintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmi2intrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmi2vlintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vnniintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vnnivlintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vpopcntdqvlintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/avx512bitalgintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/shaintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/lzcntintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/bmiintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/bmi2intrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/fmaintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/f16cintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/rtmintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/xtestintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/cetintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/gfniintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/vaesintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/vpclmulqdqintrin.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/movdirintrin.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/struct_itimerspec.h /usr/include/bits/setjmp.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_atomic_queue.h:
+
+mercury/src/util/mercury_atomic.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+mercury/src/util/mercury_mem.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/immintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/mmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/xmmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/mm_malloc.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/emmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/pmmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/tmmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/smmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/popcntintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/wmmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avxintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx2intrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512fintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512erintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512pfintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512cdintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vlintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512bwintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512dqintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vlbwintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vldqintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512ifmaintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512ifmavlintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmiintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmivlintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx5124fmapsintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx5124vnniwintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vpopcntdqintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmi2intrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vbmi2vlintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vnniintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vnnivlintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512vpopcntdqvlintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/avx512bitalgintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/shaintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/lzcntintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/bmiintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/bmi2intrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/fmaintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/f16cintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/rtmintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/xtestintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/cetintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/gfniintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/vaesintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/vpclmulqdqintrin.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/movdirintrin.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/setjmp.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
diff --git a/src/mercury/src/util/.deps/mercury_dlog.Plo b/src/mercury/src/util/.deps/mercury_dlog.Plo
new file mode 100644
index 0000000..eef468a
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_dlog.Plo
@@ -0,0 +1,214 @@
+mercury/src/util/mercury_dlog.lo: mercury/src/util/mercury_dlog.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_dlog.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ mercury/src/util/mercury_list.h mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_time.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h /usr/include/inttypes.h /usr/include/stdlib.h \
+ /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
+ /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \
+ /usr/include/sys/types.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
+ /usr/include/bits/types/__sigset_t.h /usr/include/alloca.h \
+ /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
+ /usr/include/string.h /usr/include/strings.h /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
+ /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
+ /usr/include/bits/getopt_core.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_dlog.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+mercury/src/util/mercury_list.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/usr/include/inttypes.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
+
+/usr/include/unistd.h:
+
+/usr/include/bits/posix_opt.h:
+
+/usr/include/bits/environments.h:
+
+/usr/include/bits/confname.h:
+
+/usr/include/bits/getopt_posix.h:
+
+/usr/include/bits/getopt_core.h:
diff --git a/src/mercury/src/util/.deps/mercury_event.Plo b/src/mercury/src/util/.deps/mercury_event.Plo
new file mode 100644
index 0000000..720a823
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_event.Plo
@@ -0,0 +1,219 @@
+mercury/src/util/mercury_event.lo: mercury/src/util/mercury_event.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_event.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h /usr/include/errno.h \
+ /usr/include/bits/errno.h /usr/include/linux/errno.h \
+ /usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
+ /usr/include/asm-generic/errno-base.h /usr/include/bits/types/error_t.h \
+ /usr/include/string.h /usr/include/bits/types/locale_t.h \
+ /usr/include/bits/types/__locale_t.h /usr/include/strings.h \
+ /usr/include/unistd.h /usr/include/bits/posix_opt.h \
+ /usr/include/bits/environments.h /usr/include/bits/confname.h \
+ /usr/include/bits/getopt_posix.h /usr/include/bits/getopt_core.h \
+ /usr/include/sys/eventfd.h /usr/include/bits/eventfd.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h \
+ /usr/include/pthread.h /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_event.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+/usr/include/errno.h:
+
+/usr/include/bits/errno.h:
+
+/usr/include/linux/errno.h:
+
+/usr/include/asm/errno.h:
+
+/usr/include/asm-generic/errno.h:
+
+/usr/include/asm-generic/errno-base.h:
+
+/usr/include/bits/types/error_t.h:
+
+/usr/include/string.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/strings.h:
+
+/usr/include/unistd.h:
+
+/usr/include/bits/posix_opt.h:
+
+/usr/include/bits/environments.h:
+
+/usr/include/bits/confname.h:
+
+/usr/include/bits/getopt_posix.h:
+
+/usr/include/bits/getopt_core.h:
+
+/usr/include/sys/eventfd.h:
+
+/usr/include/bits/eventfd.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
diff --git a/src/mercury/src/util/.deps/mercury_hash_table.Plo b/src/mercury/src/util/.deps/mercury_hash_table.Plo
new file mode 100644
index 0000000..2b2bef8
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_hash_table.Plo
@@ -0,0 +1,125 @@
+mercury/src/util/mercury_hash_table.lo: \
+ mercury/src/util/mercury_hash_table.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_hash_table.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h /usr/include/stdlib.h \
+ /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
+ /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/sys/types.h /usr/include/bits/types/clock_t.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/timer_t.h /usr/include/endian.h \
+ /usr/include/bits/endian.h /usr/include/bits/byteswap.h \
+ /usr/include/bits/uintn-identity.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
+ /usr/include/bits/types/__sigset_t.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/struct_timespec.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/alloca.h \
+ /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
+ /usr/include/string.h /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_hash_table.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.deps/mercury_log.Plo b/src/mercury/src/util/.deps/mercury_log.Plo
new file mode 100644
index 0000000..ce22eff
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_log.Plo
@@ -0,0 +1,204 @@
+mercury/src/util/mercury_log.lo: mercury/src/util/mercury_log.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_log.h \
+ mercury/src/util/mercury_dlog.h mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ mercury/src/util/mercury_list.h mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_time.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h mercury/src/util/mercury_queue.h \
+ /usr/include/ctype.h /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h /usr/include/string.h \
+ /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_log.h:
+
+mercury/src/util/mercury_dlog.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+mercury/src/util/mercury_list.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+mercury/src/util/mercury_queue.h:
+
+/usr/include/ctype.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.deps/mercury_mem.Plo b/src/mercury/src/util/.deps/mercury_mem.Plo
new file mode 100644
index 0000000..9b99a9b
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_mem.Plo
@@ -0,0 +1,276 @@
+mercury/src/util/mercury_mem.lo: mercury/src/util/mercury_mem.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_mem.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h \
+ /usr/include/pthread.h /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/errno.h /usr/include/bits/errno.h \
+ /usr/include/linux/errno.h /usr/include/asm/errno.h \
+ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+ /usr/include/bits/types/error_t.h /usr/include/fcntl.h \
+ /usr/include/bits/fcntl.h /usr/include/bits/fcntl-linux.h \
+ /usr/include/bits/types/struct_iovec.h /usr/include/linux/falloc.h \
+ /usr/include/bits/stat.h /usr/include/string.h /usr/include/strings.h \
+ /usr/include/sys/mman.h /usr/include/bits/mman.h \
+ /usr/include/bits/mman-linux.h /usr/include/bits/mman-shared.h \
+ /usr/include/sys/stat.h /usr/include/bits/statx.h \
+ /usr/include/sys/types.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
+ /usr/include/bits/types/__sigset_t.h /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
+ /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
+ /usr/include/bits/getopt_core.h /usr/include/stdlib.h \
+ /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
+ /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_mem.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/errno.h:
+
+/usr/include/bits/errno.h:
+
+/usr/include/linux/errno.h:
+
+/usr/include/asm/errno.h:
+
+/usr/include/asm-generic/errno.h:
+
+/usr/include/asm-generic/errno-base.h:
+
+/usr/include/bits/types/error_t.h:
+
+/usr/include/fcntl.h:
+
+/usr/include/bits/fcntl.h:
+
+/usr/include/bits/fcntl-linux.h:
+
+/usr/include/bits/types/struct_iovec.h:
+
+/usr/include/linux/falloc.h:
+
+/usr/include/bits/stat.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
+
+/usr/include/sys/mman.h:
+
+/usr/include/bits/mman.h:
+
+/usr/include/bits/mman-linux.h:
+
+/usr/include/bits/mman-shared.h:
+
+/usr/include/sys/stat.h:
+
+/usr/include/bits/statx.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/unistd.h:
+
+/usr/include/bits/posix_opt.h:
+
+/usr/include/bits/environments.h:
+
+/usr/include/bits/confname.h:
+
+/usr/include/bits/getopt_posix.h:
+
+/usr/include/bits/getopt_core.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
diff --git a/src/mercury/src/util/.deps/mercury_mem_pool.Plo b/src/mercury/src/util/.deps/mercury_mem_pool.Plo
new file mode 100644
index 0000000..970caa7
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_mem_pool.Plo
@@ -0,0 +1,228 @@
+mercury/src/util/mercury_mem_pool.lo: mercury/src/util/mercury_mem_pool.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_mem_pool.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_mem.h \
+ mercury/src/util/mercury_queue.h \
+ mercury/src/util/mercury_thread_condition.h \
+ mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h mercury/src/util/mercury_thread_spin.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/string.h /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_mem_pool.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_mem.h:
+
+mercury/src/util/mercury_queue.h:
+
+mercury/src/util/mercury_thread_condition.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+mercury/src/util/mercury_thread_spin.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.deps/mercury_poll.Plo b/src/mercury/src/util/.deps/mercury_poll.Plo
new file mode 100644
index 0000000..91ff893
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_poll.Plo
@@ -0,0 +1,262 @@
+mercury/src/util/mercury_poll.lo: mercury/src/util/mercury_poll.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_poll.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_event.h \
+ /usr/include/errno.h /usr/include/bits/errno.h \
+ /usr/include/linux/errno.h /usr/include/asm/errno.h \
+ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
+ /usr/include/bits/types/error_t.h /usr/include/string.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/strings.h /usr/include/unistd.h \
+ /usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
+ /usr/include/bits/confname.h /usr/include/bits/getopt_posix.h \
+ /usr/include/bits/getopt_core.h /usr/include/sys/eventfd.h \
+ /usr/include/bits/eventfd.h mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h /usr/include/sys/epoll.h \
+ /usr/include/bits/epoll.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_poll.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_event.h:
+
+/usr/include/errno.h:
+
+/usr/include/bits/errno.h:
+
+/usr/include/linux/errno.h:
+
+/usr/include/asm/errno.h:
+
+/usr/include/asm-generic/errno.h:
+
+/usr/include/asm-generic/errno-base.h:
+
+/usr/include/bits/types/error_t.h:
+
+/usr/include/string.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/strings.h:
+
+/usr/include/unistd.h:
+
+/usr/include/bits/posix_opt.h:
+
+/usr/include/bits/environments.h:
+
+/usr/include/bits/confname.h:
+
+/usr/include/bits/getopt_posix.h:
+
+/usr/include/bits/getopt_core.h:
+
+/usr/include/sys/eventfd.h:
+
+/usr/include/bits/eventfd.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/sys/epoll.h:
+
+/usr/include/bits/epoll.h:
diff --git a/src/mercury/src/util/.deps/mercury_request.Plo b/src/mercury/src/util/.deps/mercury_request.Plo
new file mode 100644
index 0000000..ed207e4
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_request.Plo
@@ -0,0 +1,220 @@
+mercury/src/util/mercury_request.lo: mercury/src/util/mercury_request.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_request.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ mercury/src/util/mercury_thread_condition.h \
+ mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h mercury/src/util/mercury_time.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_request.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+mercury/src/util/mercury_thread_condition.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+mercury/src/util/mercury_time.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
diff --git a/src/mercury/src/util/.deps/mercury_thread.Plo b/src/mercury/src/util/.deps/mercury_thread.Plo
new file mode 100644
index 0000000..b3bfed7
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_thread.Plo
@@ -0,0 +1,113 @@
+mercury/src/util/mercury_thread.lo: mercury/src/util/mercury_thread.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_thread.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_thread.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
diff --git a/src/mercury/src/util/.deps/mercury_thread_condition.Plo b/src/mercury/src/util/.deps/mercury_thread_condition.Plo
new file mode 100644
index 0000000..779d371
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_thread_condition.Plo
@@ -0,0 +1,153 @@
+mercury/src/util/mercury_thread_condition.lo: \
+ mercury/src/util/mercury_thread_condition.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_thread_condition.h \
+ mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_thread_condition.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
diff --git a/src/mercury/src/util/.deps/mercury_thread_mutex.Plo b/src/mercury/src/util/.deps/mercury_thread_mutex.Plo
new file mode 100644
index 0000000..e7439a8
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_thread_mutex.Plo
@@ -0,0 +1,183 @@
+mercury/src/util/mercury_thread_mutex.lo: \
+ mercury/src/util/mercury_thread_mutex.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/string.h /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.deps/mercury_thread_pool.Plo b/src/mercury/src/util/.deps/mercury_thread_pool.Plo
new file mode 100644
index 0000000..72cae2e
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_thread_pool.Plo
@@ -0,0 +1,220 @@
+mercury/src/util/mercury_thread_pool.lo: \
+ mercury/src/util/mercury_thread_pool.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_thread_pool.h mercury/src/util/mercury_queue.h \
+ mercury/src/util/mercury_thread.h mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_thread_condition.h \
+ mercury/src/util/mercury_thread_mutex.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/stdlib.h \
+ /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
+ /usr/include/bits/floatn.h /usr/include/bits/floatn-common.h \
+ /usr/include/sys/types.h /usr/include/sys/select.h \
+ /usr/include/bits/select.h /usr/include/bits/types/sigset_t.h \
+ /usr/include/bits/types/__sigset_t.h /usr/include/alloca.h \
+ /usr/include/bits/stdlib-bsearch.h /usr/include/bits/stdlib-float.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_thread_pool.h:
+
+mercury/src/util/mercury_queue.h:
+
+mercury/src/util/mercury_thread.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_thread_condition.h:
+
+mercury/src/util/mercury_thread_mutex.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
diff --git a/src/mercury/src/util/.deps/mercury_thread_rwlock.Plo b/src/mercury/src/util/.deps/mercury_thread_rwlock.Plo
new file mode 100644
index 0000000..7bcb1a0
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_thread_rwlock.Plo
@@ -0,0 +1,186 @@
+mercury/src/util/mercury_thread_rwlock.lo: \
+ mercury/src/util/mercury_thread_rwlock.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_thread_rwlock.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/string.h /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_thread_rwlock.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.deps/mercury_thread_spin.Plo b/src/mercury/src/util/.deps/mercury_thread_spin.Plo
new file mode 100644
index 0000000..8cf0151
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_thread_spin.Plo
@@ -0,0 +1,186 @@
+mercury/src/util/mercury_thread_spin.lo: \
+ mercury/src/util/mercury_thread_spin.c /usr/include/stdc-predef.h \
+ mercury/src/util/mercury_thread_spin.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h \
+ mercury/src/util/mercury_thread_annotation.h /usr/include/pthread.h \
+ /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/string.h /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_thread_spin.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.deps/mercury_util.Plo b/src/mercury/src/util/.deps/mercury_util.Plo
new file mode 100644
index 0000000..0efc265
--- /dev/null
+++ b/src/mercury/src/util/.deps/mercury_util.Plo
@@ -0,0 +1,214 @@
+mercury/src/util/mercury_util.lo: mercury/src/util/mercury_util.c \
+ /usr/include/stdc-predef.h mercury/src/util/mercury_util.h \
+ mercury/src/util/mercury_util_config.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h \
+ /usr/include/stdint.h /usr/include/bits/libc-header-start.h \
+ /usr/include/features.h /usr/include/sys/cdefs.h \
+ /usr/include/bits/wordsize.h /usr/include/bits/long-double.h \
+ /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
+ /usr/include/bits/types.h /usr/include/bits/typesizes.h \
+ /usr/include/bits/wchar.h /usr/include/bits/stdint-intn.h \
+ /usr/include/bits/stdint-uintn.h mercury/src/util/mercury_util_error.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h \
+ /usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h \
+ /usr/include/pthread.h /usr/include/endian.h /usr/include/bits/endian.h \
+ /usr/include/bits/byteswap.h /usr/include/bits/uintn-identity.h \
+ /usr/include/sched.h /usr/include/bits/types/time_t.h \
+ /usr/include/bits/types/struct_timespec.h /usr/include/bits/sched.h \
+ /usr/include/bits/types/struct_sched_param.h /usr/include/bits/cpu-set.h \
+ /usr/include/time.h /usr/include/bits/time.h /usr/include/bits/timex.h \
+ /usr/include/bits/types/struct_timeval.h \
+ /usr/include/bits/types/clock_t.h /usr/include/bits/types/struct_tm.h \
+ /usr/include/bits/types/clockid_t.h /usr/include/bits/types/timer_t.h \
+ /usr/include/bits/types/struct_itimerspec.h \
+ /usr/include/bits/types/locale_t.h /usr/include/bits/types/__locale_t.h \
+ /usr/include/bits/pthreadtypes.h /usr/include/bits/thread-shared-types.h \
+ /usr/include/bits/pthreadtypes-arch.h /usr/include/bits/setjmp.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h \
+ /usr/include/stdio.h /usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h \
+ /usr/include/bits/types/__fpos_t.h /usr/include/bits/types/__mbstate_t.h \
+ /usr/include/bits/types/__fpos64_t.h /usr/include/bits/types/__FILE.h \
+ /usr/include/bits/types/FILE.h /usr/include/bits/types/struct_FILE.h \
+ /usr/include/bits/types/cookie_io_functions_t.h \
+ /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
+ /usr/include/bits/stdio.h \
+ /home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h \
+ /usr/include/stdlib.h /usr/include/bits/waitflags.h \
+ /usr/include/bits/waitstatus.h /usr/include/bits/floatn.h \
+ /usr/include/bits/floatn-common.h /usr/include/sys/types.h \
+ /usr/include/sys/select.h /usr/include/bits/select.h \
+ /usr/include/bits/types/sigset_t.h /usr/include/bits/types/__sigset_t.h \
+ /usr/include/alloca.h /usr/include/bits/stdlib-bsearch.h \
+ /usr/include/bits/stdlib-float.h /usr/include/string.h \
+ /usr/include/strings.h
+
+/usr/include/stdc-predef.h:
+
+mercury/src/util/mercury_util.h:
+
+mercury/src/util/mercury_util_config.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stddef.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdint.h:
+
+/usr/include/stdint.h:
+
+/usr/include/bits/libc-header-start.h:
+
+/usr/include/features.h:
+
+/usr/include/sys/cdefs.h:
+
+/usr/include/bits/wordsize.h:
+
+/usr/include/bits/long-double.h:
+
+/usr/include/gnu/stubs.h:
+
+/usr/include/gnu/stubs-64.h:
+
+/usr/include/bits/types.h:
+
+/usr/include/bits/typesizes.h:
+
+/usr/include/bits/wchar.h:
+
+/usr/include/bits/stdint-intn.h:
+
+/usr/include/bits/stdint-uintn.h:
+
+mercury/src/util/mercury_util_error.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_log.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_dlog.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_util_config.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_atomic.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdatomic.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_list.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_mutex.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_thread_annotation.h:
+
+/usr/include/pthread.h:
+
+/usr/include/endian.h:
+
+/usr/include/bits/endian.h:
+
+/usr/include/bits/byteswap.h:
+
+/usr/include/bits/uintn-identity.h:
+
+/usr/include/sched.h:
+
+/usr/include/bits/types/time_t.h:
+
+/usr/include/bits/types/struct_timespec.h:
+
+/usr/include/bits/sched.h:
+
+/usr/include/bits/types/struct_sched_param.h:
+
+/usr/include/bits/cpu-set.h:
+
+/usr/include/time.h:
+
+/usr/include/bits/time.h:
+
+/usr/include/bits/timex.h:
+
+/usr/include/bits/types/struct_timeval.h:
+
+/usr/include/bits/types/clock_t.h:
+
+/usr/include/bits/types/struct_tm.h:
+
+/usr/include/bits/types/clockid_t.h:
+
+/usr/include/bits/types/timer_t.h:
+
+/usr/include/bits/types/struct_itimerspec.h:
+
+/usr/include/bits/types/locale_t.h:
+
+/usr/include/bits/types/__locale_t.h:
+
+/usr/include/bits/pthreadtypes.h:
+
+/usr/include/bits/thread-shared-types.h:
+
+/usr/include/bits/pthreadtypes-arch.h:
+
+/usr/include/bits/setjmp.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_time.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-redhat-linux/8/include/stdarg.h:
+
+/usr/include/bits/types/__fpos_t.h:
+
+/usr/include/bits/types/__mbstate_t.h:
+
+/usr/include/bits/types/__fpos64_t.h:
+
+/usr/include/bits/types/__FILE.h:
+
+/usr/include/bits/types/FILE.h:
+
+/usr/include/bits/types/struct_FILE.h:
+
+/usr/include/bits/types/cookie_io_functions_t.h:
+
+/usr/include/bits/stdio_lim.h:
+
+/usr/include/bits/sys_errlist.h:
+
+/usr/include/bits/stdio.h:
+
+/home/riwarren/Sandbox/HDF5/GITHUB/SUBFILING/selection_io_with_subfiling_vfd/hdf5/src/mercury/include/mercury_queue.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/bits/waitflags.h:
+
+/usr/include/bits/waitstatus.h:
+
+/usr/include/bits/floatn.h:
+
+/usr/include/bits/floatn-common.h:
+
+/usr/include/sys/types.h:
+
+/usr/include/sys/select.h:
+
+/usr/include/bits/select.h:
+
+/usr/include/bits/types/sigset_t.h:
+
+/usr/include/bits/types/__sigset_t.h:
+
+/usr/include/alloca.h:
+
+/usr/include/bits/stdlib-bsearch.h:
+
+/usr/include/bits/stdlib-float.h:
+
+/usr/include/string.h:
+
+/usr/include/strings.h:
diff --git a/src/mercury/src/util/.dirstamp b/src/mercury/src/util/.dirstamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/mercury/src/util/.dirstamp
diff --git a/src/mercury/src/util/CMake/FindOPA.cmake b/src/mercury/src/util/CMake/FindOPA.cmake
new file mode 100644
index 0000000..c9e1aae
--- /dev/null
+++ b/src/mercury/src/util/CMake/FindOPA.cmake
@@ -0,0 +1,31 @@
+# - Try to find OPA
+# Once done this will define
+# OPA_FOUND - System has OpenPA
+# OPA_INCLUDE_DIRS - The OPA include directories
+# OPA_LIBRARIES - The libraries needed to use OPA
+
+find_package(PkgConfig)
+pkg_check_modules(PC_OPA QUIET openpa)
+# If openpa.pc cannot be found, try to look for mpich2-c.pc
+if(NOT PC_OPA_INCLUDEDIRS)
+ pkg_check_modules(PC_MPICH2_C QUIET mpich2-c)
+ set(PC_OPA_INCLUDEDIR ${PC_MPICH2_C_INCLUDEDIR})
+ set(PC_OPA_LIBDIR ${PC_MPICH2_C_LIBDIR})
+endif()
+
+find_path(OPA_INCLUDE_DIR opa_primitives.h
+ HINTS ${PC_OPA_INCLUDEDIR} ${PC_OPA_INCLUDE_DIRS})
+
+find_library(OPA_LIBRARY NAMES opa libopa
+ HINTS ${PC_OPA_LIBDIR} ${PC_OPA_LIBRARY_DIRS})
+
+set(OPA_LIBRARIES ${OPA_LIBRARY})
+set(OPA_INCLUDE_DIRS ${OPA_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set OPA_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(OPA DEFAULT_MSG
+ OPA_LIBRARY OPA_INCLUDE_DIR)
+
+mark_as_advanced(OPA_INCLUDE_DIR OPA_LIBRARY)
diff --git a/src/mercury/src/util/CMakeLists.txt b/src/mercury/src/util/CMakeLists.txt
new file mode 100644
index 0000000..cf3621f
--- /dev/null
+++ b/src/mercury/src/util/CMakeLists.txt
@@ -0,0 +1,274 @@
+#------------------------------------------------------------------------------
+# Setup cmake module
+#------------------------------------------------------------------------------
+set(MERCURY_UTIL_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MERCURY_UTIL_CMAKE_DIR})
+
+#------------------------------------------------------------------------------
+# Include source and build directories
+#------------------------------------------------------------------------------
+set(MERCURY_UTIL_BUILD_INCLUDE_DEPENDENCIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+#------------------------------------------------------------------------------
+# External dependencies
+#------------------------------------------------------------------------------
+include(CheckCSourceCompiles)
+include(CheckIncludeFiles)
+include(CheckSymbolExists)
+include(CheckTypeSize)
+
+# Check for __attribute__((constructor))
+check_c_source_compiles(
+ "
+ static void test_constructor(void) __attribute__((constructor));
+ int main(void) {return 0;}
+ "
+ HG_UTIL_HAS_ATTR_CONSTRUCTOR
+)
+
+# Check for __attribute__((constructor(priority)))
+check_c_source_compiles(
+ "
+ static void test_constructor(void) __attribute__((constructor(101)));
+ int main(void) {return 0;}
+ "
+ HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+)
+
+# Threads
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+find_package(Threads REQUIRED)
+
+set(MERCURY_UTIL_EXT_LIB_DEPENDENCIES
+ ${MERCURY_UTIL_EXT_LIB_DEPENDENCIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+)
+if(CMAKE_USE_PTHREADS_INIT)
+ set(CMAKE_EXTRA_INCLUDE_FILES pthread.h)
+ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+
+ # Detect pthread_spinlock_t
+ check_type_size(pthread_spinlock_t HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+
+ # Use type size to check enum value
+ check_type_size(PTHREAD_MUTEX_ADAPTIVE_NP HG_UTIL_HAS_PTHREAD_MUTEX_ADAPTIVE_NP)
+
+ # Detect pthread_condattr_setclock
+ check_symbol_exists(pthread_condattr_setclock pthread.h
+ HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK)
+
+ unset(CMAKE_EXTRA_INCLUDE_FILES)
+ unset(CMAKE_REQUIRED_LIBRARIES)
+endif()
+
+# Rt
+if(NOT WIN32 AND NOT APPLE)
+ set(MERCURY_UTIL_EXT_LIB_DEPENDENCIES
+ ${MERCURY_UTIL_EXT_LIB_DEPENDENCIES}
+ -lrt
+ )
+endif()
+
+# Detect <time.h>
+check_include_files("time.h" HG_UTIL_HAS_TIME_H)
+if(HG_UTIL_HAS_TIME_H)
+ set(CMAKE_EXTRA_INCLUDE_FILES time.h)
+
+ # Detect clock_gettime
+ check_symbol_exists(clock_gettime time.h HG_UTIL_HAS_CLOCK_GETTIME)
+
+ # Use type size to check enum value
+ check_type_size(CLOCK_MONOTONIC_COARSE HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+
+ unset(CMAKE_EXTRA_INCLUDE_FILES)
+endif()
+
+# Debug
+if(MERCURY_ENABLE_DEBUG)
+ set(HG_UTIL_HAS_DEBUG 1)
+else()
+ set(HG_UTIL_HAS_DEBUG 0)
+endif()
+
+# Detect <sys/time.h>
+check_include_files("sys/time.h" HG_UTIL_HAS_SYSTIME_H)
+
+# Detect <sys/epoll.h>
+check_include_files("sys/epoll.h" HG_UTIL_HAS_SYSEPOLL_H)
+
+# Detect <sys/eventfd.h>
+check_include_files("sys/eventfd.h" HG_UTIL_HAS_SYSEVENTFD_H)
+if(HG_UTIL_HAS_SYSEVENTFD_H)
+ set(CMAKE_EXTRA_INCLUDE_FILES "sys/eventfd.h")
+ check_type_size(eventfd_t HG_UTIL_HAS_EVENTFD_T)
+endif()
+
+# Detect <sys/event.h>
+check_include_files("sys/event.h" HG_UTIL_HAS_SYSEVENT_H)
+
+# Atomics
+if(NOT WIN32)
+ # Detect stdatomic
+ check_include_files("stdatomic.h" HG_UTIL_HAS_STDATOMIC_H)
+ # Detect size of atomic_long
+ set(CMAKE_EXTRA_INCLUDE_FILES stdatomic.h)
+ check_type_size(atomic_long HG_UTIL_ATOMIC_LONG_WIDTH)
+ unset(CMAKE_EXTRA_INCLUDE_FILES)
+ # OpenPA
+ option(MERCURY_USE_OPA "Use OpenPA for atomics." OFF)
+ # Force use of OPA if <stdatomic.h> is not found
+ if(NOT HG_UTIL_HAS_STDATOMIC_H)
+ set(MERCURY_USE_OPA "ON" CACHE BOOL "Use OpenPA for atomics." FORCE)
+ endif()
+ mark_as_advanced(MERCURY_USE_OPA)
+ if(MERCURY_USE_OPA)
+ # Use OpenPA if stdatomic is not available
+ find_package(OPA REQUIRED)
+ message(STATUS "OPA include directory: ${OPA_INCLUDE_DIRS}")
+ set(HG_UTIL_HAS_OPA_PRIMITIVES_H 1)
+ set(MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES
+ ${MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES}
+ ${OPA_INCLUDE_DIRS}
+ )
+ endif()
+endif()
+
+# Colored output
+option(MERCURY_ENABLE_LOG_COLOR "Use colored output for log." OFF)
+if(MERCURY_ENABLE_LOG_COLOR)
+ set(HG_UTIL_HAS_LOG_COLOR 1)
+endif()
+mark_as_advanced(MERCURY_ENABLE_LOG_COLOR)
+
+#------------------------------------------------------------------------------
+# Configure module header files
+#------------------------------------------------------------------------------
+# Set unique var used in the autogenerated config file (symbol import/export)
+if(BUILD_SHARED_LIBS)
+ set(HG_UTIL_BUILD_SHARED_LIBS 1)
+ set(MERCURY_UTIL_LIBTYPE SHARED)
+else()
+ set(HG_UTIL_BUILD_SHARED_LIBS 0)
+ set(MERCURY_UTIL_LIBTYPE STATIC)
+endif()
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_util_config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/mercury_util_config.h
+)
+
+#------------------------------------------------------------------------------
+# Set sources
+#------------------------------------------------------------------------------
+set(MERCURY_UTIL_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_atomic_queue.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_dlog.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_event.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_hash_table.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_log.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_mem.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_mem_pool.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_poll.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_request.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_condition.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_mutex.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_pool.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_rwlock.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_spin.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_util.c
+)
+
+#------------------------------------------------------------------------------
+# Specify project public header files to be installed
+#------------------------------------------------------------------------------
+set(MERCURY_UTIL_PUBLIC_HEADERS
+ ${CMAKE_CURRENT_BINARY_DIR}/mercury_util_config.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_atomic.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_atomic_queue.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_dlog.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_event.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_hash_string.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_hash_table.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_list.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_log.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_mem.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_mem_pool.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_poll.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_queue.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_request.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_annotation.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_condition.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_mutex.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_pool.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_rwlock.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_thread_spin.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_time.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_util.h
+)
+
+#------------------------------------------------------------------------------
+# Specify project private header files
+#------------------------------------------------------------------------------
+set(MERCURY_UTIL_PRIVATE_HEADERS
+ ${CMAKE_CURRENT_SOURCE_DIR}/mercury_util_error.h
+)
+
+#----------------------------------------------------------------------------
+# Libraries
+#----------------------------------------------------------------------------
+
+# Clean up system include path first
+foreach(item ${MERCURY_SYSTEM_INCLUDE_PATH})
+ if(MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES)
+ list(REMOVE_ITEM MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES ${item})
+ endif()
+endforeach()
+
+# UTIL
+add_library(mercury_util ${MERCURY_UTIL_SRCS}
+ ${MERCURY_UTIL_PRIVATE_HEADERS} ${MERCURY_UTIL_PUBLIC_HEADERS}
+)
+if(THREADS_HAVE_PTHREAD_ARG)
+ target_compile_options(mercury_util PUBLIC "${CMAKE_THREAD_LIBS_INIT}")
+endif()
+target_include_directories(mercury_util
+ PUBLIC "$<BUILD_INTERFACE:${MERCURY_UTIL_BUILD_INCLUDE_DEPENDENCIES}>"
+ $<INSTALL_INTERFACE:${MERCURY_INSTALL_INCLUDE_INTERFACE}>
+)
+target_include_directories(mercury_util
+ SYSTEM PUBLIC ${MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES}
+)
+target_link_libraries(mercury_util ${MERCURY_UTIL_EXT_LIB_DEPENDENCIES})
+mercury_set_lib_options(mercury_util "mercury_util" ${MERCURY_UTIL_LIBTYPE})
+if(MERCURY_ENABLE_COVERAGE)
+ set_coverage_flags(mercury_util)
+endif()
+set_target_properties(mercury_util PROPERTIES
+ PUBLIC_HEADER "${MERCURY_UTIL_PUBLIC_HEADERS}"
+)
+
+#---------------------------------------------------------------------------
+# Add Target(s) to CMake Install
+#---------------------------------------------------------------------------
+install(
+ TARGETS
+ mercury_util
+ EXPORT
+ ${MERCURY_EXPORTED_TARGETS}
+ LIBRARY DESTINATION ${MERCURY_INSTALL_LIB_DIR}
+ ARCHIVE DESTINATION ${MERCURY_INSTALL_LIB_DIR}
+ PUBLIC_HEADER DESTINATION ${MERCURY_INSTALL_INCLUDE_DIR}
+ RUNTIME DESTINATION ${MERCURY_INSTALL_BIN_DIR}
+)
+
+#------------------------------------------------------------------------------
+# Set variables for parent scope
+#------------------------------------------------------------------------------
+set(MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES ${MERCURY_UTIL_EXT_INCLUDE_DEPENDENCIES} PARENT_SCOPE)
+set(MERCURY_UTIL_EXT_LIB_DEPENDENCIES ${MERCURY_UTIL_EXT_LIB_DEPENDENCIES} PARENT_SCOPE)
diff --git a/src/mercury/src/util/mercury_atomic.h b/src/mercury/src/util/mercury_atomic.h
new file mode 100644
index 0000000..d5a1417
--- /dev/null
+++ b/src/mercury/src/util/mercury_atomic.h
@@ -0,0 +1,625 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_ATOMIC_H
+#define MERCURY_ATOMIC_H
+
+#include "mercury_util_config.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+typedef struct {
+ volatile LONG value;
+} hg_atomic_int32_t;
+typedef struct {
+ volatile LONGLONG value;
+} hg_atomic_int64_t;
+#define HG_ATOMIC_VAR_INIT(x) \
+ { \
+ (x) \
+ }
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+#include <opa_primitives.h>
+typedef OPA_int_t hg_atomic_int32_t;
+typedef OPA_ptr_t hg_atomic_int64_t; /* OPA has only limited 64-bit support */
+#define HG_ATOMIC_VAR_INIT(x) OPA_PTR_T_INITIALIZER(x)
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+#ifndef __cplusplus
+#include <stdatomic.h>
+typedef atomic_int hg_atomic_int32_t;
+#if (HG_UTIL_ATOMIC_LONG_WIDTH == 8) && !defined(__APPLE__)
+typedef atomic_long hg_atomic_int64_t;
+#else
+typedef atomic_llong hg_atomic_int64_t;
+#endif
+#else
+#include <atomic>
+typedef std::atomic_int hg_atomic_int32_t;
+#if (HG_UTIL_ATOMIC_LONG_WIDTH == 8) && !defined(__APPLE__)
+typedef std::atomic_long hg_atomic_int64_t;
+#else
+typedef std::atomic_llong hg_atomic_int64_t;
+#endif
+using std::atomic_fetch_add_explicit;
+using std::atomic_thread_fence;
+using std::memory_order_acq_rel;
+using std::memory_order_acquire;
+using std::memory_order_release;
+#endif
+#define HG_ATOMIC_VAR_INIT(x) ATOMIC_VAR_INIT(x)
+#elif defined(__APPLE__)
+#include <libkern/OSAtomic.h>
+typedef struct {
+ volatile hg_util_int32_t value;
+} hg_atomic_int32_t;
+typedef struct {
+ volatile hg_util_int64_t value;
+} hg_atomic_int64_t;
+#define HG_ATOMIC_VAR_INIT(x) \
+ { \
+ (x) \
+ }
+#else
+#error "Not supported on this platform."
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Init atomic value (32-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_init32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * Set atomic value (32-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_set32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * Get atomic value (32-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ *
+ * \return Value of the atomic integer
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_get32(hg_atomic_int32_t *ptr);
+
+/**
+ * Increment atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ *
+ * \return Incremented value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_incr32(hg_atomic_int32_t *ptr);
+
+/**
+ * Decrement atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ *
+ * \return Decremented value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_decr32(hg_atomic_int32_t *ptr);
+
+/**
+ * OR atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param value [IN] value to OR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_or32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * XOR atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param value [IN] value to XOR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_xor32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * AND atomic value (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param value [IN] value to AND with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int32_t hg_atomic_and32(hg_atomic_int32_t *ptr, hg_util_int32_t value);
+
+/**
+ * Compare and swap values (32-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic32 integer
+ * \param compare_value [IN] value to compare to
+ * \param swap_value [IN] value to swap with if ptr value is equal to
+ * compare value
+ *
+ * \return HG_UTIL_TRUE if swapped or HG_UTIL_FALSE
+ */
+static HG_UTIL_INLINE hg_util_bool_t hg_atomic_cas32(hg_atomic_int32_t *ptr, hg_util_int32_t compare_value,
+ hg_util_int32_t swap_value);
+
+/**
+ * Init atomic value (64-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic32 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_init64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * Set atomic value (64-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic64 integer
+ * \param value [IN] value
+ */
+static HG_UTIL_INLINE void hg_atomic_set64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * Get atomic value (64-bit integer).
+ *
+ * \param ptr [OUT] pointer to an atomic64 integer
+ *
+ * \return Value of the atomic integer
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_get64(hg_atomic_int64_t *ptr);
+
+/**
+ * Increment atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ *
+ * \return Incremented value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_incr64(hg_atomic_int64_t *ptr);
+
+/**
+ * Decrement atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ *
+ * \return Decremented value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_decr64(hg_atomic_int64_t *ptr);
+
+/**
+ * OR atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param value [IN] value to OR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_or64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * XOR atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param value [IN] value to XOR with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_xor64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * AND atomic value (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param value [IN] value to AND with
+ *
+ * \return Original value
+ */
+static HG_UTIL_INLINE hg_util_int64_t hg_atomic_and64(hg_atomic_int64_t *ptr, hg_util_int64_t value);
+
+/**
+ * Compare and swap values (64-bit integer).
+ *
+ * \param ptr [IN/OUT] pointer to an atomic64 integer
+ * \param compare_value [IN] value to compare to
+ * \param swap_value [IN] value to swap with if ptr value is equal to
+ * compare value
+ *
+ * \return HG_UTIL_TRUE if swapped or HG_UTIL_FALSE
+ */
+static HG_UTIL_INLINE hg_util_bool_t hg_atomic_cas64(hg_atomic_int64_t *ptr, hg_util_int64_t compare_value,
+ hg_util_int64_t swap_value);
+
+/**
+ * Memory barrier.
+ *
+ */
+static HG_UTIL_INLINE void hg_atomic_fence(void);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_init32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+#if defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ atomic_init(ptr, value);
+#else
+ hg_atomic_set32(ptr, value);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_set32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+#if defined(_WIN32)
+ ptr->value = value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ OPA_store_int(ptr, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_store_explicit(ptr, value, memory_order_release);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+#error "Not supported on this platform."
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_get32(hg_atomic_int32_t *ptr)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = ptr->value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = OPA_load_int(ptr);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_load_explicit(ptr, memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = ptr->value;
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_incr32(hg_atomic_int32_t *ptr)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedIncrementNoFence(&ptr->value);
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = OPA_fetch_and_incr_int(ptr) + 1;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_add_explicit(ptr, 1, memory_order_acq_rel) + 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicIncrement32(&ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_decr32(hg_atomic_int32_t *ptr)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedDecrementNoFence(&ptr->value);
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = OPA_fetch_and_decr_int(ptr) - 1;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_sub_explicit(ptr, 1, memory_order_acq_rel) - 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicDecrement32(&ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_or32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedOrNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_or_explicit(ptr, value, memory_order_acq_rel);
+#elif defined(__APPLE__)
+ ret = OSAtomicOr32Orig((uint32_t)value, (volatile uint32_t *)&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get32(ptr);
+ } while (!hg_atomic_cas32(ptr, ret, (ret | value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_xor32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedXorNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_xor_explicit(ptr, value, memory_order_acq_rel);
+#elif defined(__APPLE__)
+ ret = OSAtomicXor32Orig((uint32_t)value, (volatile uint32_t *)&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get32(ptr);
+ } while (!hg_atomic_cas32(ptr, ret, (ret ^ value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int32_t
+hg_atomic_and32(hg_atomic_int32_t *ptr, hg_util_int32_t value)
+{
+ hg_util_int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedAndNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_and_explicit(ptr, value, memory_order_acq_rel);
+#elif defined(__APPLE__)
+ ret = OSAtomicAnd32Orig((uint32_t)value, (volatile uint32_t *)&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get32(ptr);
+ } while (!hg_atomic_cas32(ptr, ret, (ret & value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_bool_t
+hg_atomic_cas32(hg_atomic_int32_t *ptr, hg_util_int32_t compare_value, hg_util_int32_t swap_value)
+{
+ hg_util_bool_t ret;
+
+#if defined(_WIN32)
+ ret = (compare_value == InterlockedCompareExchangeNoFence(&ptr->value, swap_value, compare_value));
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = (hg_util_bool_t)(compare_value == OPA_cas_int(ptr, compare_value, swap_value));
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_compare_exchange_strong_explicit(ptr, &compare_value, swap_value, memory_order_acq_rel,
+ memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = OSAtomicCompareAndSwap32(compare_value, swap_value, &ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_init64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+#if defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ atomic_init(ptr, value);
+#else
+ hg_atomic_set64(ptr, value);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_set64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+#if defined(_WIN32)
+ ptr->value = value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ OPA_store_ptr(ptr, (void *)value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_store_explicit(ptr, value, memory_order_release);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+#error "Not supported on this platform."
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_get64(hg_atomic_int64_t *ptr)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = ptr->value;
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = (hg_util_int64_t)OPA_load_ptr(ptr);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_load_explicit(ptr, memory_order_acquire);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_incr64(hg_atomic_int64_t *ptr)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedIncrementNoFence64(&ptr->value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_add_explicit(ptr, 1L, memory_order_acq_rel) + 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicIncrement64(&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, ret + 1));
+ ret++;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_decr64(hg_atomic_int64_t *ptr)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedDecrementNoFence64(&ptr->value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_sub_explicit(ptr, 1L, memory_order_acq_rel) - 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicDecrement64(&ptr->value);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, ret - 1));
+ ret--;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_or64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedOr64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_or_explicit(ptr, value, memory_order_acq_rel);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, (ret | value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_xor64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedXor64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_xor_explicit(ptr, value, memory_order_acq_rel);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, (ret ^ value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_int64_t
+hg_atomic_and64(hg_atomic_int64_t *ptr, hg_util_int64_t value)
+{
+ hg_util_int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedAnd64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H) && !defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = atomic_fetch_and_explicit(ptr, value, memory_order_acq_rel);
+#else
+ do {
+ ret = hg_atomic_get64(ptr);
+ } while (!hg_atomic_cas64(ptr, ret, (ret & value)));
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_bool_t
+hg_atomic_cas64(hg_atomic_int64_t *ptr, hg_util_int64_t compare_value, hg_util_int64_t swap_value)
+{
+ hg_util_bool_t ret;
+
+#if defined(_WIN32)
+ ret = (compare_value == InterlockedCompareExchangeNoFence64(&ptr->value, swap_value, compare_value));
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ ret = (hg_util_bool_t)(compare_value ==
+ (hg_util_int64_t)OPA_cas_ptr(ptr, (void *)compare_value, (void *)swap_value));
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_compare_exchange_strong_explicit(ptr, &compare_value, swap_value, memory_order_acq_rel,
+ memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = OSAtomicCompareAndSwap64(compare_value, swap_value, &ptr->value);
+#else
+#error "Not supported on this platform."
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_fence()
+{
+#if defined(_WIN32)
+ MemoryBarrier();
+#elif defined(HG_UTIL_HAS_OPA_PRIMITIVES_H)
+ OPA_read_write_barrier();
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_thread_fence(memory_order_acq_rel);
+#elif defined(__APPLE__)
+ OSMemoryBarrier();
+#else
+#error "Not supported on this platform."
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_ATOMIC_H */
diff --git a/src/mercury/src/util/mercury_atomic_queue.c b/src/mercury/src/util/mercury_atomic_queue.c
new file mode 100644
index 0000000..f76177b
--- /dev/null
+++ b/src/mercury/src/util/mercury_atomic_queue.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Implementation derived from:
+ * https://github.com/freebsd/freebsd/blob/master/sys/sys/buf_ring.h
+ *
+ * -
+ * Copyright (c) 2007-2009 Kip Macy <kmacy@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "mercury_atomic_queue.h"
+#include "mercury_util_error.h"
+
+#include <stdlib.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* From <sys/param.h> */
+#define powerof2(x) ((((x)-1) & (x)) == 0)
+
+/*---------------------------------------------------------------------------*/
+struct hg_atomic_queue *
+hg_atomic_queue_alloc(unsigned int count)
+{
+ struct hg_atomic_queue *hg_atomic_queue = NULL;
+
+ HG_UTIL_CHECK_ERROR_NORET(!powerof2(count), done, "atomic queue size must be power of 2");
+
+ hg_atomic_queue = hg_mem_aligned_alloc(HG_MEM_CACHE_LINE_SIZE, sizeof(struct hg_atomic_queue) +
+ count * sizeof(hg_atomic_int64_t));
+ HG_UTIL_CHECK_ERROR_NORET(hg_atomic_queue == NULL, done, "Could not allocate atomic queue");
+
+ hg_atomic_queue->prod_size = hg_atomic_queue->cons_size = count;
+ hg_atomic_queue->prod_mask = hg_atomic_queue->cons_mask = count - 1;
+ hg_atomic_init32(&hg_atomic_queue->prod_head, 0);
+ hg_atomic_init32(&hg_atomic_queue->cons_head, 0);
+ hg_atomic_init32(&hg_atomic_queue->prod_tail, 0);
+ hg_atomic_init32(&hg_atomic_queue->cons_tail, 0);
+
+done:
+ return hg_atomic_queue;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_atomic_queue_free(struct hg_atomic_queue *hg_atomic_queue)
+{
+ hg_mem_aligned_free(hg_atomic_queue);
+}
diff --git a/src/mercury/src/util/mercury_atomic_queue.h b/src/mercury/src/util/mercury_atomic_queue.h
new file mode 100644
index 0000000..61b5128
--- /dev/null
+++ b/src/mercury/src/util/mercury_atomic_queue.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Implementation derived from:
+ * https://github.com/freebsd/freebsd/blob/master/sys/sys/buf_ring.h
+ *
+ * -
+ * Copyright (c) 2007-2009 Kip Macy <kmacy@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef MERCURY_ATOMIC_QUEUE_H
+#define MERCURY_ATOMIC_QUEUE_H
+
+#include "mercury_atomic.h"
+#include "mercury_mem.h"
+
+/* For busy loop spinning */
+#ifndef cpu_spinwait
+#if defined(_WIN32)
+#define cpu_spinwait YieldProcessor
+#elif defined(__x86_64__) || defined(__i386__)
+#include <immintrin.h>
+#define cpu_spinwait _mm_pause
+#elif defined(__arm__)
+#define cpu_spinwait() __asm__ __volatile__("yield")
+#else
+#warning "Processor yield is not supported on this architecture."
+#define cpu_spinwait(x)
+#endif
+#endif
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+struct hg_atomic_queue {
+ hg_atomic_int32_t prod_head;
+ hg_atomic_int32_t prod_tail;
+ unsigned int prod_size;
+ unsigned int prod_mask;
+ hg_util_uint64_t drops;
+ hg_atomic_int32_t cons_head __attribute__((aligned(HG_MEM_CACHE_LINE_SIZE)));
+ hg_atomic_int32_t cons_tail;
+ unsigned int cons_size;
+ unsigned int cons_mask;
+ hg_atomic_int64_t ring[] __attribute__((aligned(HG_MEM_CACHE_LINE_SIZE)));
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Allocate a new queue that can hold \count elements.
+ *
+ * \param count [IN] maximum number of elements
+ *
+ * \return pointer to allocated queue or NULL on failure
+ */
+HG_UTIL_PUBLIC struct hg_atomic_queue *hg_atomic_queue_alloc(unsigned int count);
+
+/**
+ * Free an existing queue.
+ *
+ * \param hg_atomic_queue [IN] pointer to queue
+ */
+HG_UTIL_PUBLIC void hg_atomic_queue_free(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Push an entry to the queue.
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ * \param entry [IN] pointer to object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_atomic_queue_push(struct hg_atomic_queue *hg_atomic_queue, void *entry);
+
+/**
+ * Pop an entry from the queue (multi-consumer).
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return Pointer to popped object or NULL if queue is empty
+ */
+static HG_UTIL_INLINE void *hg_atomic_queue_pop_mc(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Pop an entry from the queue (single consumer).
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return Pointer to popped object or NULL if queue is empty
+ */
+static HG_UTIL_INLINE void *hg_atomic_queue_pop_sc(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Determine whether queue is empty.
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return HG_UTIL_TRUE if empty, HG_UTIL_FALSE if not
+ */
+static HG_UTIL_INLINE hg_util_bool_t hg_atomic_queue_is_empty(struct hg_atomic_queue *hg_atomic_queue);
+
+/**
+ * Determine number of entries in a queue.
+ *
+ * \param hg_atomic_queue [IN/OUT] pointer to queue
+ *
+ * \return Number of entries queued or 0 if none
+ */
+static HG_UTIL_INLINE unsigned int hg_atomic_queue_count(struct hg_atomic_queue *hg_atomic_queue);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_atomic_queue_push(struct hg_atomic_queue *hg_atomic_queue, void *entry)
+{
+ hg_util_int32_t prod_head, prod_next, cons_tail;
+
+ do {
+ prod_head = hg_atomic_get32(&hg_atomic_queue->prod_head);
+ prod_next = (prod_head + 1) & (int)hg_atomic_queue->prod_mask;
+ cons_tail = hg_atomic_get32(&hg_atomic_queue->cons_tail);
+
+ if (prod_next == cons_tail) {
+ hg_atomic_fence();
+ if (prod_head == hg_atomic_get32(&hg_atomic_queue->prod_head) &&
+ cons_tail == hg_atomic_get32(&hg_atomic_queue->cons_tail)) {
+ hg_atomic_queue->drops++;
+ /* Full */
+ return HG_UTIL_FAIL;
+ }
+ continue;
+ }
+ } while (!hg_atomic_cas32(&hg_atomic_queue->prod_head, prod_head, prod_next));
+
+ hg_atomic_set64(&hg_atomic_queue->ring[prod_head], (hg_util_int64_t)entry);
+
+ /*
+ * If there are other enqueues in progress
+ * that preceded us, we need to wait for them
+ * to complete
+ */
+ while (hg_atomic_get32(&hg_atomic_queue->prod_tail) != prod_head)
+ cpu_spinwait();
+
+ hg_atomic_set32(&hg_atomic_queue->prod_tail, prod_next);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_atomic_queue_pop_mc(struct hg_atomic_queue *hg_atomic_queue)
+{
+ hg_util_int32_t cons_head, cons_next;
+ void * entry = NULL;
+
+ do {
+ cons_head = hg_atomic_get32(&hg_atomic_queue->cons_head);
+ cons_next = (cons_head + 1) & (int)hg_atomic_queue->cons_mask;
+
+ if (cons_head == hg_atomic_get32(&hg_atomic_queue->prod_tail))
+ return NULL;
+ } while (!hg_atomic_cas32(&hg_atomic_queue->cons_head, cons_head, cons_next));
+
+ entry = (void *)hg_atomic_get64(&hg_atomic_queue->ring[cons_head]);
+
+ /*
+ * If there are other dequeues in progress
+ * that preceded us, we need to wait for them
+ * to complete
+ */
+ while (hg_atomic_get32(&hg_atomic_queue->cons_tail) != cons_head)
+ cpu_spinwait();
+
+ hg_atomic_set32(&hg_atomic_queue->cons_tail, cons_next);
+
+ return entry;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_atomic_queue_pop_sc(struct hg_atomic_queue *hg_atomic_queue)
+{
+ hg_util_int32_t cons_head, cons_next;
+ hg_util_int32_t prod_tail;
+ void * entry = NULL;
+
+ cons_head = hg_atomic_get32(&hg_atomic_queue->cons_head);
+ prod_tail = hg_atomic_get32(&hg_atomic_queue->prod_tail);
+ cons_next = (cons_head + 1) & (int)hg_atomic_queue->cons_mask;
+
+ if (cons_head == prod_tail)
+ /* Empty */
+ return NULL;
+
+ hg_atomic_set32(&hg_atomic_queue->cons_head, cons_next);
+
+ entry = (void *)hg_atomic_get64(&hg_atomic_queue->ring[cons_head]);
+
+ hg_atomic_set32(&hg_atomic_queue->cons_tail, cons_next);
+
+ return entry;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_util_bool_t
+hg_atomic_queue_is_empty(struct hg_atomic_queue *hg_atomic_queue)
+{
+ return (hg_atomic_get32(&hg_atomic_queue->cons_head) == hg_atomic_get32(&hg_atomic_queue->prod_tail));
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE unsigned int
+hg_atomic_queue_count(struct hg_atomic_queue *hg_atomic_queue)
+{
+ return ((hg_atomic_queue->prod_size + (unsigned int)hg_atomic_get32(&hg_atomic_queue->prod_tail) -
+ (unsigned int)hg_atomic_get32(&hg_atomic_queue->cons_tail)) &
+ hg_atomic_queue->prod_mask);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_ATOMIC_QUEUE_H */
diff --git a/src/mercury/src/util/mercury_dlog.c b/src/mercury/src/util/mercury_dlog.c
new file mode 100644
index 0000000..8146691
--- /dev/null
+++ b/src/mercury/src/util/mercury_dlog.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_dlog.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*---------------------------------------------------------------------------*/
+struct hg_dlog *
+hg_dlog_alloc(char *name, unsigned int lesize, int leloop)
+{
+ struct hg_dlog_entry *le;
+ struct hg_dlog * d;
+
+ le = malloc(sizeof(*le) * lesize);
+ if (!le)
+ return NULL;
+
+ d = malloc(sizeof(*d));
+ if (!d) {
+ free(le);
+ return NULL;
+ }
+
+ memset(d, 0, sizeof(*d));
+ snprintf(d->dlog_magic, sizeof(d->dlog_magic), "%s%s", HG_DLOG_STDMAGIC, name);
+ hg_thread_mutex_init(&d->dlock);
+ HG_LIST_INIT(&d->cnts32);
+ HG_LIST_INIT(&d->cnts64);
+ d->le = le;
+ d->lesize = lesize;
+ d->leloop = leloop;
+ d->mallocd = 1;
+
+ return d;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_free(struct hg_dlog *d)
+{
+ struct hg_dlog_dcount32 *cp32 = HG_LIST_FIRST(&d->cnts32);
+ struct hg_dlog_dcount64 *cp64 = HG_LIST_FIRST(&d->cnts64);
+
+ while (cp32) {
+ struct hg_dlog_dcount32 *cp = cp32;
+ cp32 = HG_LIST_NEXT(cp, l);
+ free(cp);
+ }
+ HG_LIST_INIT(&d->cnts32);
+
+ while (cp64) {
+ struct hg_dlog_dcount64 *cp = cp64;
+ cp64 = HG_LIST_NEXT(cp, l);
+ free(cp);
+ }
+ HG_LIST_INIT(&d->cnts64);
+
+ if (d->mallocd) {
+ free(d->le);
+ free(d);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_mkcount32(struct hg_dlog *d, hg_atomic_int32_t **cptr, const char *name, const char *descr)
+{
+ struct hg_dlog_dcount32 *dcnt;
+
+ hg_thread_mutex_lock(&d->dlock);
+ if (*cptr == NULL) {
+ dcnt = malloc(sizeof(*dcnt));
+ if (!dcnt) {
+ fprintf(stderr, "hd_dlog_mkcount: malloc of %s failed!", name);
+ abort();
+ }
+ dcnt->name = name;
+ dcnt->descr = descr;
+ hg_atomic_init32(&dcnt->c, 0);
+ HG_LIST_INSERT_HEAD(&d->cnts32, dcnt, l);
+ *cptr = &dcnt->c; /* set it in caller's variable */
+ }
+ hg_thread_mutex_unlock(&d->dlock);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_mkcount64(struct hg_dlog *d, hg_atomic_int64_t **cptr, const char *name, const char *descr)
+{
+ struct hg_dlog_dcount64 *dcnt;
+
+ hg_thread_mutex_lock(&d->dlock);
+ if (*cptr == NULL) {
+ dcnt = malloc(sizeof(*dcnt));
+ if (!dcnt) {
+ fprintf(stderr, "hd_dlog_mkcount: malloc of %s failed!", name);
+ abort();
+ }
+ dcnt->name = name;
+ dcnt->descr = descr;
+ hg_atomic_init64(&dcnt->c, 0);
+ HG_LIST_INSERT_HEAD(&d->cnts64, dcnt, l);
+ *cptr = &dcnt->c; /* set it in caller's variable */
+ }
+ hg_thread_mutex_unlock(&d->dlock);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_setlogstop(struct hg_dlog *d, int stop)
+{
+ d->lestop = stop; /* no need to lock */
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_resetlog(struct hg_dlog *d)
+{
+ hg_thread_mutex_lock(&d->dlock);
+ d->lefree = 0;
+ d->leadds = 0;
+ hg_thread_mutex_unlock(&d->dlock);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_dump(struct hg_dlog *d, int (*log_func)(FILE *, const char *, ...), FILE *stream, int trylock)
+{
+ unsigned int left, idx;
+ struct hg_dlog_dcount32 *dc32;
+ struct hg_dlog_dcount64 *dc64;
+
+ if (trylock) {
+ int try_ret = hg_thread_mutex_try_lock(&d->dlock);
+ if (try_ret != HG_UTIL_SUCCESS) /* warn them, but keep going */ {
+ fprintf(stderr, "hg_dlog_dump: WARN - lock failed\n");
+ return;
+ }
+ }
+ else
+ hg_thread_mutex_lock(&d->dlock);
+
+ if (d->leadds > 0) {
+ log_func(stream,
+ "### ----------------------\n"
+ "### (%s) debug log summary\n"
+ "### ----------------------\n",
+ (d->dlog_magic + strlen(HG_DLOG_STDMAGIC)));
+ if (!HG_LIST_IS_EMPTY(&d->cnts32) && !HG_LIST_IS_EMPTY(&d->cnts64)) {
+ log_func(stream, "# Counters\n");
+ HG_LIST_FOREACH(dc32, &d->cnts32, l)
+ {
+ log_func(stream, "# %s: %" PRId32 " [%s]\n", dc32->name, hg_atomic_get32(&dc32->c),
+ dc32->descr);
+ }
+ HG_LIST_FOREACH(dc64, &d->cnts64, l)
+ {
+ log_func(stream, "# %s: %" PRId64 " [%s]\n", dc64->name, hg_atomic_get64(&dc64->c),
+ dc64->descr);
+ }
+ log_func(stream, "# -\n");
+ }
+
+ log_func(stream, "# Number of log entries: %d\n", d->leadds);
+
+ idx = (d->lefree < d->leadds) ? d->lesize + d->lefree - d->leadds : d->lefree - d->leadds;
+ left = d->leadds;
+ while (left--) {
+ log_func(stream, "# [%lf] %s:%d\n## %s()\n", hg_time_to_double(d->le[idx].time), d->le[idx].file,
+ d->le[idx].line, d->le[idx].func);
+ idx = (idx + 1) % d->lesize;
+ }
+ }
+
+ hg_thread_mutex_unlock(&d->dlock);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_dump_file(struct hg_dlog *d, const char *base, int addpid, int trylock)
+{
+ char buf[BUFSIZ];
+ int pid = getpid();
+ FILE * fp = NULL;
+ unsigned int left, idx;
+ struct hg_dlog_dcount32 *dc32;
+ struct hg_dlog_dcount64 *dc64;
+
+ if (addpid)
+ snprintf(buf, sizeof(buf), "%s-%d.log", base, pid);
+ else
+ snprintf(buf, sizeof(buf), "%s.log", base);
+
+ fp = fopen(buf, "w");
+ if (!fp) {
+ perror("fopen");
+ return;
+ }
+
+ if (trylock) {
+ int try_ret = hg_thread_mutex_try_lock(&d->dlock);
+ if (try_ret != HG_UTIL_SUCCESS) /* warn them, but keep going */ {
+ fprintf(stderr, "hg_dlog_dump: WARN - lock failed\n");
+ fclose(fp);
+ return;
+ }
+ }
+ else
+ hg_thread_mutex_lock(&d->dlock);
+
+ fprintf(fp, "# START COUNTERS\n");
+ HG_LIST_FOREACH(dc32, &d->cnts32, l)
+ {
+ fprintf(fp, "%s %d %" PRId32 " # %s\n", dc32->name, pid, hg_atomic_get32(&dc32->c), dc32->descr);
+ }
+ HG_LIST_FOREACH(dc64, &d->cnts64, l)
+ {
+ fprintf(fp, "%s %d %" PRId64 " # %s\n", dc64->name, pid, hg_atomic_get64(&dc64->c), dc64->descr);
+ }
+ fprintf(fp, "# END COUNTERS\n\n");
+
+ fprintf(fp, "# NLOGS %d FOR %d\n", d->leadds, pid);
+
+ idx = (d->lefree < d->leadds) ? d->lesize + d->lefree - d->leadds : d->lefree - d->leadds;
+ left = d->leadds;
+ while (left--) {
+ fprintf(fp, "%lf %d %s %u %s %s %p\n", hg_time_to_double(d->le[idx].time), pid, d->le[idx].file,
+ d->le[idx].line, d->le[idx].func, d->le[idx].msg, d->le[idx].data);
+ idx = (idx + 1) % d->lesize;
+ }
+
+ hg_thread_mutex_unlock(&d->dlock);
+ fclose(fp);
+}
diff --git a/src/mercury/src/util/mercury_dlog.h b/src/mercury/src/util/mercury_dlog.h
new file mode 100644
index 0000000..557b745
--- /dev/null
+++ b/src/mercury/src/util/mercury_dlog.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_DLOG_H
+#define MERCURY_DLOG_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_atomic.h"
+#include "mercury_list.h"
+#include "mercury_thread_mutex.h"
+#include "mercury_time.h"
+
+#include <stdio.h>
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*
+ * putting a magic number at the front of the dlog allows us to search
+ * for a dlog in a coredump file after a crash and examine its contents.
+ */
+#define HG_DLOG_MAGICLEN 16 /* bytes to reserve for magic# */
+#define HG_DLOG_STDMAGIC ">D.LO.G<" /* standard for first 8 bytes */
+
+/*
+ * HG_DLOG_INITIALIZER: initializer for a dlog in a global variable.
+ * LESIZE is the number of entries in the LE array. use it like this:
+ *
+ * #define FOO_NENTS 128
+ * struct hg_dlog_entry foo_le[FOO_NENTS];
+ * struct hg_dlog foo_dlog = HG_DLOG_INITIALIZER("foo", foo_le, FOO_NENTS, 0);
+ */
+#define HG_DLOG_INITIALIZER(NAME, LE, LESIZE, LELOOP) \
+ { \
+ HG_DLOG_STDMAGIC NAME, HG_THREAD_MUTEX_INITIALIZER, HG_LIST_HEAD_INITIALIZER(cnts32), \
+ HG_LIST_HEAD_INITIALIZER(cnts64), LE, LESIZE, LELOOP, 0, 0, 0, 0 \
+ }
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*
+ * hg_dlog_entry: an entry in the dlog
+ */
+struct hg_dlog_entry {
+ const char * file; /* file name */
+ unsigned int line; /* line number */
+ const char * func; /* function name */
+ const char * msg; /* entry message (optional) */
+ const void * data; /* user data (optional) */
+ hg_time_t time; /* time added to log */
+};
+
+/*
+ * hg_dlog_dcount32: 32-bit debug counter in the dlog
+ */
+struct hg_dlog_dcount32 {
+ const char * name; /* counter name (short) */
+ const char * descr; /* description of counter */
+ hg_atomic_int32_t c; /* the counter itself */
+ HG_LIST_ENTRY(hg_dlog_dcount32) l; /* linkage */
+};
+
+/*
+ * hg_dlog_dcount64: 64-bit debug counter in the dlog
+ */
+struct hg_dlog_dcount64 {
+ const char * name; /* counter name (short) */
+ const char * descr; /* description of counter */
+ hg_atomic_int64_t c; /* the counter itself */
+ HG_LIST_ENTRY(hg_dlog_dcount64) l; /* linkage */
+};
+
+/*
+ * hg_dlog: main structure
+ */
+struct hg_dlog {
+ char dlog_magic[HG_DLOG_MAGICLEN]; /* magic number + name */
+ hg_thread_mutex_t dlock; /* lock for this data struct */
+
+ /* counter lists */
+ HG_LIST_HEAD(hg_dlog_dcount32) cnts32; /* counter list */
+ HG_LIST_HEAD(hg_dlog_dcount64) cnts64; /* counter list */
+
+ /* log */
+ struct hg_dlog_entry *le; /* array of log entries */
+ unsigned int lesize; /* size of le[] array */
+ int leloop; /* circular buffer? */
+ unsigned int lefree; /* next free entry in le[] */
+ unsigned int leadds; /* #adds done if < lesize */
+ int lestop; /* stop taking new logs */
+
+ int mallocd; /* allocated with malloc? */
+};
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * malloc and return a new dlog
+ *
+ * \param name [IN] name of dlog (truncated past 8 bytes)
+ * \param lesize [IN] number of entries to allocate for log buffer
+ * \param leloop [IN] set to make log circular (can overwrite old
+ * entries)
+ *
+ * \return the new dlog or NULL on malloc error
+ */
+HG_UTIL_PUBLIC struct hg_dlog *hg_dlog_alloc(char *name, unsigned int lesize, int leloop);
+
+/**
+ * free anything we malloc'd on a dlog. assumes we have the final
+ * active reference to dlog and it won't be used anymore after this
+ * call (so no need to lock it).
+ *
+ * \param d [IN] the dlog to finalize
+ */
+HG_UTIL_PUBLIC void hg_dlog_free(struct hg_dlog *d);
+
+/**
+ * make a named atomic32 counter in a dlog and return a pointer to
+ * it. we use the dlock to ensure a counter under a given name only
+ * gets created once (makes it easy to share a counter across files).
+ * aborts if unable to alloc counter. use it like this:
+ *
+ * hg_atomic_int32_t *foo_count;
+ * static int init = 0;
+ * if (init == 0) {
+ * hg_dlog_mkcount32(dlog, &foo_count, "foocount", "counts of foo");
+ * init = 1;
+ * }
+ *
+ * \param d [IN] dlog to create the counter in
+ * \param cptr [IN/OUT] pointer to use for counter (set to NULL to
+ * start)
+ * \param name [IN] short one word name for counter
+ * \param descr [IN] short description of counter
+ */
+HG_UTIL_PUBLIC void hg_dlog_mkcount32(struct hg_dlog *d, hg_atomic_int32_t **cptr, const char *name,
+ const char *descr);
+
+/**
+ * make a named atomic64 counter in a dlog and return a pointer to
+ * it. we use the dlock to ensure a counter under a given name only
+ * gets created once (makes it easy to share a counter across files).
+ * aborts if unable to alloc counter. use it like this:
+ *
+ * hg_atomic_int64_t *foo_count;
+ * static int init = 0;
+ * if (init == 0) {
+ * hg_dlog_mkcount64(dlog, &foo_count, "foocount", "counts of foo");
+ * init = 1;
+ * }
+ *
+ * \param d [IN] dlog to create the counter in
+ * \param cptr [IN/OUT] pointer to use for counter (set to NULL to
+ * start)
+ * \param name [IN] short one word name for counter
+ * \param descr [IN] short description of counter
+ */
+HG_UTIL_PUBLIC void hg_dlog_mkcount64(struct hg_dlog *d, hg_atomic_int64_t **cptr, const char *name,
+ const char *descr);
+
+/**
+ * attempt to add a log record to a dlog. the id and msg should point
+ * to static strings that are valid throughout the life of the program
+ * (not something that is is on the stack).
+ *
+ * \param d [IN] the dlog to add the log record to
+ * \param file [IN] file entry
+ * \param line [IN] line entry
+ * \param func [IN] func entry
+ * \param msg [IN] log entry message (optional, NULL ok)
+ * \param data [IN] user data pointer for record (optional, NULL ok)
+ *
+ * \return 1 if added, 0 otherwise
+ */
+static HG_UTIL_INLINE unsigned int hg_dlog_addlog(struct hg_dlog *d, const char *file, unsigned int line,
+ const char *func, const char *msg, const void *data);
+
+/**
+ * set the value of stop for a dlog (to enable/disable logging)
+ *
+ * \param d [IN] dlog to set stop in
+ * \param stop [IN] value of stop to use (1=stop, 0=go)
+ */
+HG_UTIL_PUBLIC void hg_dlog_setlogstop(struct hg_dlog *d, int stop);
+
+/**
+ * reset the log. this does not change the counters (since users
+ * have direct access to the hg_atomic_int64_t's, we don't need
+ * an API to change them here).
+ *
+ * \param d [IN] dlog to reset
+ */
+HG_UTIL_PUBLIC void hg_dlog_resetlog(struct hg_dlog *d);
+
+/**
+ * dump dlog info to a stream. set trylock if you want to dump even
+ * if it is locked (e.g. you are crashing and you don't care about
+ * locking).
+ *
+ * \param d [IN] dlog to dump
+ * \param log_func [IN] log function to use (default printf)
+ * \param stream [IN] stream to use
+ * \param trylock [IN] just try to lock (warn if it fails)
+ */
+HG_UTIL_PUBLIC void hg_dlog_dump(struct hg_dlog *d, int (*log_func)(FILE *, const char *, ...), FILE *stream,
+ int trylock);
+
+/**
+ * dump dlog info to a file. set trylock if you want to dump even
+ * if it is locked (e.g. you are crashing and you don't care about
+ * locking). the output file is "base.log" or base-pid.log" depending
+ * on the value of addpid.
+ *
+ * \param d [IN] dlog to dump
+ * \param base [IN] output file basename
+ * \param addpid [IN] add pid to output filename
+ * \param trylock [IN] just try to lock (warn if it fails)
+ */
+HG_UTIL_PUBLIC void hg_dlog_dump_file(struct hg_dlog *d, const char *base, int addpid, int trylock);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE unsigned int
+hg_dlog_addlog(struct hg_dlog *d, const char *file, unsigned int line, const char *func, const char *msg,
+ const void *data)
+{
+ unsigned int rv = 0;
+ unsigned int idx;
+
+ hg_thread_mutex_lock(&d->dlock);
+ if (d->lestop)
+ goto done;
+ if (d->leloop == 0 && d->leadds >= d->lesize)
+ goto done;
+ idx = d->lefree;
+ d->lefree = (d->lefree + 1) % d->lesize;
+ if (d->leadds < d->lesize)
+ d->leadds++;
+ d->le[idx].file = file;
+ d->le[idx].line = line;
+ d->le[idx].func = func;
+ d->le[idx].msg = msg;
+ d->le[idx].data = data;
+ hg_time_get_current(&d->le[idx].time);
+ rv = 1;
+
+done:
+ hg_thread_mutex_unlock(&d->dlock);
+ return rv;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_DLOG_H */
diff --git a/src/mercury/src/util/mercury_event.c b/src/mercury/src/util/mercury_event.c
new file mode 100644
index 0000000..f7d5bb9
--- /dev/null
+++ b/src/mercury/src/util/mercury_event.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_event.h"
+
+#include "mercury_util_error.h"
+
+/*---------------------------------------------------------------------------*/
+int
+hg_event_create(void)
+{
+ int fd = -1;
+#if defined(_WIN32)
+
+#elif defined(HG_UTIL_HAS_SYSEVENTFD_H)
+ /* Create local signal event on self address */
+ fd = eventfd(0, EFD_NONBLOCK | EFD_SEMAPHORE);
+ HG_UTIL_CHECK_ERROR_NORET(fd == -1, done, "eventfd() failed (%s)", strerror(errno));
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ struct kevent kev;
+ struct timespec timeout = {0, 0};
+ int rc;
+
+ /* Create kqueue */
+ fd = kqueue();
+ HG_UTIL_CHECK_ERROR_NORET(fd == -1, done, "kqueue() failed (%s)", strerror(errno));
+
+ EV_SET(&kev, HG_EVENT_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
+
+ /* Add user-defined event to kqueue */
+ rc = kevent(fd, &kev, 1, NULL, 0, &timeout);
+ HG_UTIL_CHECK_ERROR_NORET(rc == -1, error, "kevent() failed (%s)", strerror(errno));
+#else
+
+#endif
+ HG_UTIL_LOG_DEBUG("Created event fd=%d", fd);
+
+done:
+ return fd;
+
+#if defined(HG_UTIL_HAS_SYSEVENT_H)
+error:
+ hg_event_destroy(fd);
+
+ return -1;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_event_destroy(int fd)
+{
+ int ret = HG_UTIL_SUCCESS, rc;
+#if defined(_WIN32)
+
+#else
+ rc = close(fd);
+ HG_UTIL_CHECK_ERROR(rc == -1, done, ret, HG_UTIL_FAIL, "close() failed (%s)", strerror(errno));
+#endif
+ HG_UTIL_LOG_DEBUG("Destroyed event fd=%d", fd);
+
+done:
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_event.h b/src/mercury/src/util/mercury_event.h
new file mode 100644
index 0000000..8be18a5
--- /dev/null
+++ b/src/mercury/src/util/mercury_event.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_EVENT_H
+#define MERCURY_EVENT_H
+
+#include "mercury_util_config.h"
+
+#ifdef _WIN32
+
+#else
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(HG_UTIL_HAS_SYSEVENTFD_H)
+#include <sys/eventfd.h>
+#ifndef HG_UTIL_HAS_EVENTFD_T
+typedef uint64_t eventfd_t;
+#endif
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+#include <sys/event.h>
+#define HG_EVENT_IDENT 42 /* User-defined ident */
+#endif
+#endif
+
+/**
+ * Purpose: define an event object that can be used as an event
+ * wait/notify mechanism.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a new event object.
+ *
+ * \return file descriptor on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_event_create(void);
+
+/**
+ * Destroy an event object.
+ *
+ * \param fd [IN] event file descriptor
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_event_destroy(int fd);
+
+/**
+ * Notify for event.
+ *
+ * \param fd [IN] event file descriptor
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_event_set(int fd);
+
+/**
+ * Get event notification.
+ *
+ * \param fd [IN] event file descriptor
+ * \param notified [IN] boolean set to HG_UTIL_TRUE if event received
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_event_get(int fd, hg_util_bool_t *notified);
+
+/*---------------------------------------------------------------------------*/
+#if defined(_WIN32)
+/* TODO */
+#elif defined(HG_UTIL_HAS_SYSEVENTFD_H)
+#ifdef HG_UTIL_HAS_EVENTFD_T
+static HG_UTIL_INLINE int
+hg_event_set(int fd)
+{
+ return (eventfd_write(fd, 1) == 0) ? HG_UTIL_SUCCESS : HG_UTIL_FAIL;
+}
+#else
+static HG_UTIL_INLINE int
+hg_event_set(int fd)
+{
+ eventfd_t count = 1;
+ ssize_t s = write(fd, &count, sizeof(eventfd_t));
+
+ return (s == sizeof(eventfd_t)) ? HG_UTIL_SUCCESS : HG_UTIL_FAIL;
+}
+#endif
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+static HG_UTIL_INLINE int
+hg_event_set(int fd)
+{
+ struct kevent kev;
+ struct timespec timeout = {0, 0};
+ int rc;
+
+ EV_SET(&kev, HG_EVENT_IDENT, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ /* Trigger user-defined event */
+ rc = kevent(fd, &kev, 1, NULL, 0, &timeout);
+
+ return (rc == -1) ? HG_UTIL_FAIL : HG_UTIL_SUCCESS;
+}
+#else
+#error "Not supported on this platform."
+#endif
+
+/*---------------------------------------------------------------------------*/
+#if defined(_WIN32)
+#elif defined(HG_UTIL_HAS_SYSEVENTFD_H)
+#ifdef HG_UTIL_HAS_EVENTFD_T
+static HG_UTIL_INLINE int
+hg_event_get(int fd, hg_util_bool_t *signaled)
+{
+ eventfd_t count = 0;
+
+ if ((eventfd_read(fd, &count) == 0) && count)
+ *signaled = HG_UTIL_TRUE;
+ else {
+ if (errno == EAGAIN)
+ *signaled = HG_UTIL_FALSE;
+ else
+ return HG_UTIL_FAIL;
+ }
+
+ return HG_UTIL_SUCCESS;
+}
+#else
+static HG_UTIL_INLINE int
+hg_event_get(int fd, hg_util_bool_t *signaled)
+{
+ eventfd_t count = 0;
+ ssize_t s = read(fd, &count, sizeof(eventfd_t));
+ if ((s == sizeof(eventfd_t)) && count)
+ *signaled = HG_UTIL_TRUE;
+ else {
+ if (errno == EAGAIN)
+ *signaled = HG_UTIL_FALSE;
+ else
+ return HG_UTIL_FAIL;
+ }
+
+ return HG_UTIL_SUCCESS;
+}
+#endif
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+static HG_UTIL_INLINE int
+hg_event_get(int fd, hg_util_bool_t *signaled)
+{
+ struct kevent kev;
+ int nfds;
+ struct timespec timeout = {0, 0};
+
+ /* Check user-defined event */
+ nfds = kevent(fd, NULL, 0, &kev, 1, &timeout);
+ if (nfds == -1)
+ return HG_UTIL_FAIL;
+
+ *signaled = ((nfds > 0) && (kev.ident == HG_EVENT_IDENT)) ? HG_UTIL_TRUE : HG_UTIL_FALSE;
+
+ return HG_UTIL_SUCCESS;
+}
+#else
+#error "Not supported on this platform."
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_EVENT_H */
diff --git a/src/mercury/src/util/mercury_hash_string.h b/src/mercury/src/util/mercury_hash_string.h
new file mode 100644
index 0000000..0b136ca
--- /dev/null
+++ b/src/mercury/src/util/mercury_hash_string.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_HASH_STRING_H
+#define MERCURY_HASH_STRING_H
+
+#include "mercury_util_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Hash function name for unique ID to register.
+ *
+ * \param string [IN] string name
+ *
+ * \return Non-negative ID that corresponds to string name
+ */
+static HG_UTIL_INLINE unsigned int
+hg_hash_string(const char *string)
+{
+ /* This is the djb2 string hash function */
+
+ unsigned int result = 5381;
+ const unsigned char *p;
+
+ p = (const unsigned char *)string;
+
+ while (*p != '\0') {
+ result = (result << 5) + result + *p;
+ ++p;
+ }
+ return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_HASH_STRING_H */
diff --git a/src/mercury/src/util/mercury_hash_table.c b/src/mercury/src/util/mercury_hash_table.c
new file mode 100644
index 0000000..b6d29cf
--- /dev/null
+++ b/src/mercury/src/util/mercury_hash_table.c
@@ -0,0 +1,435 @@
+/*
+Copyright (c) 2005-2008, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Hash table implementation */
+
+#include "mercury_hash_table.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct hg_hash_table_entry {
+ hg_hash_table_key_t key;
+ hg_hash_table_value_t value;
+ hg_hash_table_entry_t *next;
+};
+
+struct hg_hash_table {
+ hg_hash_table_entry_t ** table;
+ unsigned int table_size;
+ hg_hash_table_hash_func_t hash_func;
+ hg_hash_table_equal_func_t equal_func;
+ hg_hash_table_key_free_func_t key_free_func;
+ hg_hash_table_value_free_func_t value_free_func;
+ unsigned int entries;
+ unsigned int prime_index;
+};
+
+/* This is a set of good hash table prime numbers, from:
+ * http://planetmath.org/goodhashtableprimes
+ * Each prime is roughly double the previous value, and as far as
+ * possible from the nearest powers of two. */
+
+static const unsigned int hash_table_primes[] = {
+ 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
+ 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
+ 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741,
+};
+
+static const unsigned int hash_table_num_primes = sizeof(hash_table_primes) / sizeof(int);
+
+/* Internal function used to allocate the table on hash table creation
+ * and when enlarging the table */
+static int
+hash_table_allocate_table(hg_hash_table_t *hash_table)
+{
+ unsigned int new_table_size;
+
+ /* Determine the table size based on the current prime index.
+ * An attempt is made here to ensure sensible behavior if the
+ * maximum prime is exceeded, but in practice other things are
+ * likely to break long before that happens. */
+
+ if (hash_table->prime_index < hash_table_num_primes)
+ new_table_size = hash_table_primes[hash_table->prime_index];
+ else
+ new_table_size = hash_table->entries * 10;
+
+ hash_table->table_size = new_table_size;
+
+ /* Allocate the table and initialise to NULL for all entries */
+ hash_table->table =
+ (hg_hash_table_entry_t **)calloc(hash_table->table_size, sizeof(hg_hash_table_entry_t *));
+ if (hash_table->table == NULL)
+ return 0;
+
+ return 1;
+}
+
+/* Free an entry, calling the free functions if there are any registered */
+static void
+hash_table_free_entry(hg_hash_table_t *hash_table, hg_hash_table_entry_t *entry)
+{
+ /* If there is a function registered for freeing keys, use it to free
+ * the key */
+ if (hash_table->key_free_func != NULL)
+ hash_table->key_free_func(entry->key);
+
+ /* Likewise with the value */
+ if (hash_table->value_free_func != NULL)
+ hash_table->value_free_func(entry->value);
+
+ /* Free the data structure */
+ free(entry);
+}
+
+hg_hash_table_t *
+hg_hash_table_new(hg_hash_table_hash_func_t hash_func, hg_hash_table_equal_func_t equal_func)
+{
+ hg_hash_table_t *hash_table;
+
+ /* Allocate a new hash table structure */
+
+ hash_table = (hg_hash_table_t *)malloc(sizeof(hg_hash_table_t));
+
+ if (hash_table == NULL)
+ return NULL;
+
+ hash_table->hash_func = hash_func;
+ hash_table->equal_func = equal_func;
+ hash_table->key_free_func = NULL;
+ hash_table->value_free_func = NULL;
+ hash_table->entries = 0;
+ hash_table->prime_index = 0;
+
+ /* Allocate the table */
+ if (!hash_table_allocate_table(hash_table)) {
+ free(hash_table);
+
+ return NULL;
+ }
+
+ return hash_table;
+}
+
+void
+hg_hash_table_free(hg_hash_table_t *hash_table)
+{
+ hg_hash_table_entry_t *rover;
+ hg_hash_table_entry_t *next;
+ unsigned int i;
+
+ /* Free all entries in all chains */
+
+ for (i = 0; i < hash_table->table_size; ++i) {
+ rover = hash_table->table[i];
+ while (rover != NULL) {
+ next = rover->next;
+ hash_table_free_entry(hash_table, rover);
+ rover = next;
+ }
+ }
+
+ /* Free the table */
+ free(hash_table->table);
+
+ /* Free the hash table structure */
+ free(hash_table);
+}
+
+void
+hg_hash_table_register_free_functions(hg_hash_table_t * hash_table,
+ hg_hash_table_key_free_func_t key_free_func,
+ hg_hash_table_value_free_func_t value_free_func)
+{
+ hash_table->key_free_func = key_free_func;
+ hash_table->value_free_func = value_free_func;
+}
+
+static int
+hash_table_enlarge(hg_hash_table_t *hash_table)
+{
+ hg_hash_table_entry_t **old_table;
+ unsigned int old_table_size;
+ unsigned int old_prime_index;
+ hg_hash_table_entry_t * rover;
+ hg_hash_table_entry_t * next;
+ unsigned int entry_index;
+ unsigned int i;
+
+ /* Store a copy of the old table */
+ old_table = hash_table->table;
+ old_table_size = hash_table->table_size;
+ old_prime_index = hash_table->prime_index;
+
+ /* Allocate a new, larger table */
+ ++hash_table->prime_index;
+
+ if (!hash_table_allocate_table(hash_table)) {
+ /* Failed to allocate the new table */
+ hash_table->table = old_table;
+ hash_table->table_size = old_table_size;
+ hash_table->prime_index = old_prime_index;
+
+ return 0;
+ }
+
+ /* Link all entries from all chains into the new table */
+
+ for (i = 0; i < old_table_size; ++i) {
+ rover = old_table[i];
+
+ while (rover != NULL) {
+ next = rover->next;
+
+ /* Find the index into the new table */
+ entry_index = hash_table->hash_func(rover->key) % hash_table->table_size;
+
+ /* Link this entry into the chain */
+ rover->next = hash_table->table[entry_index];
+ hash_table->table[entry_index] = rover;
+
+ /* Advance to next in the chain */
+ rover = next;
+ }
+ }
+
+ /* Free the old table */
+ free(old_table);
+
+ return 1;
+}
+
+int
+hg_hash_table_insert(hg_hash_table_t *hash_table, hg_hash_table_key_t key, hg_hash_table_value_t value)
+{
+ hg_hash_table_entry_t *rover;
+ hg_hash_table_entry_t *newentry;
+ unsigned int entry_index;
+
+ /* If there are too many items in the table with respect to the table
+ * size, the number of hash collisions increases and performance
+ * decreases. Enlarge the table size to prevent this happening */
+
+ if ((hash_table->entries * 3) / hash_table->table_size > 0) {
+
+ /* Table is more than 1/3 full */
+ if (!hash_table_enlarge(hash_table)) {
+
+ /* Failed to enlarge the table */
+
+ return 0;
+ }
+ }
+
+ /* Generate the hash of the key and hence the index into the table */
+ entry_index = hash_table->hash_func(key) % hash_table->table_size;
+
+ /* Traverse the chain at this location and look for an existing
+ * entry with the same key */
+ rover = hash_table->table[entry_index];
+
+ while (rover != NULL) {
+ if (hash_table->equal_func(rover->key, key) != 0) {
+
+ /* Same key: overwrite this entry with new data */
+
+ /* If there is a value free function, free the old data
+ * before adding in the new data */
+ if (hash_table->value_free_func != NULL)
+ hash_table->value_free_func(rover->value);
+
+ /* Same with the key: use the new key value and free
+ * the old one */
+ if (hash_table->key_free_func != NULL)
+ hash_table->key_free_func(rover->key);
+
+ rover->key = key;
+ rover->value = value;
+
+ /* Finished */
+ return 1;
+ }
+ rover = rover->next;
+ }
+
+ /* Not in the hash table yet. Create a new entry */
+ newentry = (hg_hash_table_entry_t *)malloc(sizeof(hg_hash_table_entry_t));
+
+ if (newentry == NULL)
+ return 0;
+
+ newentry->key = key;
+ newentry->value = value;
+
+ /* Link into the list */
+ newentry->next = hash_table->table[entry_index];
+ hash_table->table[entry_index] = newentry;
+
+ /* Maintain the count of the number of entries */
+ ++hash_table->entries;
+
+ /* Added successfully */
+ return 1;
+}
+
+hg_hash_table_value_t
+hg_hash_table_lookup(hg_hash_table_t *hash_table, hg_hash_table_key_t key)
+{
+ hg_hash_table_entry_t *rover;
+ unsigned int entry_index;
+
+ /* Generate the hash of the key and hence the index into the table */
+ entry_index = hash_table->hash_func(key) % hash_table->table_size;
+
+ /* Walk the chain at this index until the corresponding entry is
+ * found */
+ rover = hash_table->table[entry_index];
+
+ while (rover != NULL) {
+ if (hash_table->equal_func(key, rover->key) != 0) {
+ /* Found the entry. Return the data. */
+ return rover->value;
+ }
+ rover = rover->next;
+ }
+
+ /* Not found */
+ return HG_HASH_TABLE_NULL;
+}
+
+int
+hg_hash_table_remove(hg_hash_table_t *hash_table, hg_hash_table_key_t key)
+{
+ hg_hash_table_entry_t **rover;
+ hg_hash_table_entry_t * entry;
+ unsigned int entry_index;
+ int result;
+
+ /* Generate the hash of the key and hence the index into the table */
+ entry_index = hash_table->hash_func(key) % hash_table->table_size;
+
+ /* Rover points at the pointer which points at the current entry
+ * in the chain being inspected. ie. the entry in the table, or
+ * the "next" pointer of the previous entry in the chain. This
+ * allows us to unlink the entry when we find it. */
+ result = 0;
+ rover = &hash_table->table[entry_index];
+
+ while (*rover != NULL) {
+ if (hash_table->equal_func(key, (*rover)->key) != 0) {
+ /* This is the entry to remove */
+ entry = *rover;
+
+ /* Unlink from the list */
+ *rover = entry->next;
+
+ /* Destroy the entry structure */
+ hash_table_free_entry(hash_table, entry);
+
+ /* Track count of entries */
+ --hash_table->entries;
+ result = 1;
+ break;
+ }
+
+ /* Advance to the next entry */
+ rover = &((*rover)->next);
+ }
+
+ return result;
+}
+
+unsigned int
+hg_hash_table_num_entries(hg_hash_table_t *hash_table)
+{
+ return hash_table->entries;
+}
+
+void
+hg_hash_table_iterate(hg_hash_table_t *hash_table, hg_hash_table_iter_t *iterator)
+{
+ unsigned int chain;
+
+ iterator->hash_table = hash_table;
+
+ /* Default value of next if no entries are found. */
+ iterator->next_entry = NULL;
+
+ /* Find the first entry */
+ for (chain = 0; chain < hash_table->table_size; ++chain) {
+ if (hash_table->table[chain] != NULL) {
+ iterator->next_entry = hash_table->table[chain];
+ iterator->next_chain = chain;
+ break;
+ }
+ }
+}
+
+int
+hg_hash_table_iter_has_more(hg_hash_table_iter_t *iterator)
+{
+ return iterator->next_entry != NULL;
+}
+
+hg_hash_table_value_t
+hg_hash_table_iter_next(hg_hash_table_iter_t *iterator)
+{
+ hg_hash_table_entry_t *current_entry;
+ hg_hash_table_t * hash_table;
+ hg_hash_table_value_t result;
+ unsigned int chain;
+
+ hash_table = iterator->hash_table;
+
+ /* No more entries? */
+ if (iterator->next_entry == NULL)
+ return HG_HASH_TABLE_NULL;
+
+ /* Result is immediately available */
+ current_entry = iterator->next_entry;
+ result = current_entry->value;
+
+ /* Find the next entry */
+ if (current_entry->next != NULL) {
+ /* Next entry in current chain */
+ iterator->next_entry = current_entry->next;
+ }
+ else {
+ /* None left in this chain, so advance to the next chain */
+ chain = iterator->next_chain + 1;
+
+ /* Default value if no next chain found */
+ iterator->next_entry = NULL;
+
+ while (chain < hash_table->table_size) {
+ /* Is there anything in this chain? */
+ if (hash_table->table[chain] != NULL) {
+ iterator->next_entry = hash_table->table[chain];
+ break;
+ }
+
+ /* Try the next chain */
+ ++chain;
+ }
+
+ iterator->next_chain = chain;
+ }
+
+ return result;
+}
diff --git a/src/mercury/src/util/mercury_hash_table.h b/src/mercury/src/util/mercury_hash_table.h
new file mode 100644
index 0000000..0063f02
--- /dev/null
+++ b/src/mercury/src/util/mercury_hash_table.h
@@ -0,0 +1,242 @@
+/*
+
+Copyright (c) 2005-2008, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+/**
+ * \file mercury_hash_table.h
+ *
+ * \brief Hash table.
+ *
+ * A hash table stores a set of values which can be addressed by a
+ * key. Given the key, the corresponding value can be looked up
+ * quickly.
+ *
+ * To create a hash table, use \ref hg_hash_table_new. To destroy a
+ * hash table, use \ref hg_hash_table_free.
+ *
+ * To insert a value into a hash table, use \ref hg_hash_table_insert.
+ *
+ * To remove a value from a hash table, use \ref hg_hash_table_remove.
+ *
+ * To look up a value by its key, use \ref hg_hash_table_lookup.
+ *
+ * To iterate over all values in a hash table, use
+ * \ref hg_hash_table_iterate to initialize a \ref hg_hash_table_iter
+ * structure. Each value can then be read in turn using
+ * \ref hg_hash_table_iter_next and \ref hg_hash_table_iter_has_more.
+ */
+
+#ifndef HG_HASH_TABLE_H
+#define HG_HASH_TABLE_H
+
+#include "mercury_util_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A hash table structure.
+ */
+
+typedef struct hg_hash_table hg_hash_table_t;
+
+/**
+ * Structure used to iterate over a hash table.
+ */
+
+typedef struct hg_hash_table_iter hg_hash_table_iter_t;
+
+/**
+ * Internal structure representing an entry in a hash table.
+ */
+
+typedef struct hg_hash_table_entry hg_hash_table_entry_t;
+
+/**
+ * A key to look up a value in a \ref hg_hash_table_t.
+ */
+
+typedef void *hg_hash_table_key_t;
+
+/**
+ * A value stored in a \ref hg_hash_table_t.
+ */
+
+typedef void *hg_hash_table_value_t;
+
+/**
+ * Definition of a \ref hg_hash_table_iter.
+ */
+
+struct hg_hash_table_iter {
+ hg_hash_table_t * hash_table;
+ hg_hash_table_entry_t *next_entry;
+ unsigned int next_chain;
+};
+
+/**
+ * A null \ref HashTableValue.
+ */
+
+#define HG_HASH_TABLE_NULL ((void *)0)
+
+/**
+ * Hash function used to generate hash values for keys used in a hash
+ * table.
+ *
+ * \param value The value to generate a hash value for.
+ * \return The hash value.
+ */
+
+typedef unsigned int (*hg_hash_table_hash_func_t)(hg_hash_table_key_t value);
+
+/**
+ * Function used to compare two keys for equality.
+ *
+ * \return Non-zero if the two keys are equal, zero if the keys are
+ * not equal.
+ */
+
+typedef int (*hg_hash_table_equal_func_t)(hg_hash_table_key_t value1, hg_hash_table_key_t value2);
+
+/**
+ * Type of function used to free keys when entries are removed from a
+ * hash table.
+ */
+
+typedef void (*hg_hash_table_key_free_func_t)(hg_hash_table_key_t value);
+
+/**
+ * Type of function used to free values when entries are removed from a
+ * hash table.
+ */
+
+typedef void (*hg_hash_table_value_free_func_t)(hg_hash_table_value_t value);
+
+/**
+ * Create a new hash table.
+ *
+ * \param hash_func Function used to generate hash keys for the
+ * keys used in the table.
+ * \param equal_func Function used to test keys used in the table
+ * for equality.
+ * \return A new hash table structure, or NULL if it
+ * was not possible to allocate the new hash
+ * table.
+ */
+HG_UTIL_PUBLIC hg_hash_table_t *hg_hash_table_new(hg_hash_table_hash_func_t hash_func,
+ hg_hash_table_equal_func_t equal_func);
+
+/**
+ * Destroy a hash table.
+ *
+ * \param hash_table The hash table to destroy.
+ */
+HG_UTIL_PUBLIC void hg_hash_table_free(hg_hash_table_t *hash_table);
+
+/**
+ * Register functions used to free the key and value when an entry is
+ * removed from a hash table.
+ *
+ * \param hash_table The hash table.
+ * \param key_free_func Function used to free keys.
+ * \param value_free_func Function used to free values.
+ */
+HG_UTIL_PUBLIC void hg_hash_table_register_free_functions(hg_hash_table_t * hash_table,
+ hg_hash_table_key_free_func_t key_free_func,
+ hg_hash_table_value_free_func_t value_free_func);
+
+/**
+ * Insert a value into a hash table, overwriting any existing entry
+ * using the same key.
+ *
+ * \param hash_table The hash table.
+ * \param key The key for the new value.
+ * \param value The value to insert.
+ * \return Non-zero if the value was added successfully,
+ * or zero if it was not possible to allocate
+ * memory for the new entry.
+ */
+HG_UTIL_PUBLIC int hg_hash_table_insert(hg_hash_table_t *hash_table, hg_hash_table_key_t key,
+ hg_hash_table_value_t value);
+
+/**
+ * Look up a value in a hash table by key.
+ *
+ * \param hash_table The hash table.
+ * \param key The key of the value to look up.
+ * \return The value, or \ref HASH_TABLE_NULL if there
+ * is no value with that key in the hash table.
+ */
+HG_UTIL_PUBLIC hg_hash_table_value_t hg_hash_table_lookup(hg_hash_table_t * hash_table,
+ hg_hash_table_key_t key);
+
+/**
+ * Remove a value from a hash table.
+ *
+ * \param hash_table The hash table.
+ * \param key The key of the value to remove.
+ * \return Non-zero if a key was removed, or zero if the
+ * specified key was not found in the hash table.
+ */
+HG_UTIL_PUBLIC int hg_hash_table_remove(hg_hash_table_t *hash_table, hg_hash_table_key_t key);
+
+/**
+ * Retrieve the number of entries in a hash table.
+ *
+ * \param hash_table The hash table.
+ * \return The number of entries in the hash table.
+ */
+HG_UTIL_PUBLIC unsigned int hg_hash_table_num_entries(hg_hash_table_t *hash_table);
+
+/**
+ * Initialise a \ref HashTableIterator to iterate over a hash table.
+ *
+ * \param hash_table The hash table.
+ * \param iter Pointer to an iterator structure to
+ * initialise.
+ */
+HG_UTIL_PUBLIC void hg_hash_table_iterate(hg_hash_table_t *hash_table, hg_hash_table_iter_t *iter);
+
+/**
+ * Determine if there are more keys in the hash table to iterate over.
+ *
+ * \param iterator The hash table iterator.
+ * \return Zero if there are no more values to iterate
+ * over, non-zero if there are more values to
+ * iterate over.
+ */
+HG_UTIL_PUBLIC int hg_hash_table_iter_has_more(hg_hash_table_iter_t *iterator);
+
+/**
+ * Using a hash table iterator, retrieve the next key.
+ *
+ * \param iterator The hash table iterator.
+ * \return The next key from the hash table, or
+ * \ref HG_HASH_TABLE_NULL if there are no more
+ * keys to iterate over.
+ */
+HG_UTIL_PUBLIC hg_hash_table_value_t hg_hash_table_iter_next(hg_hash_table_iter_t *iterator);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HG_HASH_TABLE_H */
diff --git a/src/mercury/src/util/mercury_list.h b/src/mercury/src/util/mercury_list.h
new file mode 100644
index 0000000..18ce93a
--- /dev/null
+++ b/src/mercury/src/util/mercury_list.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Code below is derived from sys/queue.h which follows the below notice:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef MERCURY_LIST_H
+#define MERCURY_LIST_H
+
+#define HG_LIST_HEAD_INITIALIZER(name) \
+ { \
+ NULL \
+ }
+
+#define HG_LIST_HEAD_INIT(struct_head_name, var_name) \
+ struct struct_head_name var_name = HG_LIST_HEAD_INITIALIZER(var_name)
+
+#define HG_LIST_HEAD_DECL(struct_head_name, struct_entry_name) \
+ struct struct_head_name { \
+ struct struct_entry_name *head; \
+ }
+
+#define HG_LIST_HEAD(struct_entry_name) \
+ struct { \
+ struct struct_entry_name *head; \
+ }
+
+#define HG_LIST_ENTRY(struct_entry_name) \
+ struct { \
+ struct struct_entry_name * next; \
+ struct struct_entry_name **prev; \
+ }
+
+#define HG_LIST_INIT(head_ptr) \
+ do { \
+ (head_ptr)->head = NULL; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_IS_EMPTY(head_ptr) ((head_ptr)->head == NULL)
+
+#define HG_LIST_FIRST(head_ptr) ((head_ptr)->head)
+
+#define HG_LIST_NEXT(entry_ptr, entry_field_name) ((entry_ptr)->entry_field_name.next)
+
+#define HG_LIST_INSERT_AFTER(list_entry_ptr, entry_ptr, entry_field_name) \
+ do { \
+ if (((entry_ptr)->entry_field_name.next = (list_entry_ptr)->entry_field_name.next) != NULL) \
+ (list_entry_ptr)->entry_field_name.next->entry_field_name.prev = \
+ &(entry_ptr)->entry_field_name.next; \
+ (list_entry_ptr)->entry_field_name.next = (entry_ptr); \
+ (entry_ptr)->entry_field_name.prev = &(list_entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_INSERT_BEFORE(list_entry_ptr, entry_ptr, entry_field_name) \
+ do { \
+ (entry_ptr)->entry_field_name.prev = (list_entry_ptr)->entry_field_name.prev; \
+ (entry_ptr)->entry_field_name.next = (list_entry_ptr); \
+ *(list_entry_ptr)->entry_field_name.prev = (entry_ptr); \
+ (list_entry_ptr)->entry_field_name.prev = &(entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_INSERT_HEAD(head_ptr, entry_ptr, entry_field_name) \
+ do { \
+ if (((entry_ptr)->entry_field_name.next = (head_ptr)->head) != NULL) \
+ (head_ptr)->head->entry_field_name.prev = &(entry_ptr)->entry_field_name.next; \
+ (head_ptr)->head = (entry_ptr); \
+ (entry_ptr)->entry_field_name.prev = &(head_ptr)->head; \
+ } while (/*CONSTCOND*/ 0)
+
+/* TODO would be nice to not have any condition */
+#define HG_LIST_REMOVE(entry_ptr, entry_field_name) \
+ do { \
+ if ((entry_ptr)->entry_field_name.next != NULL) \
+ (entry_ptr)->entry_field_name.next->entry_field_name.prev = (entry_ptr)->entry_field_name.prev; \
+ *(entry_ptr)->entry_field_name.prev = (entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_LIST_FOREACH(var, head_ptr, entry_field_name) \
+ for ((var) = ((head_ptr)->head); (var); (var) = ((var)->entry_field_name.next))
+
+#endif /* MERCURY_LIST_H */
diff --git a/src/mercury/src/util/mercury_log.c b/src/mercury/src/util/mercury_log.c
new file mode 100644
index 0000000..52dc675
--- /dev/null
+++ b/src/mercury/src/util/mercury_log.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_log.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Make sure it executes first */
+#ifdef HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+#define HG_UTIL_CONSTRUCTOR_1 __attribute__((constructor(101)))
+#else
+#define HG_UTIL_CONSTRUCTOR_1
+#endif
+
+/* Destructor (used to finalize log outlets) */
+#define HG_UTIL_DESTRUCTOR __attribute__((destructor))
+
+/* Max number of subsystems that can be tracked */
+#define HG_LOG_SUBSYS_MAX (16)
+
+/* Max length of subsystem name (without trailing \0) */
+#define HG_LOG_SUBSYS_NAME_MAX (16)
+
+/* Log buffer size */
+#define HG_LOG_BUF_MAX (256)
+
+#ifdef HG_UTIL_HAS_LOG_COLOR
+#define HG_LOG_ESC "\033"
+#define HG_LOG_RESET HG_LOG_ESC "[0m"
+#define HG_LOG_REG HG_LOG_ESC "[0;"
+#define HG_LOG_BOLD HG_LOG_ESC "[1;"
+#define HG_LOG_RED "31m"
+#define HG_LOG_GREEN "32m"
+#define HG_LOG_YELLOW "33m"
+#define HG_LOG_BLUE "34m"
+#define HG_LOG_MAGENTA "35m"
+#define HG_LOG_CYAN "36m"
+#endif
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Init logs */
+static void hg_log_init(void) HG_UTIL_CONSTRUCTOR_1;
+
+/* Finalize logs */
+static void hg_log_finalize(void) HG_UTIL_DESTRUCTOR;
+
+/* Init log level */
+static void hg_log_init_level(void);
+
+/* Init log subsys */
+static void hg_log_init_subsys(void);
+
+/* Reset all log levels */
+static void hg_log_outlet_reset_all(void);
+
+/* Free all attached logs */
+static void hg_log_free_dlogs(void);
+
+/* Is log active */
+static int hg_log_outlet_active(const char *name);
+
+/* Update log level of outlet */
+static void hg_log_outlet_update_level(struct hg_log_outlet *hg_log_outlet);
+
+/* Update level of all outlets */
+static void hg_log_outlet_update_all(void);
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Default log outlet */
+HG_LOG_OUTLET_DECL(hg) = HG_LOG_OUTLET_INITIALIZER(hg, HG_LOG_OFF, NULL, NULL);
+
+/* List of all registered outlets */
+static HG_QUEUE_HEAD(hg_log_outlet) hg_log_outlets_g = HG_QUEUE_HEAD_INITIALIZER(hg_log_outlets_g);
+
+/* Default 'printf' log function */
+static int (*hg_log_func_g)(FILE *stream, const char *format, ...) = fprintf;
+
+/* Default log level */
+static enum hg_log_level hg_log_level_g = HG_LOG_LEVEL_ERROR;
+
+/* Default log subsystems */
+static char hg_log_subsys_g[HG_LOG_SUBSYS_MAX][HG_LOG_SUBSYS_NAME_MAX + 1] = {{"\0"}};
+
+/* Log level string table */
+#define X(a, b, c) b,
+static const char *const hg_log_level_name_g[] = {HG_LOG_LEVELS};
+#undef X
+
+/* Standard log streams */
+#define X(a, b, c) c,
+static FILE **const hg_log_std_streams_g[] = {HG_LOG_LEVELS};
+#undef X
+static FILE *hg_log_streams_g[HG_LOG_LEVEL_MAX] = {NULL};
+
+/* Log colors */
+#ifdef HG_UTIL_HAS_LOG_COLOR
+static const char *const hg_log_colors_g[] = {"", HG_LOG_RED, HG_LOG_MAGENTA, HG_LOG_BLUE, HG_LOG_BLUE, ""};
+#endif
+
+/* Init */
+#ifndef HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+static hg_util_bool_t hg_log_init_g = HG_UTIL_FALSE;
+#endif
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_init(void)
+{
+ hg_log_init_level();
+ hg_log_init_subsys();
+
+ /* Register top outlet */
+ hg_log_outlet_register(&HG_LOG_OUTLET(hg));
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_finalize(void)
+{
+ hg_log_free_dlogs();
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_init_level(void)
+{
+ const char *log_level = getenv("HG_LOG_LEVEL");
+
+ /* Override default log level */
+ if (log_level == NULL)
+ return;
+
+ hg_log_set_level(hg_log_name_to_level(log_level));
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_init_subsys(void)
+{
+ const char *log_subsys = getenv("HG_LOG_SUBSYS");
+
+ if (log_subsys == NULL)
+ return;
+
+ // fprintf(stderr, "subsys: %s\n", log_subsys);
+ hg_log_set_subsys(log_subsys);
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_outlet_reset_all(void)
+{
+ struct hg_log_outlet *outlet;
+ int i;
+
+ /* Reset levels */
+ HG_QUEUE_FOREACH(outlet, &hg_log_outlets_g, entry)
+ outlet->level = HG_LOG_LEVEL_NONE;
+
+ /* Reset subsys */
+ for (i = 0; i < HG_LOG_SUBSYS_MAX; i++)
+ strcpy(hg_log_subsys_g[i], "\0");
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_free_dlogs(void)
+{
+ struct hg_log_outlet *outlet;
+
+ /* Free logs if any was attached */
+ HG_QUEUE_FOREACH(outlet, &hg_log_outlets_g, entry)
+ if (outlet->debug_log)
+ hg_dlog_free(outlet->debug_log);
+}
+
+/*---------------------------------------------------------------------------*/
+static int
+hg_log_outlet_active(const char *name)
+{
+ int i = 0;
+
+ while (hg_log_subsys_g[i][0] != '\0' && i < HG_LOG_SUBSYS_MAX) {
+ /* Force a subsystem to be inactive */
+ if ((hg_log_subsys_g[i][0] == '~') && (strcmp(&hg_log_subsys_g[i][1], name) == 0))
+ return -1;
+
+ if (strcmp(hg_log_subsys_g[i], name) == 0) {
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_outlet_update_level(struct hg_log_outlet *hg_log_outlet)
+{
+ int active = hg_log_outlet_active(hg_log_outlet->name);
+
+ if (active > 0 || hg_log_outlet->state == HG_LOG_ON)
+ hg_log_outlet->level = hg_log_level_g;
+ else if (!(active < 0) && hg_log_outlet->state == HG_LOG_PASS && hg_log_outlet->parent)
+ hg_log_outlet->level = hg_log_outlet->parent->level;
+ else
+ hg_log_outlet->level = HG_LOG_LEVEL_NONE;
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_log_outlet_update_all(void)
+{
+ struct hg_log_outlet *hg_log_outlet;
+
+ HG_QUEUE_FOREACH(hg_log_outlet, &hg_log_outlets_g, entry)
+ hg_log_outlet_update_level(hg_log_outlet);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_level(enum hg_log_level log_level)
+{
+ hg_log_level_g = log_level;
+
+ hg_log_outlet_update_all();
+}
+
+/*---------------------------------------------------------------------------*/
+enum hg_log_level
+hg_log_get_level(void)
+{
+ return hg_log_level_g;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_subsys(const char *log_subsys)
+{
+ char *subsys, *current, *next;
+ int i = 0;
+
+ subsys = strdup(log_subsys);
+ if (!subsys)
+ return;
+
+ current = subsys;
+
+ /* Reset all */
+ hg_log_outlet_reset_all();
+
+ /* Enable each of the subsys */
+ while (strtok_r(current, ",", &next) && i < HG_LOG_SUBSYS_MAX) {
+ int j, exist = 0;
+
+ /* Skip duplicates */
+ for (j = 0; j < i; j++) {
+ if (strcmp(current, hg_log_subsys_g[j]) == 0) {
+ exist = 1;
+ break;
+ }
+ }
+
+ if (!exist) {
+ strncpy(hg_log_subsys_g[i], current, HG_LOG_SUBSYS_NAME_MAX);
+ i++;
+ }
+ current = next;
+ }
+
+ /* Update outlets */
+ hg_log_outlet_update_all();
+
+ free(subsys);
+}
+
+/*---------------------------------------------------------------------------*/
+const char *
+hg_log_get_subsys(void)
+{
+ static char log_subsys[HG_LOG_SUBSYS_MAX * (HG_LOG_SUBSYS_NAME_MAX + 2)] = "\0";
+ char * p = log_subsys;
+ int i = 0;
+
+ while (hg_log_subsys_g[i][0] != '\0' && i < HG_LOG_SUBSYS_MAX) {
+ strcpy(p, hg_log_subsys_g[i]);
+ p += strlen(hg_log_subsys_g[i]);
+ *p = ',';
+ p++;
+ i++;
+ }
+ if (i > 0)
+ *(p - 1) = '\0';
+
+ return (const char *)log_subsys;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_subsys_level(const char *subsys, enum hg_log_level log_level)
+{
+ const char *log_subsys = hg_log_get_subsys();
+ char * new_subsys = NULL;
+ const char *new_subsys_ptr;
+
+ if (strcmp(log_subsys, "") != 0) {
+ new_subsys = malloc(strlen(log_subsys) + strlen(subsys) + 2);
+ if (!new_subsys)
+ return;
+ strcpy(new_subsys, log_subsys);
+ strcat(new_subsys, ",");
+ strcat(new_subsys, subsys);
+ new_subsys_ptr = new_subsys;
+ }
+ else
+ new_subsys_ptr = subsys;
+
+ hg_log_set_level(log_level);
+ hg_log_set_subsys(new_subsys_ptr);
+
+ free(new_subsys);
+}
+
+/*---------------------------------------------------------------------------*/
+enum hg_log_level
+hg_log_name_to_level(const char *log_level)
+{
+ enum hg_log_level l = 0;
+
+ if (!log_level)
+ return HG_LOG_LEVEL_NONE;
+
+ while (strcasecmp(hg_log_level_name_g[l], log_level) != 0 && l != HG_LOG_LEVEL_MAX)
+ l++;
+
+ if (l == HG_LOG_LEVEL_MAX) {
+ fprintf(stderr, "Warning: invalid log level was passed, defaulting to none\n");
+ return HG_LOG_LEVEL_NONE;
+ }
+
+ return l;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_func(int (*log_func)(FILE *stream, const char *format, ...))
+{
+ hg_log_func_g = log_func;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_stream_debug(FILE *stream)
+{
+ hg_log_streams_g[HG_LOG_LEVEL_DEBUG] = stream;
+}
+
+/*---------------------------------------------------------------------------*/
+FILE *
+hg_log_get_stream_debug(void)
+{
+ return hg_log_streams_g[HG_LOG_LEVEL_DEBUG] ? hg_log_streams_g[HG_LOG_LEVEL_DEBUG]
+ : *hg_log_std_streams_g[HG_LOG_LEVEL_DEBUG];
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_stream_warning(FILE *stream)
+{
+ hg_log_streams_g[HG_LOG_LEVEL_WARNING] = stream;
+}
+
+/*---------------------------------------------------------------------------*/
+FILE *
+hg_log_get_stream_warning(void)
+{
+ return hg_log_streams_g[HG_LOG_LEVEL_WARNING] ? hg_log_streams_g[HG_LOG_LEVEL_WARNING]
+ : *hg_log_std_streams_g[HG_LOG_LEVEL_WARNING];
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_set_stream_error(FILE *stream)
+{
+ hg_log_streams_g[HG_LOG_LEVEL_ERROR] = stream;
+}
+
+/*---------------------------------------------------------------------------*/
+FILE *
+hg_log_get_stream_error(void)
+{
+ return hg_log_streams_g[HG_LOG_LEVEL_ERROR] ? hg_log_streams_g[HG_LOG_LEVEL_ERROR]
+ : *hg_log_std_streams_g[HG_LOG_LEVEL_ERROR];
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_outlet_register(struct hg_log_outlet *hg_log_outlet)
+{
+#ifndef HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+ if (!hg_log_init_g) {
+ /* Set here to prevent infinite loop */
+ hg_log_init_g = HG_UTIL_TRUE;
+ hg_log_init();
+ }
+#endif
+
+ hg_log_outlet_update_level(hg_log_outlet);
+
+ /* Inherit debug log if not set and parent has one */
+ if (!hg_log_outlet->debug_log && hg_log_outlet->parent && hg_log_outlet->parent->debug_log)
+ hg_log_outlet->debug_log = hg_log_outlet->parent->debug_log;
+
+ HG_QUEUE_PUSH_TAIL(&hg_log_outlets_g, hg_log_outlet, entry);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_log_write(struct hg_log_outlet *hg_log_outlet, enum hg_log_level log_level, const char *file,
+ unsigned int line, const char *func, const char *format, ...)
+{
+ char buf[HG_LOG_BUF_MAX];
+ FILE * stream = NULL;
+ const char *level_name = NULL;
+#ifdef HG_UTIL_HAS_LOG_COLOR
+ const char *color = hg_log_colors_g[log_level];
+#endif
+ hg_time_t tv;
+ va_list ap;
+
+ if (!(log_level > HG_LOG_LEVEL_NONE && log_level < HG_LOG_LEVEL_MAX))
+ return;
+
+ hg_time_get_current(&tv);
+ level_name = hg_log_level_name_g[log_level];
+ stream = hg_log_streams_g[log_level] ? hg_log_streams_g[log_level] : *hg_log_std_streams_g[log_level];
+#ifdef HG_UTIL_HAS_LOG_COLOR
+ color = hg_log_colors_g[log_level];
+#endif
+
+ va_start(ap, format);
+ vsnprintf(buf, HG_LOG_BUF_MAX, format, ap);
+ va_end(ap);
+
+#ifdef HG_UTIL_HAS_LOG_COLOR
+ /* Print using logging function */
+ hg_log_func_g(stream,
+ "# %s%s[%lf] %s%s%s->%s%s: %s%s[%s]%s%s %s:%d %s\n"
+ "## %s%s%s()%s: %s%s%s%s\n",
+ HG_LOG_REG, HG_LOG_GREEN, hg_time_to_double(tv), HG_LOG_REG, HG_LOG_YELLOW, "mercury",
+ hg_log_outlet->name, HG_LOG_RESET, HG_LOG_BOLD, color, level_name, HG_LOG_REG, color, file,
+ line, HG_LOG_RESET, HG_LOG_REG, HG_LOG_YELLOW, func, HG_LOG_RESET, HG_LOG_REG,
+ log_level != HG_LOG_LEVEL_DEBUG ? color : HG_LOG_RESET, buf, HG_LOG_RESET);
+#else
+ /* Print using logging function */
+ hg_log_func_g(stream,
+ "# [%lf] %s->%s: [%s] %s:%d\n"
+ " # %s(): %s\n",
+ hg_time_to_double(tv), "mercury", hg_log_outlet->name, level_name, file, line, func, buf);
+#endif
+
+ if (log_level == HG_LOG_LEVEL_ERROR && hg_log_outlet->debug_log &&
+ hg_log_outlet->level >= HG_LOG_LEVEL_MIN_DEBUG) {
+ hg_dlog_dump(hg_log_outlet->debug_log, hg_log_func_g, stream, 0);
+ hg_dlog_resetlog(hg_log_outlet->debug_log);
+ }
+}
diff --git a/src/mercury/src/util/mercury_log.h b/src/mercury/src/util/mercury_log.h
new file mode 100644
index 0000000..0e98710
--- /dev/null
+++ b/src/mercury/src/util/mercury_log.h
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/*
+ * Copyright (c) 2004, 2005, 2006, 2007 David Young. All rights reserved.
+ *
+ * Copyright (c) 2004 Urbana-Champaign Independent Media Center.
+ * All rights reserved.
+ *
+ *
+ * Portions of hlog are Copyright (c) David Young. The applicable copyright
+ * notice and licensing terms are reproduced here:
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 David Young. All rights reserved.
+ *
+ * This file contains code contributed by David Young.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * -----------------------------------------------------------------------------
+ * -----------------------------------------------------------------------------
+ *
+ * Portions of hlog are Copyright (c) Urbana-Champaign Independent Media Center.
+ * The applicable copyright notice and licensing terms are reproduced here:
+ *
+ * Copyright (c) 2004 Urbana-Champaign Independent Media Center.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
+ * MEDIA CENTER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MERCURY_LOG_H
+#define MERCURY_LOG_H
+
+#include "mercury_dlog.h"
+#include "mercury_queue.h"
+#include "mercury_util_config.h"
+
+#include <stdio.h>
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* For compatibility */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)
+#if defined(__GNUC__) && (__GNUC__ >= 2)
+#define __func__ __FUNCTION__
+#else
+#define __func__ "<unknown>"
+#endif
+#elif defined(_WIN32)
+#define __func__ __FUNCTION__
+#endif
+
+/* Cat macro */
+#define HG_UTIL_CAT(x, y) x##y
+
+/* Stringify macro */
+#define HG_UTIL_STRINGIFY(x) #x
+
+/* Constructor (used to initialize log outlets) */
+#define HG_UTIL_CONSTRUCTOR __attribute__((constructor))
+
+/* Available log levels, additional log levels should be added to that list by
+ * order of verbosity. Format is:
+ * - enum type
+ * - level name
+ * - default output
+ *
+ * error: print error level logs
+ * warning: print warning level logs
+ * min_debug: store minimal debug information and defer printing until error
+ * debug: print debug level logs
+ */
+#define HG_LOG_LEVELS \
+ X(HG_LOG_LEVEL_NONE, "", NULL) /*!< no log */ \
+ X(HG_LOG_LEVEL_ERROR, "error", &stderr) /*!< error log type */ \
+ X(HG_LOG_LEVEL_WARNING, "warning", &stdout) /*!< warning log type */ \
+ X(HG_LOG_LEVEL_MIN_DEBUG, "min_debug", &stdout) /*!< debug log type */ \
+ X(HG_LOG_LEVEL_DEBUG, "debug", &stdout) /*!< debug log type */ \
+ X(HG_LOG_LEVEL_MAX, "", NULL)
+
+/* HG_LOG_OUTLET: global variable name of log outlet. */
+#define HG_LOG_OUTLET(name) HG_UTIL_CAT(name, _log_outlet_g)
+
+/* HG_LOG_OUTLET_DECL: declare an outlet. */
+#define HG_LOG_OUTLET_DECL(name) struct hg_log_outlet HG_LOG_OUTLET(name)
+
+/*
+ * HG_LOG_OUTLET_INITIALIZER: initializer for a log in a global variable.
+ * (parent and debug_log are optional and can be set to NULL)
+ */
+#define HG_LOG_OUTLET_INITIALIZER(name, state, parent, debug_log) \
+ { \
+ HG_UTIL_STRINGIFY(name), state, HG_LOG_LEVEL_NONE, parent, debug_log, { NULL } \
+ }
+
+/* HG_LOG_OUTLET_SUBSYS_INITIALIZER: initializer for a sub-system log. */
+#define HG_LOG_OUTLET_SUBSYS_INITIALIZER(name, parent_name) \
+ HG_LOG_OUTLET_INITIALIZER(name, HG_LOG_PASS, &HG_LOG_OUTLET(parent_name), NULL)
+
+/* HG_LOG_OUTLET_SUBSYS_STATE_INITIALIZER: initializer for a sub-system log with
+ * a defined state. */
+#define HG_LOG_OUTLET_SUBSYS_STATE_INITIALIZER(name, parent_name, state) \
+ HG_LOG_OUTLET_INITIALIZER(name, state, &HG_LOG_OUTLET(parent_name), NULL)
+
+/* HG_LOG_SUBSYS_REGISTER: register a name */
+#define HG_LOG_SUBSYS_REGISTER(name) \
+ static void HG_UTIL_CAT(hg_log_outlet_, name)(void) HG_UTIL_CONSTRUCTOR; \
+ static void HG_UTIL_CAT(hg_log_outlet_, name)(void) { hg_log_outlet_register(&HG_LOG_OUTLET(name)); } \
+ /* Keep unused prototype to use semicolon at end of macro */ \
+ void hg_log_outlet_##name##_unused(void)
+
+/* HG_LOG_SUBSYS_DECL_REGISTER: declare and register a log outlet. */
+#define HG_LOG_SUBSYS_DECL_REGISTER(name, parent_name) \
+ struct hg_log_outlet HG_LOG_OUTLET(name) = HG_LOG_OUTLET_SUBSYS_INITIALIZER(name, parent_name); \
+ HG_LOG_SUBSYS_REGISTER(name)
+
+/* HG_LOG_SUBSYS_DECL_STATE_REGISTER: declare and register a log outlet and
+ * enforce an init state. */
+#define HG_LOG_SUBSYS_DECL_STATE_REGISTER(name, parent_name, state) \
+ struct hg_log_outlet HG_LOG_OUTLET(name) = \
+ HG_LOG_OUTLET_SUBSYS_STATE_INITIALIZER(name, parent_name, state); \
+ HG_LOG_SUBSYS_REGISTER(name)
+
+/* Log macro */
+#define HG_LOG_WRITE(name, log_level, ...) \
+ do { \
+ if (HG_LOG_OUTLET(name).level < log_level) \
+ break; \
+ hg_log_write(&HG_LOG_OUTLET(name), log_level, __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } while (0)
+
+/* Log macro */
+#define HG_LOG_WRITE_DEBUG(name, debug_func, ...) \
+ do { \
+ if (HG_LOG_OUTLET(name).level < HG_LOG_LEVEL_MIN_DEBUG) \
+ break; \
+ if (HG_LOG_OUTLET(name).level >= HG_LOG_LEVEL_MIN_DEBUG && HG_LOG_OUTLET(name).debug_log) \
+ hg_dlog_addlog(HG_LOG_OUTLET(name).debug_log, __FILE__, __LINE__, __func__, NULL, NULL); \
+ if (HG_LOG_OUTLET(name).level == HG_LOG_LEVEL_DEBUG) { \
+ hg_log_write(&HG_LOG_OUTLET(name), HG_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __func__, \
+ __VA_ARGS__); \
+ debug_func; \
+ } \
+ } while (0)
+
+/**
+ * Additional macros for debug log support.
+ */
+
+/* HG_LOG_DEBUG_DLOG: global variable name of debug log. */
+#define HG_LOG_DEBUG_DLOG(name) HG_UTIL_CAT(name, _dlog_g)
+
+/* HG_LOG_DEBUG_LE: global variable name of debug log entries. */
+#define HG_LOG_DEBUG_LE(name) HG_UTIL_CAT(name, _dlog_entries_g)
+
+/* HG_LOG_DEBUG_DECL_DLOG: declare new debug log. */
+#define HG_LOG_DEBUG_DECL_DLOG(name) struct hg_dlog HG_LOG_DEBUG_DLOG(name)
+
+/* HG_LOG_DEBUG_DECL_LE: declare array of debug log entries. */
+#define HG_LOG_DEBUG_DECL_LE(name, size) struct hg_dlog_entry HG_LOG_DEBUG_LE(name)[size]
+
+/* HG_LOG_DLOG_INITIALIZER: initializer for a debug log */
+#define HG_LOG_DLOG_INITIALIZER(name, size) \
+ HG_DLOG_INITIALIZER(HG_UTIL_STRINGIFY(name), HG_LOG_DEBUG_LE(name), size, 1)
+
+/* HG_LOG_OUTLET_SUBSYS_DLOG_INITIALIZER: initializer for a sub-system with
+ * debug log. */
+#define HG_LOG_OUTLET_SUBSYS_DLOG_INITIALIZER(name, parent_name) \
+ HG_LOG_OUTLET_INITIALIZER(name, HG_LOG_PASS, &HG_LOG_OUTLET(parent_name), &HG_LOG_DEBUG_DLOG(name))
+
+/* HG_LOG_SUBSYS_DLOG_DECL_REGISTER: declare and register a log outlet with
+ * debug log. */
+#define HG_LOG_SUBSYS_DLOG_DECL_REGISTER(name, parent_name) \
+ struct hg_log_outlet HG_LOG_OUTLET(name) = HG_LOG_OUTLET_SUBSYS_DLOG_INITIALIZER(name, parent_name); \
+ HG_LOG_SUBSYS_REGISTER(name)
+
+/* HG_LOG_ADD_COUNTER32: add 32-bit debug log counter */
+#define HG_LOG_ADD_COUNTER32(name, counter_ptr, counter_name, counter_desc) \
+ hg_dlog_mkcount32(HG_LOG_OUTLET(name).debug_log, counter_ptr, counter_name, counter_desc)
+
+/* HG_LOG_ADD_COUNTER64: add 64-bit debug log counter */
+#define HG_LOG_ADD_COUNTER64(name, counter_ptr, counter_name, counter_desc) \
+ hg_dlog_mkcount64(HG_LOG_OUTLET(name)->debug_log, counter_ptr, counter_name, counter_desc)
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#define X(a, b, c) a,
+/* Log levels */
+enum hg_log_level { HG_LOG_LEVELS };
+#undef X
+
+/* Log states */
+enum hg_log_state { HG_LOG_PASS, HG_LOG_OFF, HG_LOG_ON };
+
+/* Log outlet */
+struct hg_log_outlet {
+ const char * name; /* Name of outlet */
+ enum hg_log_state state; /* Init state of outlet */
+ enum hg_log_level level; /* Level of outlet */
+ struct hg_log_outlet *parent; /* Parent of outlet */
+ struct hg_dlog * debug_log; /* Debug log to use */
+ HG_QUEUE_ENTRY(hg_log_outlet) entry; /* List entry */
+};
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Set the global log level.
+ *
+ * \param log_level [IN] enum log level type
+ */
+HG_UTIL_PUBLIC void hg_log_set_level(enum hg_log_level log_level);
+
+/**
+ * Get the global log level.
+ *
+ * \return global log_level
+ */
+HG_UTIL_PUBLIC enum hg_log_level hg_log_get_level(void);
+
+/**
+ * Set the log subsystems from a string. Format is: subsys1,subsys2,...
+ * Subsys can also be forced to be disabled with "~", e.g., ~subsys1
+ *
+ * \param log_level [IN] null terminated string
+ */
+HG_UTIL_PUBLIC void hg_log_set_subsys(const char *log_subsys);
+
+/**
+ * Get the log subsystems as a string. Format is similar to hg_log_set_subsys().
+ * Buffer returned is static.
+ *
+ * \return string of enabled log subsystems
+ */
+HG_UTIL_PUBLIC const char *hg_log_get_subsys(void);
+
+/**
+ * Set a specific subsystem's log level.
+ */
+HG_UTIL_PUBLIC void hg_log_set_subsys_level(const char *subsys, enum hg_log_level log_level);
+
+/**
+ * Get the log level from a string.
+ *
+ * \param log_level [IN] null terminated string
+ *
+ * \return log type enum value
+ */
+HG_UTIL_PUBLIC enum hg_log_level hg_log_name_to_level(const char *log_level);
+
+/**
+ * Set the logging function.
+ *
+ * \param log_func [IN] pointer to function
+ */
+HG_UTIL_PUBLIC void hg_log_set_func(int (*log_func)(FILE *stream, const char *format, ...));
+
+/**
+ * Set the stream for error output.
+ *
+ * \param stream [IN/OUT] pointer to stream
+ */
+HG_UTIL_PUBLIC void hg_log_set_stream_error(FILE *stream);
+
+/**
+ * Get the stream for error output.
+ *
+ * \return pointer to stream
+ */
+HG_UTIL_PUBLIC FILE *hg_log_get_stream_error(void);
+
+/**
+ * Set the stream for warning output.
+ *
+ * \param stream [IN/OUT] pointer to stream
+ */
+HG_UTIL_PUBLIC void hg_log_set_stream_warning(FILE *stream);
+
+/**
+ * Get the stream for warning output.
+ *
+ * \return pointer to stream
+ */
+HG_UTIL_PUBLIC FILE *hg_log_get_stream_warning(void);
+
+/**
+ * Set the stream for debug output.
+ *
+ * \param stream [IN/OUT] pointer to stream
+ */
+HG_UTIL_PUBLIC void hg_log_set_stream_debug(FILE *stream);
+
+/**
+ * Get the stream for debug output.
+ *
+ * \return pointer to stream
+ */
+HG_UTIL_PUBLIC FILE *hg_log_get_stream_debug(void);
+
+/**
+ * Register log outlet.
+ *
+ * \param outlet [IN] log outlet
+ */
+HG_UTIL_PUBLIC void hg_log_outlet_register(struct hg_log_outlet *outlet);
+
+/**
+ * Write log.
+ *
+ * \param outlet [IN] log outlet
+ * \param log_level [IN] log level
+ * \param file [IN] file name
+ * \param line [IN] line number
+ * \param func [IN] function name
+ * \param format [IN] string format
+ */
+HG_UTIL_PUBLIC void hg_log_write(struct hg_log_outlet *outlet, enum hg_log_level log_level, const char *file,
+ unsigned int line, const char *func, const char *format, ...)
+ HG_UTIL_PRINTF_LIKE(6, 7);
+
+/*********************/
+/* Public Variables */
+/*********************/
+
+/* Top error outlet */
+extern HG_UTIL_PUBLIC HG_LOG_OUTLET_DECL(hg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_LOG_H */
diff --git a/src/mercury/src/util/mercury_mem.c b/src/mercury/src/util/mercury_mem.c
new file mode 100644
index 0000000..ae57cdf
--- /dev/null
+++ b/src/mercury/src/util/mercury_mem.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_mem.h"
+
+#include "mercury_util_error.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <errno.h>
+#include <fcntl.h> /* For O_* constants */
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+
+/*---------------------------------------------------------------------------*/
+long
+hg_mem_get_page_size(void)
+{
+ static long page_size = 0;
+
+ if (page_size == 0) {
+#ifdef _WIN32
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ page_size = system_info.dwPageSize;
+#else
+ page_size = sysconf(_SC_PAGE_SIZE);
+#endif
+ }
+
+ return page_size;
+}
+
+/*---------------------------------------------------------------------------*/
+void *
+hg_mem_aligned_alloc(size_t alignment, size_t size)
+{
+ void *mem_ptr = NULL;
+
+#ifdef _WIN32
+ mem_ptr = _aligned_malloc(size, alignment);
+#else
+#ifdef _ISOC11_SOURCE
+ mem_ptr = aligned_alloc(alignment, size);
+#else
+ int rc = posix_memalign(&mem_ptr, alignment, size);
+ if (rc != 0)
+ return NULL;
+#endif
+#endif
+
+ return mem_ptr;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_mem_aligned_free(void *mem_ptr)
+{
+#ifdef _WIN32
+ _aligned_free(mem_ptr);
+#else
+ free(mem_ptr);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+void *
+hg_mem_header_alloc(size_t header_size, size_t alignment, size_t size)
+{
+ const size_t pad =
+ (alignment == 0 || header_size % alignment == 0) ? 0 : alignment - header_size % alignment;
+
+ return (char *)malloc(header_size + pad + size) + header_size + pad;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_mem_header_free(size_t header_size, size_t alignment, void *mem_ptr)
+{
+ const size_t pad =
+ (alignment == 0 || header_size % alignment == 0) ? 0 : alignment - header_size % alignment;
+
+ free((char *)mem_ptr - header_size - pad);
+}
+
+/*---------------------------------------------------------------------------*/
+void *
+hg_mem_shm_map(const char *name, size_t size, hg_util_bool_t create)
+{
+ void *mem_ptr = NULL;
+#ifdef _WIN32
+ HANDLE fd = INVALID_HANDLE_VALUE;
+ LARGE_INTEGER large = {.QuadPart = size};
+ DWORD access = FILE_MAP_READ | FILE_MAP_WRITE;
+ BOOL rc;
+
+ if (create) {
+ fd = CreateFileMappingA(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, large.HighPart, large.LowPart, name);
+ HG_UTIL_CHECK_ERROR_NORET(!fd, error, "CreateFileMappingA() failed");
+ }
+ else {
+ fd = OpenFileMappingA(access, FALSE, name);
+ HG_UTIL_CHECK_ERROR_NORET(!fd, error, "OpenFileMappingA() failed");
+ }
+
+ mem_ptr = MapViewOfFile(fd, access, 0, 0, size);
+ HG_UTIL_CHECK_ERROR_NORET(!mem_ptr, error, "MapViewOfFile() failed");
+
+ /* The handle can be closed without affecting the memory mapping */
+ rc = CloseHandle(fd);
+ HG_UTIL_CHECK_ERROR_NORET(!rc, error, "CloseHandle() failed");
+#else
+ int fd = 0;
+ int flags = O_RDWR | (create ? O_CREAT : 0);
+ struct stat shm_stat;
+ int rc;
+
+ fd = shm_open(name, flags, S_IRUSR | S_IWUSR);
+ HG_UTIL_CHECK_ERROR_NORET(fd < 0, error, "shm_open() failed (%s)", strerror(errno));
+
+ rc = fstat(fd, &shm_stat);
+ HG_UTIL_CHECK_ERROR_NORET(rc != 0, error, "fstat() failed (%s)", strerror(errno));
+
+ if (shm_stat.st_size == 0) {
+ rc = ftruncate(fd, (off_t)size);
+ HG_UTIL_CHECK_ERROR_NORET(rc != 0, error, "ftruncate() failed (%s)", strerror(errno));
+ }
+ else
+ HG_UTIL_CHECK_ERROR_NORET(shm_stat.st_size < (off_t)size, error, "shm file size too small");
+
+ mem_ptr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
+ HG_UTIL_CHECK_ERROR_NORET(mem_ptr == MAP_FAILED, error, "mmap() failed (%s)", strerror(errno));
+
+ /* The file descriptor can be closed without affecting the memory mapping */
+ rc = close(fd);
+ HG_UTIL_CHECK_ERROR_NORET(rc != 0, error, "close() failed (%s)", strerror(errno));
+#endif
+
+ return mem_ptr;
+
+error:
+#ifdef _WIN32
+ if (fd)
+ CloseHandle(fd);
+#else
+ if (fd > 0)
+ close(fd);
+#endif
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_mem_shm_unmap(const char *name, void *mem_ptr, size_t size)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#ifdef _WIN32
+ if (mem_ptr) {
+ BOOL rc = UnmapViewOfFile(mem_ptr);
+ HG_UTIL_CHECK_ERROR(!rc, done, ret, HG_UTIL_FAIL, "UnmapViewOfFile() failed");
+ }
+#else
+ if (mem_ptr && mem_ptr != MAP_FAILED) {
+ int rc = munmap(mem_ptr, size);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "munmap() failed (%s)", strerror(errno));
+ }
+
+ if (name) {
+ int rc = shm_unlink(name);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "shm_unlink() failed (%s)", strerror(errno));
+ }
+#endif
+
+done:
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_mem.h b/src/mercury/src/util/mercury_mem.h
new file mode 100644
index 0000000..3c15c01
--- /dev/null
+++ b/src/mercury/src/util/mercury_mem.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_MEM_H
+#define MERCURY_MEM_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+#define HG_MEM_CACHE_LINE_SIZE 64
+#define HG_MEM_PAGE_SIZE 4096
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get system default page size.
+ *
+ * \return page size on success or negative on failure
+ */
+HG_UTIL_PUBLIC long hg_mem_get_page_size(void);
+
+/**
+ * Allocate size bytes and return a pointer to the allocated memory.
+ * The memory address will be a multiple of alignment, which must be a power of
+ * two, and size should be a multiple of alignment.
+ *
+ * \param alignment [IN] alignment size
+ * \param size [IN] total requested size
+ *
+ * \return a pointer to the allocated memory, or NULL in case of failure
+ */
+HG_UTIL_PUBLIC void *hg_mem_aligned_alloc(size_t alignment, size_t size);
+
+/**
+ * Free memory allocated from hg_aligned_alloc().
+ *
+ * \param mem_ptr [IN] pointer to allocated memory
+ */
+HG_UTIL_PUBLIC void hg_mem_aligned_free(void *mem_ptr);
+
+/**
+ * Allocate a buffer with a `size`-bytes, `alignment`-aligned payload
+ * preceded by a `header_size` header, padding the allocation with up
+ * to `alignment - 1` bytes to ensure that the payload is properly aligned.
+ *
+ * If `alignment` is 0, do not try to align the payload. It's ok if
+ * `size` is 0, however, behavior is undefined if both `header_size`
+ * and `size` are 0.
+ *
+ * \param header_size [IN] size of header
+ * \param alignment [IN] alignment size
+ * \param size [IN] requested payload size
+ *
+ * \return a pointer to the payload or NULL on failure
+ */
+HG_UTIL_PUBLIC void *hg_mem_header_alloc(size_t header_size, size_t alignment, size_t size);
+
+/**
+ * Free the memory that was returned previously by a call to
+ * `hg_mem_header_alloc()`.
+ *
+ * \param header_size [IN] size of header
+ * \param alignment [IN] alignment size
+ * \param mem_ptr [IN] memory pointer
+ */
+HG_UTIL_PUBLIC void hg_mem_header_free(size_t header_size, size_t alignment, void *mem_ptr);
+
+/**
+ * Create/open a shared-memory mapped file of size \size with name \name.
+ *
+ * \param name [IN] name of mapped file
+ * \param size [IN] total requested size
+ * \param create [IN] create file if not existing
+ *
+ * \return a pointer to the mapped memory region, or NULL in case of failure
+ */
+HG_UTIL_PUBLIC void *hg_mem_shm_map(const char *name, size_t size, hg_util_bool_t create);
+
+/**
+ * Unmap a previously mapped region and close the file.
+ *
+ * \param name [IN] name of mapped file
+ * \param mem_ptr [IN] pointer to mapped memory region
+ * \param size [IN] size range of the mapped region
+ *
+ * \return non-negative on success, or negative in case of failure
+ */
+HG_UTIL_PUBLIC int hg_mem_shm_unmap(const char *name, void *mem_ptr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_MEM_H */
diff --git a/src/mercury/src/util/mercury_mem_pool.c b/src/mercury/src/util/mercury_mem_pool.c
new file mode 100644
index 0000000..d97b438
--- /dev/null
+++ b/src/mercury/src/util/mercury_mem_pool.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_mem_pool.h"
+
+#include "mercury_mem.h"
+#include "mercury_queue.h"
+#include "mercury_thread_condition.h"
+#include "mercury_thread_mutex.h"
+#include "mercury_thread_spin.h"
+#include "mercury_util_error.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/**
+ * container_of - cast a member of a structure done to the containing structure
+ * \ptr: the pointer to the member.
+ * \type: the type of the container struct this is embedded in.
+ * \member: the name of the member within the struct.
+ *
+ */
+#if !defined(container_of)
+#define container_of(ptr, type, member) ((type *)((char *)ptr - offsetof(type, member)))
+#endif
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+/**
+ * Memory chunk (points to actual data).
+ */
+struct hg_mem_pool_chunk {
+ HG_QUEUE_ENTRY(hg_mem_pool_chunk) entry; /* Entry in chunk_list */
+ char *chunk; /* Must be last */
+};
+
+/**
+ * Memory block. Each block has a fixed chunk size, the underlying memory
+ * buffer is registered.
+ */
+struct hg_mem_pool_block {
+ HG_QUEUE_HEAD(hg_mem_pool_chunk) chunks; /* Chunk list */
+ HG_QUEUE_ENTRY(hg_mem_pool_block) entry; /* Entry in block list */
+ void * mr_handle; /* Pointer to MR handle */
+ hg_thread_spin_t chunk_lock; /* Chunk list lock */
+};
+
+/**
+ * Memory pool. A pool is composed of multiple blocks.
+ */
+struct hg_mem_pool {
+ hg_thread_mutex_t extend_mutex; /* Extend mutex */
+ hg_thread_cond_t extend_cond; /* Extend cond */
+ HG_QUEUE_HEAD(hg_mem_pool_block) blocks; /* Block list */
+ hg_mem_pool_register_func_t register_func; /* Register func */
+ hg_mem_pool_deregister_func_t deregister_func; /* Deregister func */
+ void * arg; /* Func args */
+ size_t chunk_size; /* Chunk size */
+ size_t chunk_count; /* Chunk count */
+ int extending; /* Extending pool */
+ hg_thread_spin_t block_lock; /* Block list lock */
+};
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/* Allocate new pool block */
+static struct hg_mem_pool_block *hg_mem_pool_block_alloc(size_t chunk_size, size_t chunk_count,
+ hg_mem_pool_register_func_t register_func,
+ void * arg);
+
+/* Free pool block */
+static void hg_mem_pool_block_free(struct hg_mem_pool_block * hg_mem_pool_block,
+ hg_mem_pool_deregister_func_t deregister_func, void *arg);
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*---------------------------------------------------------------------------*/
+
+struct hg_mem_pool *
+hg_mem_pool_create(size_t chunk_size, size_t chunk_count, size_t block_count,
+ hg_mem_pool_register_func_t register_func, hg_mem_pool_deregister_func_t deregister_func,
+ void *arg)
+{
+ struct hg_mem_pool *hg_mem_pool = NULL;
+ size_t i;
+
+ hg_mem_pool = (struct hg_mem_pool *)malloc(sizeof(struct hg_mem_pool));
+ HG_UTIL_CHECK_ERROR_NORET(hg_mem_pool == NULL, done, "Could not allocate memory pool");
+ HG_QUEUE_INIT(&hg_mem_pool->blocks);
+ hg_mem_pool->register_func = register_func;
+ hg_mem_pool->deregister_func = deregister_func;
+ hg_mem_pool->arg = arg;
+ hg_mem_pool->chunk_size = chunk_size;
+ hg_mem_pool->chunk_count = chunk_count;
+ hg_thread_mutex_init(&hg_mem_pool->extend_mutex);
+ hg_thread_cond_init(&hg_mem_pool->extend_cond);
+ hg_thread_spin_init(&hg_mem_pool->block_lock);
+ hg_mem_pool->extending = 0;
+
+ /* Allocate single block */
+ for (i = 0; i < block_count; i++) {
+ struct hg_mem_pool_block *hg_mem_pool_block =
+ hg_mem_pool_block_alloc(chunk_size, chunk_count, register_func, arg);
+ HG_UTIL_CHECK_ERROR_NORET(hg_mem_pool_block == NULL, error, "Could not allocate block of %zu bytes",
+ chunk_size * chunk_count);
+ HG_QUEUE_PUSH_TAIL(&hg_mem_pool->blocks, hg_mem_pool_block, entry);
+ }
+
+done:
+ return hg_mem_pool;
+
+error:
+ hg_mem_pool_destroy(hg_mem_pool);
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_mem_pool_destroy(struct hg_mem_pool *hg_mem_pool)
+{
+ if (!hg_mem_pool)
+ return;
+
+ while (!HG_QUEUE_IS_EMPTY(&hg_mem_pool->blocks)) {
+ struct hg_mem_pool_block *hg_mem_pool_block = HG_QUEUE_FIRST(&hg_mem_pool->blocks);
+ HG_QUEUE_POP_HEAD(&hg_mem_pool->blocks, entry);
+ hg_mem_pool_block_free(hg_mem_pool_block, hg_mem_pool->deregister_func, hg_mem_pool->arg);
+ }
+ hg_thread_mutex_destroy(&hg_mem_pool->extend_mutex);
+ hg_thread_cond_destroy(&hg_mem_pool->extend_cond);
+ hg_thread_spin_destroy(&hg_mem_pool->block_lock);
+ free(hg_mem_pool);
+}
+
+/*---------------------------------------------------------------------------*/
+static struct hg_mem_pool_block *
+hg_mem_pool_block_alloc(size_t chunk_size, size_t chunk_count, hg_mem_pool_register_func_t register_func,
+ void *arg)
+{
+ struct hg_mem_pool_block *hg_mem_pool_block = NULL;
+ size_t page_size = (size_t)hg_mem_get_page_size();
+ void * mem_ptr = NULL, *mr_handle = NULL;
+ size_t block_size, i;
+ size_t block_header = sizeof(struct hg_mem_pool_block);
+ size_t chunk_header = offsetof(struct hg_mem_pool_chunk, chunk);
+
+ /* Size of block struct + number of chunks x (chunk_size + size of entry) */
+ block_size = block_header + chunk_count * (chunk_header + chunk_size);
+
+ /* Allocate backend buffer */
+ mem_ptr = hg_mem_aligned_alloc(page_size, block_size);
+ HG_UTIL_CHECK_ERROR_NORET(mem_ptr == NULL, done, "Could not allocate %zu bytes", block_size);
+ memset(mem_ptr, 0, block_size);
+
+ /* Register memory if registration function is provided */
+ if (register_func) {
+ int rc = register_func(mem_ptr, block_size, &mr_handle, arg);
+ if (unlikely(rc != HG_UTIL_SUCCESS)) {
+ hg_mem_aligned_free(mem_ptr);
+ HG_UTIL_GOTO_ERROR(done, mem_ptr, NULL, "register_func() failed");
+ }
+ }
+
+ /* Map allocated memory to block */
+ hg_mem_pool_block = (struct hg_mem_pool_block *)mem_ptr;
+
+ HG_QUEUE_INIT(&hg_mem_pool_block->chunks);
+ hg_thread_spin_init(&hg_mem_pool_block->chunk_lock);
+ hg_mem_pool_block->mr_handle = mr_handle;
+
+ /* Assign chunks and insert them to free list */
+ for (i = 0; i < chunk_count; i++) {
+ struct hg_mem_pool_chunk *hg_mem_pool_chunk =
+ (struct hg_mem_pool_chunk *)((char *)hg_mem_pool_block + block_header +
+ i * (chunk_header + chunk_size));
+ HG_QUEUE_PUSH_TAIL(&hg_mem_pool_block->chunks, hg_mem_pool_chunk, entry);
+ }
+
+done:
+ return hg_mem_pool_block;
+}
+
+/*---------------------------------------------------------------------------*/
+static void
+hg_mem_pool_block_free(struct hg_mem_pool_block * hg_mem_pool_block,
+ hg_mem_pool_deregister_func_t deregister_func, void *arg)
+{
+ if (!hg_mem_pool_block)
+ return;
+
+ /* Release MR handle is there was any */
+ if (hg_mem_pool_block->mr_handle && deregister_func) {
+ int rc = deregister_func(hg_mem_pool_block->mr_handle, arg);
+ HG_UTIL_CHECK_ERROR_NORET(rc != HG_UTIL_SUCCESS, done, "deregister_func() failed");
+ }
+
+done:
+ hg_thread_spin_destroy(&hg_mem_pool_block->chunk_lock);
+ hg_mem_aligned_free((void *)hg_mem_pool_block);
+ return;
+}
+
+/*---------------------------------------------------------------------------*/
+void *
+hg_mem_pool_alloc(struct hg_mem_pool *hg_mem_pool, size_t size, void **mr_handle)
+{
+ struct hg_mem_pool_block *hg_mem_pool_block;
+ struct hg_mem_pool_chunk *hg_mem_pool_chunk = NULL;
+ void * mem_ptr = NULL;
+
+ HG_UTIL_CHECK_ERROR(size > hg_mem_pool->chunk_size, done, mem_ptr, NULL,
+ "Chunk size is too small for requested size");
+ HG_UTIL_CHECK_ERROR(!mr_handle && hg_mem_pool->register_func, done, mem_ptr, NULL, "MR handle is NULL");
+
+ do {
+ int found = 0;
+
+ /* Check whether we can get a block from one of the pools */
+ hg_thread_spin_lock(&hg_mem_pool->block_lock);
+ HG_QUEUE_FOREACH(hg_mem_pool_block, &hg_mem_pool->blocks, entry)
+ {
+ hg_thread_spin_lock(&hg_mem_pool_block->chunk_lock);
+ found = !HG_QUEUE_IS_EMPTY(&hg_mem_pool_block->chunks);
+ hg_thread_spin_unlock(&hg_mem_pool_block->chunk_lock);
+ if (found)
+ break;
+ }
+ hg_thread_spin_unlock(&hg_mem_pool->block_lock);
+
+ /* If not, allocate and register a new pool */
+ if (!found) {
+ /* Let other threads sleep while the pool is being extended */
+ hg_thread_mutex_lock(&hg_mem_pool->extend_mutex);
+ if (hg_mem_pool->extending) {
+ hg_thread_cond_wait(&hg_mem_pool->extend_cond, &hg_mem_pool->extend_mutex);
+ hg_thread_mutex_unlock(&hg_mem_pool->extend_mutex);
+ continue;
+ }
+ hg_mem_pool->extending = 1;
+ hg_thread_mutex_unlock(&hg_mem_pool->extend_mutex);
+
+ hg_mem_pool_block = hg_mem_pool_block_alloc(hg_mem_pool->chunk_size, hg_mem_pool->chunk_count,
+ hg_mem_pool->register_func, hg_mem_pool->arg);
+ HG_UTIL_CHECK_ERROR(hg_mem_pool_block == NULL, done, mem_ptr, NULL,
+ "Could not allocate block of %zu bytes",
+ hg_mem_pool->chunk_size * hg_mem_pool->chunk_count);
+
+ hg_thread_spin_lock(&hg_mem_pool->block_lock);
+ HG_QUEUE_PUSH_TAIL(&hg_mem_pool->blocks, hg_mem_pool_block, entry);
+ hg_thread_spin_unlock(&hg_mem_pool->block_lock);
+
+ hg_thread_mutex_lock(&hg_mem_pool->extend_mutex);
+ hg_mem_pool->extending = 0;
+ hg_thread_cond_broadcast(&hg_mem_pool->extend_cond);
+ hg_thread_mutex_unlock(&hg_mem_pool->extend_mutex);
+ }
+
+ /* Try to pick a node from one of the available pools */
+ hg_thread_spin_lock(&hg_mem_pool_block->chunk_lock);
+ if (!HG_QUEUE_IS_EMPTY(&hg_mem_pool_block->chunks)) {
+ hg_mem_pool_chunk = HG_QUEUE_FIRST(&hg_mem_pool_block->chunks);
+ HG_QUEUE_POP_HEAD(&hg_mem_pool_block->chunks, entry);
+ }
+ hg_thread_spin_unlock(&hg_mem_pool_block->chunk_lock);
+ } while (!hg_mem_pool_chunk);
+
+ mem_ptr = &hg_mem_pool_chunk->chunk;
+ if (mr_handle && hg_mem_pool_block)
+ *mr_handle = hg_mem_pool_block->mr_handle;
+
+done:
+ return mem_ptr;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_mem_pool_free(struct hg_mem_pool *hg_mem_pool, void *mem_ptr, void *mr_handle)
+{
+ struct hg_mem_pool_block *hg_mem_pool_block;
+ int found = 0;
+
+ if (!mem_ptr)
+ return;
+
+ /* Put the node back to the pool */
+ hg_thread_spin_lock(&hg_mem_pool->block_lock);
+ HG_QUEUE_FOREACH(hg_mem_pool_block, &hg_mem_pool->blocks, entry)
+ {
+ /* If MR handle is NULL, it does not really matter which pool we push
+ * the node back to.
+ */
+ if (hg_mem_pool_block->mr_handle == mr_handle) {
+ struct hg_mem_pool_chunk *hg_mem_pool_chunk =
+ container_of(mem_ptr, struct hg_mem_pool_chunk, chunk);
+ hg_thread_spin_lock(&hg_mem_pool_block->chunk_lock);
+ HG_QUEUE_PUSH_TAIL(&hg_mem_pool_block->chunks, hg_mem_pool_chunk, entry);
+ hg_thread_spin_unlock(&hg_mem_pool_block->chunk_lock);
+ found = 1;
+ break;
+ }
+ }
+ hg_thread_spin_unlock(&hg_mem_pool->block_lock);
+
+ HG_UTIL_CHECK_WARNING(found != 1, "Memory block was not found");
+}
+
+/*---------------------------------------------------------------------------*/
+size_t
+hg_mem_pool_chunk_offset(struct hg_mem_pool *hg_mem_pool, void *mem_ptr, void *mr_handle)
+{
+ struct hg_mem_pool_block *hg_mem_pool_block;
+
+ hg_thread_spin_lock(&hg_mem_pool->block_lock);
+ HG_QUEUE_FOREACH(hg_mem_pool_block, &hg_mem_pool->blocks, entry)
+ if (hg_mem_pool_block->mr_handle == mr_handle)
+ break;
+ hg_thread_spin_unlock(&hg_mem_pool->block_lock);
+
+ return (size_t)((char *)mem_ptr - (char *)hg_mem_pool_block);
+}
diff --git a/src/mercury/src/util/mercury_mem_pool.h b/src/mercury/src/util/mercury_mem_pool.h
new file mode 100644
index 0000000..d2acfdd
--- /dev/null
+++ b/src/mercury/src/util/mercury_mem_pool.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_MEM_POOL_H
+#define MERCURY_MEM_POOL_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/**
+ * Register memory block.
+ *
+ * \param buf [IN] pointer to buffer
+ * \param size [IN] buffer size
+ * \param handle [OUT] handle
+ * \param arg [IN/OUT] optional arguments
+ *
+ * \return HG_UTIL_SUCCESS if successful / error code otherwise
+ */
+typedef int (*hg_mem_pool_register_func_t)(const void *buf, size_t size, void **handle, void *arg);
+
+/**
+ * Deregister memory block.
+ *
+ * \param handle [IN/OUT] handle
+ * \param arg [IN/OUT] optional arguments
+ *
+ * \return HG_UTIL_SUCCESS if successful / error code otherwise
+ */
+typedef int (*hg_mem_pool_deregister_func_t)(void *handle, void *arg);
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a memory pool with \block_count of size \chunk_count x \chunk_size
+ * bytes. Optionally register and deregister memory for each block using
+ * \register_func and \deregister_func respectively.
+ *
+ * \param chunk_size [IN] size of chunks
+ * \param chunk_count [IN] number of chunks
+ * \param block_count [IN] number of blocks
+ * \param register_func [IN] pointer to register function
+ * \param deregister_func [IN] pointer to deregister function
+ * \param arg [IN/OUT] optional arguments passed to register functions
+ *
+ * \return HG_UTIL_SUCCESS if successful / error code otherwise
+ */
+HG_UTIL_PUBLIC struct hg_mem_pool *hg_mem_pool_create(size_t chunk_size, size_t chunk_count,
+ size_t block_count,
+ hg_mem_pool_register_func_t register_func,
+ hg_mem_pool_deregister_func_t deregister_func,
+ void * arg);
+
+/**
+ * Destroy a memory pool.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ *
+ */
+HG_UTIL_PUBLIC void hg_mem_pool_destroy(struct hg_mem_pool *hg_mem_pool);
+
+/**
+ * Allocate \size bytes and optionally return a memory handle
+ * \mr_handle if registration functions were provided.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ * \param size [IN] requested size
+ * \param mr_handle [OUT] pointer to memory handle
+ *
+ * \return pointer to memory block
+ */
+HG_UTIL_PUBLIC void *hg_mem_pool_alloc(struct hg_mem_pool *hg_mem_pool, size_t size, void **mr_handle);
+
+/**
+ * Release memory at address \mem_ptr.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ * \param mem_ptr [IN] pointer to memory
+ * \param mr_handle [INT] pointer to memory handle
+ *
+ */
+HG_UTIL_PUBLIC void hg_mem_pool_free(struct hg_mem_pool *hg_mem_pool, void *mem_ptr, void *mr_handle);
+
+/**
+ * Retrieve chunk offset relative to the address used for registering
+ * the memory block it belongs to.
+ *
+ * \param hg_mem_pool [IN/OUT] pointer to memory pool
+ * \param mem_ptr [IN] pointer to memory
+ * \param mr_handle [INT] pointer to memory handle
+ *
+ * \return offset within registered block.
+ */
+HG_UTIL_PUBLIC size_t hg_mem_pool_chunk_offset(struct hg_mem_pool *hg_mem_pool, void *mem_ptr,
+ void *mr_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_MEM_POOL_H */
diff --git a/src/mercury/src/util/mercury_poll.c b/src/mercury/src/util/mercury_poll.c
new file mode 100644
index 0000000..eb54a82
--- /dev/null
+++ b/src/mercury/src/util/mercury_poll.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_poll.h"
+#include "mercury_event.h"
+#include "mercury_thread_mutex.h"
+#include "mercury_util_error.h"
+
+#include <stdlib.h>
+
+#if defined(_WIN32)
+/* TODO */
+#else
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(HG_UTIL_HAS_SYSEPOLL_H)
+#include <sys/epoll.h>
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+#include <sys/event.h>
+#include <sys/time.h>
+#else
+#include <poll.h>
+#endif
+#endif /* defined(_WIN32) */
+
+/****************/
+/* Local Macros */
+/****************/
+
+#define HG_POLL_INIT_NEVENTS 32
+#define HG_POLL_MAX_EVENTS 4096
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+struct hg_poll_set {
+ hg_thread_mutex_t lock;
+#if defined(HG_UTIL_HAS_SYSEPOLL_H)
+ struct epoll_event *events;
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ struct kevent *events;
+#else
+ struct pollfd * events;
+ hg_poll_data_t *event_data;
+#endif
+ unsigned int max_events;
+ unsigned int nfds;
+ int fd;
+};
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*---------------------------------------------------------------------------*/
+hg_poll_set_t *
+hg_poll_create(void)
+{
+ struct hg_poll_set *hg_poll_set = NULL;
+
+ hg_poll_set = malloc(sizeof(struct hg_poll_set));
+ HG_UTIL_CHECK_ERROR_NORET(hg_poll_set == NULL, error, "malloc() failed (%s)", strerror(errno));
+
+ hg_thread_mutex_init(&hg_poll_set->lock);
+ hg_poll_set->nfds = 0;
+ hg_poll_set->max_events = HG_POLL_INIT_NEVENTS;
+
+ /* Preallocate events, size will grow as needed */
+ hg_poll_set->events = malloc(sizeof(*hg_poll_set->events) * hg_poll_set->max_events);
+ HG_UTIL_CHECK_ERROR_NORET(!hg_poll_set->events, error, "malloc() failed (%s)", strerror(errno));
+
+#if defined(_WIN32)
+ /* TODO */
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H)
+ hg_poll_set->fd = epoll_create1(0);
+ HG_UTIL_CHECK_ERROR_NORET(hg_poll_set->fd == -1, error, "epoll_create1() failed (%s)", strerror(errno));
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ hg_poll_set->fd = kqueue();
+ HG_UTIL_CHECK_ERROR_NORET(hg_poll_set->fd == -1, error, "kqueue() failed (%s)", strerror(errno));
+#else
+ hg_poll_set->fd = hg_event_create();
+ HG_UTIL_CHECK_ERROR_NORET(hg_poll_set->fd == -1, error, "hg_event_create() failed (%s)", strerror(errno));
+
+ /* Preallocate event_data, size will grow as needed */
+ hg_poll_set->event_data = malloc(sizeof(*hg_poll_set->event_data) * hg_poll_set->max_events);
+ HG_UTIL_CHECK_ERROR_NORET(!hg_poll_set->events, error, "malloc() failed (%s)", strerror(errno));
+#endif
+ HG_UTIL_LOG_DEBUG("Created new poll set, fd=%d", hg_poll_set->fd);
+
+ return hg_poll_set;
+
+error:
+ if (hg_poll_set) {
+ free(hg_poll_set->events);
+ hg_thread_mutex_destroy(&hg_poll_set->lock);
+ free(hg_poll_set);
+ }
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_poll_destroy(hg_poll_set_t *poll_set)
+{
+ int ret = HG_UTIL_SUCCESS;
+ int rc;
+
+ if (!poll_set)
+ goto done;
+
+ HG_UTIL_CHECK_ERROR(poll_set->nfds > 0, done, ret, HG_UTIL_FAIL, "Poll set non empty");
+
+ HG_UTIL_LOG_DEBUG("Destroying poll set, fd=%d", poll_set->fd);
+
+#if defined(_WIN32)
+ /* TODO */
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H) || defined(HG_UTIL_HAS_SYSEVENT_H)
+ /* Close poll descriptor */
+ rc = close(poll_set->fd);
+ HG_UTIL_CHECK_ERROR(rc == -1, done, ret, HG_UTIL_FAIL, "close() failed (%s)", strerror(errno));
+#else
+ rc = hg_event_destroy(poll_set->fd);
+ HG_UTIL_CHECK_ERROR(rc == HG_UTIL_FAIL, done, ret, HG_UTIL_FAIL, "hg_event_destroy() failed (%s)",
+ strerror(errno));
+#endif
+
+ hg_thread_mutex_destroy(&poll_set->lock);
+#if !defined(_WIN32) && !defined(HG_UTIL_HAS_SYSEPOLL_H) && !defined(HG_UTIL_HAS_SYSEVENT_H)
+ free(poll_set->event_data);
+#endif
+ free(poll_set->events);
+ free(poll_set);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_poll_get_fd(hg_poll_set_t *poll_set)
+{
+#if defined(_WIN32)
+ /* TODO */
+ return -1;
+#else
+ return poll_set->fd;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_poll_add(hg_poll_set_t *poll_set, int fd, struct hg_poll_event *event)
+{
+#if defined(_WIN32)
+ /* TODO */
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H)
+ struct epoll_event ev;
+ uint32_t poll_flags = 0;
+ int rc;
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ struct kevent ev;
+ struct timespec timeout = {0, 0};
+ int16_t poll_flags = 0;
+ int rc;
+#else
+ struct pollfd ev;
+ short int poll_flags = 0;
+#endif
+ int ret = HG_UTIL_SUCCESS;
+
+ HG_UTIL_LOG_DEBUG("Adding fd=%d to poll set (fd=%d)", fd, poll_set->fd);
+
+#if defined(_WIN32)
+ /* TODO */
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H)
+ /* Translate flags */
+ if (event->events & HG_POLLIN)
+ poll_flags |= EPOLLIN;
+ if (event->events & HG_POLLOUT)
+ poll_flags |= EPOLLOUT;
+
+ ev.events = poll_flags;
+ ev.data.u64 = (uint64_t)event->data.u64;
+
+ rc = epoll_ctl(poll_set->fd, EPOLL_CTL_ADD, fd, &ev);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "epoll_ctl() failed (%s)", strerror(errno));
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ /* Translate flags */
+ if (event->events & HG_POLLIN)
+ poll_flags |= EVFILT_READ;
+ if (event->events & HG_POLLOUT)
+ poll_flags |= EVFILT_WRITE;
+
+ EV_SET(&ev, (uintptr_t)fd, poll_flags, EV_ADD, 0, 0, event->data.ptr);
+
+ rc = kevent(poll_set->fd, &ev, 1, NULL, 0, &timeout);
+ HG_UTIL_CHECK_ERROR(rc == -1, done, ret, HG_UTIL_FAIL, "kevent() failed (%s)", strerror(errno));
+#else
+ /* Translate flags */
+ if (event->events & HG_POLLIN)
+ poll_flags |= POLLIN;
+ if (event->events & HG_POLLOUT)
+ poll_flags |= POLLOUT;
+
+ ev.fd = fd;
+ ev.events = poll_flags;
+ ev.revents = 0;
+#endif
+
+ hg_thread_mutex_lock(&poll_set->lock);
+
+#if !defined(_WIN32) && !defined(HG_UTIL_HAS_SYSEPOLL_H) && !defined(HG_UTIL_HAS_SYSEVENT_H)
+ /* Grow array if reached max number */
+ if (poll_set->nfds == poll_set->max_events) {
+ HG_UTIL_CHECK_ERROR(poll_set->max_events * 2 > HG_POLL_MAX_EVENTS, unlock, ret, HG_UTIL_FAIL,
+ "reached max number of events for this poll set (%d)", poll_set->max_events);
+
+ poll_set->events = realloc(poll_set->events, sizeof(*poll_set->events) * poll_set->max_events * 2);
+ HG_UTIL_CHECK_ERROR(!poll_set->events, unlock, ret, HG_UTIL_FAIL, "realloc() failed (%s)",
+ strerror(errno));
+
+ poll_set->event_data =
+ realloc(poll_set->event_data, sizeof(*poll_set->event_data) * poll_set->max_events * 2);
+ HG_UTIL_CHECK_ERROR(!poll_set->event_data, unlock, ret, HG_UTIL_FAIL, "realloc() failed (%s)",
+ strerror(errno));
+
+ poll_set->max_events *= 2;
+ }
+ poll_set->events[poll_set->nfds] = ev;
+ poll_set->event_data[poll_set->nfds] = event->data;
+#endif
+ poll_set->nfds++;
+
+#if !defined(_WIN32) && !defined(HG_UTIL_HAS_SYSEPOLL_H) && !defined(HG_UTIL_HAS_SYSEVENT_H)
+unlock:
+#endif
+ hg_thread_mutex_unlock(&poll_set->lock);
+
+done:
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_poll_remove(hg_poll_set_t *poll_set, int fd)
+{
+#if defined(_WIN32)
+ /* TODO */
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H)
+ int rc;
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ struct kevent ev;
+ struct timespec timeout = {0, 0};
+ int rc;
+#else
+ int i, found = -1;
+#endif
+ int ret = HG_UTIL_SUCCESS;
+
+ HG_UTIL_LOG_DEBUG("Removing fd=%d from poll set (fd=%d)", fd, poll_set->fd);
+
+#if defined(_WIN32)
+ /* TODO */
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H)
+ rc = epoll_ctl(poll_set->fd, EPOLL_CTL_DEL, fd, NULL);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "epoll_ctl() failed (%s)", strerror(errno));
+ hg_thread_mutex_lock(&poll_set->lock);
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ /* Events which are attached to file descriptors are automatically
+ * deleted on the last close of the descriptor. */
+ EV_SET(&ev, (uintptr_t)fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ rc = kevent(poll_set->fd, &ev, 1, NULL, 0, &timeout);
+ HG_UTIL_CHECK_ERROR(rc == -1, done, ret, HG_UTIL_FAIL, "kevent() failed (%s)", strerror(errno));
+ hg_thread_mutex_lock(&poll_set->lock);
+#else
+ hg_thread_mutex_lock(&poll_set->lock);
+ for (i = 0; i < (int)poll_set->nfds; i++) {
+ if (poll_set->events[i].fd == fd) {
+ found = i;
+ break;
+ }
+ }
+ HG_UTIL_CHECK_ERROR(found < 0, error, ret, HG_UTIL_FAIL, "Could not find fd in poll_set");
+
+ for (i = found; i < (int)poll_set->nfds - 1; i++) {
+ poll_set->events[i] = poll_set->events[i + 1];
+ poll_set->event_data[i] = poll_set->event_data[i + 1];
+ }
+#endif
+ poll_set->nfds--;
+ hg_thread_mutex_unlock(&poll_set->lock);
+
+done:
+ return ret;
+
+#if !defined(_WIN32) && !defined(HG_UTIL_HAS_SYSEPOLL_H) && !defined(HG_UTIL_HAS_SYSEVENT_H)
+error:
+ hg_thread_mutex_unlock(&poll_set->lock);
+
+ return ret;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_poll_wait(hg_poll_set_t *poll_set, unsigned int timeout, unsigned int max_events,
+ struct hg_poll_event *events, unsigned int *actual_events)
+{
+ int max_poll_events = (int)MIN(max_events, poll_set->max_events);
+ int nfds = 0, i;
+ int ret = HG_UTIL_SUCCESS;
+
+#if defined(_WIN32)
+
+#elif defined(HG_UTIL_HAS_SYSEPOLL_H)
+ nfds = epoll_wait(poll_set->fd, poll_set->events, max_poll_events, (int)timeout);
+ HG_UTIL_CHECK_ERROR(nfds == -1 && errno != EINTR, done, ret, HG_UTIL_FAIL, "epoll_wait() failed (%s)",
+ strerror(errno));
+
+ /* Handle signal interrupts */
+ if (unlikely(errno == EINTR)) {
+ events[0].events |= HG_POLLINTR;
+ *actual_events = 1;
+
+ /* Reset errno */
+ errno = 0;
+
+ return HG_UTIL_SUCCESS;
+ }
+
+ for (i = 0; i < nfds; ++i) {
+ events[i].events = 0;
+ events[i].data.u64 = (hg_util_uint64_t)poll_set->events[i].data.u64;
+
+ if (poll_set->events[i].events & EPOLLIN)
+ events[i].events |= HG_POLLIN;
+
+ if (poll_set->events[i].events & EPOLLOUT)
+ events[i].events |= HG_POLLOUT;
+
+ /* Don't change the if/else order */
+ if (poll_set->events[i].events & EPOLLERR)
+ events[i].events |= HG_POLLERR;
+ else if (poll_set->events[i].events & EPOLLHUP)
+ events[i].events |= HG_POLLHUP;
+ else if (poll_set->events[i].events & EPOLLRDHUP)
+ events[i].events |= HG_POLLHUP;
+ }
+
+ /* Grow array if reached max number */
+ if ((nfds == (int)poll_set->max_events) && (poll_set->max_events * 2 <= HG_POLL_MAX_EVENTS)) {
+ poll_set->events = realloc(poll_set->events, sizeof(*poll_set->events) * poll_set->max_events * 2);
+ HG_UTIL_CHECK_ERROR(!poll_set->events, done, ret, HG_UTIL_FAIL, "realloc() failed (%s)",
+ strerror(errno));
+
+ poll_set->max_events *= 2;
+ }
+#elif defined(HG_UTIL_HAS_SYSEVENT_H)
+ struct timespec timeout_spec;
+ ldiv_t ld;
+
+ /* Get sec / nsec */
+ ld = ldiv(timeout, 1000L);
+ timeout_spec.tv_sec = ld.quot;
+ timeout_spec.tv_nsec = ld.rem * 1000000L;
+
+ nfds = kevent(poll_set->fd, NULL, 0, poll_set->events, max_poll_events, &timeout_spec);
+ HG_UTIL_CHECK_ERROR(nfds == -1 && errno != EINTR, done, ret, HG_UTIL_FAIL, "kevent() failed (%s)",
+ strerror(errno));
+
+ /* Handle signal interrupts */
+ if (unlikely(errno == EINTR)) {
+ events[0].events |= HG_POLLINTR;
+ *actual_events = 1;
+
+ return HG_UTIL_SUCCESS;
+ }
+
+ for (i = 0; i < nfds; ++i) {
+ events[i].events = 0;
+ events[i].data.ptr = poll_set->events[i].udata;
+
+ if (poll_set->events[i].flags & EVFILT_READ)
+ events[i].events |= HG_POLLIN;
+
+ if (poll_set->events[i].flags & EVFILT_WRITE)
+ events[i].events |= HG_POLLOUT;
+ }
+
+ /* Grow array if reached max number */
+ if ((nfds == (int)poll_set->max_events) && (poll_set->max_events * 2 <= HG_POLL_MAX_EVENTS)) {
+ poll_set->events = realloc(poll_set->events, sizeof(*poll_set->events) * poll_set->max_events * 2);
+ HG_UTIL_CHECK_ERROR(!poll_set->events, done, ret, HG_UTIL_FAIL, "realloc() failed (%s)",
+ strerror(errno));
+
+ poll_set->max_events *= 2;
+ }
+#else
+ int nevent = 0, rc;
+ hg_util_bool_t signaled;
+
+ rc = hg_event_get(poll_set->fd, &signaled);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, done, ret, HG_UTIL_FAIL, "hg_event_get() failed (%s)",
+ strerror(errno));
+ if (signaled) {
+ /* Should we do anything in that case? */
+ }
+
+ hg_thread_mutex_lock(&poll_set->lock);
+
+ /* Reset revents */
+ for (i = 0; i < (int)poll_set->nfds; i++)
+ poll_set->events[i].revents = 0;
+
+ nfds = poll(poll_set->events, (nfds_t)poll_set->nfds, (int)timeout);
+ HG_UTIL_CHECK_ERROR(nfds == -1 && errno != EINTR, unlock, ret, HG_UTIL_FAIL, "poll() failed (%s)",
+ strerror(errno));
+
+ /* Handle signal interrupts */
+ if (unlikely(errno == EINTR)) {
+ events[0].events |= HG_POLLINTR;
+ *actual_events = 1;
+ hg_thread_mutex_unlock(&poll_set->lock);
+
+ return HG_UTIL_SUCCESS;
+ }
+
+ nfds = (int)MIN(max_poll_events, nfds);
+
+ /* An event on one of the fds has occurred. */
+ for (i = 0; i < (int)poll_set->nfds && nevent < nfds; ++i) {
+ events[i].events = 0;
+ events[i].data.u64 = (hg_util_uint64_t)poll_set->event_data[i].u64;
+
+ if (poll_set->events[i].revents & POLLIN)
+ events[i].events |= HG_POLLIN;
+
+ if (poll_set->events[i].revents & POLLOUT)
+ events[i].events |= HG_POLLOUT;
+
+ /* Don't change the if/else order */
+ if (poll_set->events[i].revents & POLLERR)
+ events[i].events |= HG_POLLERR;
+ else if (poll_set->events[i].revents & POLLHUP)
+ events[i].events |= HG_POLLHUP;
+ else if (poll_set->events[i].events & POLLNVAL)
+ events[i].events |= HG_POLLERR;
+
+ nevent++;
+ }
+
+ hg_thread_mutex_unlock(&poll_set->lock);
+
+ HG_UTIL_CHECK_ERROR(nevent != nfds, done, ret, HG_UTIL_FAIL, "found only %d events, expected %d", nevent,
+ nfds);
+
+ if (nfds > 0) {
+ /* TODO should figure where to call hg_event_get() */
+ rc = hg_event_set(poll_set->fd);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, done, ret, HG_UTIL_FAIL, "hg_event_set() failed (%s)",
+ strerror(errno));
+ }
+#endif
+
+ *actual_events = (unsigned int)nfds;
+
+done:
+ return ret;
+
+#if !defined(_WIN32) && !defined(HG_UTIL_HAS_SYSEPOLL_H) && !defined(HG_UTIL_HAS_SYSEVENT_H)
+unlock:
+ hg_thread_mutex_unlock(&poll_set->lock);
+
+ return ret;
+#endif
+}
diff --git a/src/mercury/src/util/mercury_poll.h b/src/mercury/src/util/mercury_poll.h
new file mode 100644
index 0000000..f4072a5
--- /dev/null
+++ b/src/mercury/src/util/mercury_poll.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_POLL_H
+#define MERCURY_POLL_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_poll_set hg_poll_set_t;
+
+typedef union hg_poll_data {
+ void * ptr;
+ int fd;
+ hg_util_uint32_t u32;
+ hg_util_uint64_t u64;
+} hg_poll_data_t;
+
+struct hg_poll_event {
+ hg_util_uint32_t events; /* Poll events */
+ hg_poll_data_t data; /* User data variable */
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/**
+ * Polling events.
+ */
+#define HG_POLLIN (1 << 0) /* There is data to read. */
+#define HG_POLLOUT (1 << 1) /* Writing now will not block. */
+#define HG_POLLERR (1 << 2) /* Error condition. */
+#define HG_POLLHUP (1 << 3) /* Hung up. */
+#define HG_POLLINTR (1 << 4) /* Interrupted. */
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Create a new poll set.
+ *
+ * \return Pointer to poll set or NULL in case of failure
+ */
+HG_UTIL_PUBLIC hg_poll_set_t *hg_poll_create(void);
+
+/**
+ * Destroy a poll set.
+ *
+ * \param poll_set [IN/OUT] pointer to poll set
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_destroy(hg_poll_set_t *poll_set);
+
+/**
+ * Get a file descriptor from an existing poll set.
+ *
+ * \param poll_set [IN] pointer to poll set
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_get_fd(hg_poll_set_t *poll_set);
+
+/**
+ * Add file descriptor to poll set.
+ *
+ * \param poll_set [IN] pointer to poll set
+ * \param fd [IN] file descriptor
+ * \param event [IN] pointer to event struct
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_add(hg_poll_set_t *poll_set, int fd, struct hg_poll_event *event);
+
+/**
+ * Remove file descriptor from poll set.
+ *
+ * \param poll_set [IN] pointer to poll set
+ * \param fd [IN] file descriptor
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_remove(hg_poll_set_t *poll_set, int fd);
+
+/**
+ * Wait on a poll set for timeout ms, and return at most max_events.
+ *
+ * \param poll_set [IN] pointer to poll set
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param max_events [IN] max number of events
+ * \param events [IN/OUT] array of events to be returned
+ * \param actual_events [OUT] actual number of events returned
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_poll_wait(hg_poll_set_t *poll_set, unsigned int timeout, unsigned int max_events,
+ struct hg_poll_event events[], unsigned int *actual_events);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_POLL_H */
diff --git a/src/mercury/src/util/mercury_queue.h b/src/mercury/src/util/mercury_queue.h
new file mode 100644
index 0000000..116a209
--- /dev/null
+++ b/src/mercury/src/util/mercury_queue.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Code below is derived from sys/queue.h which follows the below notice:
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef MERCURY_QUEUE_H
+#define MERCURY_QUEUE_H
+
+#define HG_QUEUE_HEAD_INITIALIZER(name) \
+ { \
+ NULL, &(name).head \
+ }
+
+#define HG_QUEUE_HEAD_INIT(struct_head_name, var_name) \
+ struct struct_head_name var_name = HG_QUEUE_HEAD_INITIALIZER(var_name)
+
+#define HG_QUEUE_HEAD_DECL(struct_head_name, struct_entry_name) \
+ struct struct_head_name { \
+ struct struct_entry_name * head; \
+ struct struct_entry_name **tail; \
+ }
+
+#define HG_QUEUE_HEAD(struct_entry_name) \
+ struct { \
+ struct struct_entry_name * head; \
+ struct struct_entry_name **tail; \
+ }
+
+#define HG_QUEUE_ENTRY(struct_entry_name) \
+ struct { \
+ struct struct_entry_name *next; \
+ }
+
+#define HG_QUEUE_INIT(head_ptr) \
+ do { \
+ (head_ptr)->head = NULL; \
+ (head_ptr)->tail = &(head_ptr)->head; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_QUEUE_IS_EMPTY(head_ptr) ((head_ptr)->head == NULL)
+
+#define HG_QUEUE_FIRST(head_ptr) ((head_ptr)->head)
+
+#define HG_QUEUE_NEXT(entry_ptr, entry_field_name) ((entry_ptr)->entry_field_name.next)
+
+#define HG_QUEUE_PUSH_TAIL(head_ptr, entry_ptr, entry_field_name) \
+ do { \
+ (entry_ptr)->entry_field_name.next = NULL; \
+ *(head_ptr)->tail = (entry_ptr); \
+ (head_ptr)->tail = &(entry_ptr)->entry_field_name.next; \
+ } while (/*CONSTCOND*/ 0)
+
+/* TODO would be nice to not have any condition */
+#define HG_QUEUE_POP_HEAD(head_ptr, entry_field_name) \
+ do { \
+ if ((head_ptr)->head && ((head_ptr)->head = (head_ptr)->head->entry_field_name.next) == NULL) \
+ (head_ptr)->tail = &(head_ptr)->head; \
+ } while (/*CONSTCOND*/ 0)
+
+#define HG_QUEUE_FOREACH(var, head_ptr, entry_field_name) \
+ for ((var) = ((head_ptr)->head); (var); (var) = ((var)->entry_field_name.next))
+
+/**
+ * Avoid using those for performance reasons or use mercury_list.h instead
+ */
+
+#define HG_QUEUE_REMOVE(head_ptr, entry_ptr, type, entry_field_name) \
+ do { \
+ if ((head_ptr)->head == (entry_ptr)) { \
+ HG_QUEUE_POP_HEAD((head_ptr), entry_field_name); \
+ } \
+ else { \
+ struct type *curelm = (head_ptr)->head; \
+ while (curelm->entry_field_name.next != (entry_ptr)) \
+ curelm = curelm->entry_field_name.next; \
+ if ((curelm->entry_field_name.next = curelm->entry_field_name.next->entry_field_name.next) == \
+ NULL) \
+ (head_ptr)->tail = &(curelm)->entry_field_name.next; \
+ } \
+ } while (/*CONSTCOND*/ 0)
+
+#endif /* MERCURY_QUEUE_H */
diff --git a/src/mercury/src/util/mercury_request.c b/src/mercury/src/util/mercury_request.c
new file mode 100644
index 0000000..6951c61
--- /dev/null
+++ b/src/mercury/src/util/mercury_request.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_request.h"
+#include "mercury_thread_condition.h"
+#include "mercury_thread_mutex.h"
+#include "mercury_time.h"
+#include "mercury_util_error.h"
+
+#include <stdlib.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+struct hg_request_class {
+ hg_request_progress_func_t progress_func;
+ hg_request_trigger_func_t trigger_func;
+ void * arg;
+ hg_util_bool_t progressing;
+ hg_thread_mutex_t progress_mutex;
+ hg_thread_cond_t progress_cond;
+};
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*---------------------------------------------------------------------------*/
+hg_request_class_t *
+hg_request_init(hg_request_progress_func_t progress_func, hg_request_trigger_func_t trigger_func, void *arg)
+{
+ struct hg_request_class *hg_request_class = NULL;
+
+ hg_request_class = (struct hg_request_class *)malloc(sizeof(struct hg_request_class));
+ HG_UTIL_CHECK_ERROR_NORET(hg_request_class == NULL, done, "Could not allocate hg_request_class");
+
+ hg_request_class->progress_func = progress_func;
+ hg_request_class->trigger_func = trigger_func;
+ hg_request_class->arg = arg;
+ hg_request_class->progressing = HG_UTIL_FALSE;
+ hg_thread_mutex_init(&hg_request_class->progress_mutex);
+ hg_thread_cond_init(&hg_request_class->progress_cond);
+
+done:
+ return hg_request_class;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_request_finalize(hg_request_class_t *request_class, void **arg)
+{
+ if (!request_class)
+ return;
+
+ if (arg)
+ *arg = request_class->arg;
+ hg_thread_mutex_destroy(&request_class->progress_mutex);
+ hg_thread_cond_destroy(&request_class->progress_cond);
+ free(request_class);
+}
+
+/*---------------------------------------------------------------------------*/
+hg_request_t *
+hg_request_create(hg_request_class_t *request_class)
+{
+ struct hg_request *hg_request = NULL;
+
+ hg_request = (struct hg_request *)malloc(sizeof(struct hg_request));
+ HG_UTIL_CHECK_ERROR_NORET(hg_request == NULL, done, "Could not allocate hg_request");
+
+ hg_request->request_class = request_class;
+ hg_request->data = NULL;
+ hg_atomic_init32(&hg_request->completed, HG_UTIL_FALSE);
+
+done:
+ return hg_request;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_request_destroy(hg_request_t *request)
+{
+ free(request);
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_request_wait(hg_request_t *request, unsigned int timeout_ms, unsigned int *flag)
+{
+ hg_time_t deadline, remaining = hg_time_from_ms(timeout_ms);
+ hg_time_t now = hg_time_from_ms(0);
+ hg_util_int32_t completed = HG_UTIL_FALSE;
+ int ret = HG_UTIL_SUCCESS;
+
+ if (timeout_ms != 0)
+ hg_time_get_current_ms(&now);
+ deadline = hg_time_add(now, remaining);
+
+ do {
+ unsigned int trigger_flag = 0;
+ int trigger_ret;
+
+ do {
+ trigger_ret = request->request_class->trigger_func(0, &trigger_flag, request->request_class->arg);
+ } while ((trigger_ret == HG_UTIL_SUCCESS) && trigger_flag);
+
+ if ((completed = hg_atomic_get32(&request->completed)) == HG_UTIL_TRUE)
+ break;
+
+ hg_thread_mutex_lock(&request->request_class->progress_mutex);
+ if (request->request_class->progressing) {
+ if (hg_thread_cond_timedwait(&request->request_class->progress_cond,
+ &request->request_class->progress_mutex,
+ hg_time_to_ms(remaining)) != HG_UTIL_SUCCESS) {
+ /* Timeout occurred so leave */
+ hg_thread_mutex_unlock(&request->request_class->progress_mutex);
+ break;
+ }
+ /* Continue as request may have completed in the meantime */
+ hg_thread_mutex_unlock(&request->request_class->progress_mutex);
+ goto next;
+ }
+ request->request_class->progressing = HG_UTIL_TRUE;
+ hg_thread_mutex_unlock(&request->request_class->progress_mutex);
+
+ request->request_class->progress_func(hg_time_to_ms(remaining), request->request_class->arg);
+
+ hg_thread_mutex_lock(&request->request_class->progress_mutex);
+ request->request_class->progressing = HG_UTIL_FALSE;
+ hg_thread_cond_broadcast(&request->request_class->progress_cond);
+ hg_thread_mutex_unlock(&request->request_class->progress_mutex);
+
+next:
+ if (timeout_ms != 0)
+ hg_time_get_current_ms(&now);
+ remaining = hg_time_subtract(deadline, now);
+ } while (hg_time_less(now, deadline));
+
+ if (flag)
+ *flag = (unsigned int)completed;
+
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_request.h b/src/mercury/src/util/mercury_request.h
new file mode 100644
index 0000000..4d7fdf8
--- /dev/null
+++ b/src/mercury/src/util/mercury_request.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_REQUEST_H
+#define MERCURY_REQUEST_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_atomic.h"
+
+/**
+ * Purpose: define a request emulation library on top of the callback model
+ * that uses progress/trigger functions. Note that this library can not be
+ * safely used within RPCs in most cases - calling hg_request_wait causes
+ * deadlock when the caller function was triggered by HG_Trigger
+ * (or HG_Bulk_trigger).
+ */
+
+typedef struct hg_request_class hg_request_class_t; /* Opaque request class */
+typedef struct hg_request hg_request_t; /* Opaque request object */
+
+struct hg_request {
+ hg_request_class_t *request_class;
+ void * data;
+ hg_atomic_int32_t completed;
+};
+
+/**
+ * Progress callback, arg can be used to pass extra parameters required by
+ * underlying API.
+ *
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return HG_UTIL_SUCCESS if any completion has occurred / error code otherwise
+ */
+typedef int (*hg_request_progress_func_t)(unsigned int timeout, void *arg);
+
+/**
+ * Trigger callback, arg can be used to pass extra parameters required by
+ * underlying API.
+ *
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param flag [OUT] 1 if callback has been triggered, 0 otherwise
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return HG_UTIL_SUCCESS or corresponding error code
+ */
+typedef int (*hg_request_trigger_func_t)(unsigned int timeout, unsigned int *flag, void *arg);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the request class with the specific progress/trigger functions
+ * that will be called on hg_request_wait().
+ * arg can be used to pass extra parameters required by underlying API.
+ *
+ * \param progress [IN] progress function
+ * \param trigger [IN] trigger function
+ * \param arg [IN] pointer to data passed to callback
+ *
+ * \return Pointer to request class or NULL in case of failure
+ */
+HG_UTIL_PUBLIC hg_request_class_t *hg_request_init(hg_request_progress_func_t progress,
+ hg_request_trigger_func_t trigger, void *arg);
+
+/**
+ * Finalize the request class. User args that were passed through
+ * hg_request_init() can be retrieved through the \a arg parameter.
+ *
+ * \param request_class [IN] pointer to request class
+ * \param arg [IN/OUT] pointer to init args
+ */
+HG_UTIL_PUBLIC void hg_request_finalize(hg_request_class_t *request_class, void **arg);
+
+/**
+ * Create a new request from a specified request class. The progress function
+ * explicitly makes progress and may insert the completed operation into a
+ * completion queue. The operation gets triggered after a call to the trigger
+ * function.
+ *
+ * \param request_class [IN] pointer to request class
+ *
+ * \return Pointer to request or NULL in case of failure
+ */
+HG_UTIL_PUBLIC hg_request_t *hg_request_create(hg_request_class_t *request_class);
+
+/**
+ * Destroy the request, freeing the resources.
+ *
+ * \param request [IN/OUT] pointer to request
+ */
+HG_UTIL_PUBLIC void hg_request_destroy(hg_request_t *request);
+
+/**
+ * Reset an existing request so that it can be safely re-used.
+ *
+ * \param request [IN/OUT] pointer to request
+ */
+static HG_UTIL_INLINE void hg_request_reset(hg_request_t *request);
+
+/**
+ * Mark the request as completed. (most likely called by a callback triggered
+ * after a call to trigger)
+ *
+ * \param request [IN/OUT] pointer to request
+ */
+static HG_UTIL_INLINE void hg_request_complete(hg_request_t *request);
+
+/**
+ * Wait timeout ms for the specified request to complete.
+ *
+ * \param request [IN/OUT] pointer to request
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param flag [OUT] 1 if request has completed, 0 otherwise
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_request_wait(hg_request_t *request, unsigned int timeout, unsigned int *flag);
+
+/**
+ * Wait timeout ms for all the specified request to complete.
+ *
+ * \param count [IN] number of requests
+ * \param request [IN/OUT] arrays of requests
+ * \param timeout [IN] timeout (in milliseconds)
+ * \param flag [OUT] 1 if all requests have completed, 0 otherwise
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_request_waitall(int count, hg_request_t *request[], unsigned int timeout,
+ unsigned int *flag);
+
+/**
+ * Attach user data to a specified request.
+ *
+ * \param request [IN/OUT] pointer to request
+ * \param data [IN] pointer to data
+ */
+static HG_UTIL_INLINE void hg_request_set_data(hg_request_t *request, void *data);
+
+/**
+ * Get user data from a specified request.
+ *
+ * \param request [IN/OUT] pointer to request
+ *
+ * \return Pointer to data or NULL if nothing was attached by user
+ */
+static HG_UTIL_INLINE void *hg_request_get_data(hg_request_t *request);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_request_reset(hg_request_t *request)
+{
+ hg_atomic_set32(&request->completed, HG_UTIL_FALSE);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_request_complete(hg_request_t *request)
+{
+ hg_atomic_set32(&request->completed, HG_UTIL_TRUE);
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_request_waitall(int count, hg_request_t *request[], unsigned int timeout, unsigned int *flag)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ hg_request_wait(request[i], timeout, flag);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_request_set_data(hg_request_t *request, void *data)
+{
+ request->data = data;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_request_get_data(hg_request_t *request)
+{
+ return request->data;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_REQUEST_H */
diff --git a/src/mercury/src/util/mercury_thread.c b/src/mercury/src/util/mercury_thread.c
new file mode 100644
index 0000000..3b1f9a9
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_thread.h"
+
+/*---------------------------------------------------------------------------*/
+void
+hg_thread_init(hg_thread_t *thread)
+{
+#ifdef _WIN32
+ *thread = NULL;
+#else
+ *thread = 0;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_create(hg_thread_t *thread, hg_thread_func_t f, void *data)
+{
+#ifdef _WIN32
+ *thread = CreateThread(NULL, 0, f, data, 0, NULL);
+ if (*thread == NULL)
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_create(thread, NULL, f, data))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_thread_exit(hg_thread_ret_t ret)
+{
+#ifdef _WIN32
+ ExitThread(ret);
+#else
+ pthread_exit(ret);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_join(hg_thread_t thread)
+{
+#ifdef _WIN32
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+#else
+ if (pthread_join(thread, NULL))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_cancel(hg_thread_t thread)
+{
+#ifdef _WIN32
+ WaitForSingleObject(thread, 0);
+ CloseHandle(thread);
+#else
+ if (pthread_cancel(thread))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_yield(void)
+{
+#ifdef _WIN32
+ SwitchToThread();
+#elif defined(__APPLE__)
+ pthread_yield_np();
+#else
+ pthread_yield();
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_key_create(hg_thread_key_t *key)
+{
+ if (!key)
+ return HG_UTIL_FAIL;
+
+#ifdef _WIN32
+ if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_key_create(key, NULL))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_key_delete(hg_thread_key_t key)
+{
+#ifdef _WIN32
+ if (!TlsFree(key))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_key_delete(key))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_getaffinity(hg_thread_t thread, hg_cpu_set_t *cpu_mask)
+{
+#if defined(_WIN32)
+ return HG_UTIL_FAIL;
+#elif defined(__APPLE__)
+ (void)thread;
+ (void)cpu_mask;
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_getaffinity_np(thread, sizeof(hg_cpu_set_t), cpu_mask))
+ return HG_UTIL_FAIL;
+ return HG_UTIL_SUCCESS;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_setaffinity(hg_thread_t thread, const hg_cpu_set_t *cpu_mask)
+{
+#if defined(_WIN32)
+ if (!SetThreadAffinityMask(thread, *cpu_mask))
+ return HG_UTIL_FAIL;
+#elif defined(__APPLE__)
+ (void)thread;
+ (void)cpu_mask;
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_setaffinity_np(thread, sizeof(hg_cpu_set_t), cpu_mask))
+ return HG_UTIL_FAIL;
+ return HG_UTIL_SUCCESS;
+#endif
+}
diff --git a/src/mercury/src/util/mercury_thread.h b/src/mercury/src/util/mercury_thread.h
new file mode 100644
index 0000000..3317c41
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_H
+#define MERCURY_THREAD_H
+
+#if !defined(_WIN32) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#include "mercury_util_config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+typedef HANDLE hg_thread_t;
+typedef LPTHREAD_START_ROUTINE hg_thread_func_t;
+typedef DWORD hg_thread_ret_t;
+#define HG_THREAD_RETURN_TYPE hg_thread_ret_t WINAPI
+typedef DWORD hg_thread_key_t;
+typedef DWORD_PTR hg_cpu_set_t;
+#else
+#include <pthread.h>
+typedef pthread_t hg_thread_t;
+typedef void *(*hg_thread_func_t)(void *);
+typedef void * hg_thread_ret_t;
+#define HG_THREAD_RETURN_TYPE hg_thread_ret_t
+typedef pthread_key_t hg_thread_key_t;
+#ifdef __APPLE__
+/* Size definition for CPU sets. */
+#define HG_CPU_SETSIZE 1024
+#define HG_NCPUBITS (8 * sizeof(hg_cpu_mask_t))
+/* Type for array elements in 'cpu_set_t'. */
+typedef hg_util_uint64_t hg_cpu_mask_t;
+typedef struct {
+ hg_cpu_mask_t bits[HG_CPU_SETSIZE / HG_NCPUBITS];
+} hg_cpu_set_t;
+#else
+typedef cpu_set_t hg_cpu_set_t;
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the thread.
+ *
+ * \param thread [IN/OUT] pointer to thread object
+ */
+HG_UTIL_PUBLIC void hg_thread_init(hg_thread_t *thread);
+
+/**
+ * Create a new thread for the given function.
+ *
+ * \param thread [IN/OUT] pointer to thread object
+ * \param f [IN] pointer to function
+ * \param data [IN] pointer to data than be passed to function f
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_create(hg_thread_t *thread, hg_thread_func_t f, void *data);
+
+/**
+ * Ends the calling thread.
+ *
+ * \param ret [IN] exit code for the thread
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC void hg_thread_exit(hg_thread_ret_t ret);
+
+/**
+ * Wait for thread completion.
+ *
+ * \param thread [IN] thread object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_join(hg_thread_t thread);
+
+/**
+ * Terminate the thread.
+ *
+ * \param thread [IN] thread object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_cancel(hg_thread_t thread);
+
+/**
+ * Yield the processor.
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_yield(void);
+
+/**
+ * Obtain handle of the calling thread.
+ *
+ * \return
+ */
+static HG_UTIL_INLINE hg_thread_t hg_thread_self(void);
+
+/**
+ * Compare thread IDs.
+ *
+ * \return Non-zero if equal, zero if not equal
+ */
+static HG_UTIL_INLINE int hg_thread_equal(hg_thread_t t1, hg_thread_t t2);
+
+/**
+ * Create a thread-specific data key visible to all threads in the process.
+ *
+ * \param key [OUT] pointer to thread key object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_key_create(hg_thread_key_t *key);
+
+/**
+ * Delete a thread-specific data key previously returned by
+ * hg_thread_key_create().
+ *
+ * \param key [IN] thread key object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_key_delete(hg_thread_key_t key);
+
+/**
+ * Get value from specified key.
+ *
+ * \param key [IN] thread key object
+ *
+ * \return Pointer to data associated to the key
+ */
+static HG_UTIL_INLINE void *hg_thread_getspecific(hg_thread_key_t key);
+
+/**
+ * Set value to specified key.
+ *
+ * \param key [IN] thread key object
+ * \param value [IN] pointer to data that will be associated
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_setspecific(hg_thread_key_t key, const void *value);
+
+/**
+ * Get affinity mask.
+ *
+ * \param thread [IN] thread object
+ * \param cpu_mask [IN/OUT] cpu mask
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_getaffinity(hg_thread_t thread, hg_cpu_set_t *cpu_mask);
+
+/**
+ * Set affinity mask.
+ *
+ * \param thread [IN] thread object
+ * \param cpu_mask [IN] cpu mask
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_setaffinity(hg_thread_t thread, const hg_cpu_set_t *cpu_mask);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_thread_t
+hg_thread_self(void)
+{
+#ifdef _WIN32
+ return GetCurrentThread();
+#else
+ return pthread_self();
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_equal(hg_thread_t t1, hg_thread_t t2)
+{
+#ifdef _WIN32
+ return GetThreadId(t1) == GetThreadId(t2);
+#else
+ return pthread_equal(t1, t2);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void *
+hg_thread_getspecific(hg_thread_key_t key)
+{
+#ifdef _WIN32
+ return TlsGetValue(key);
+#else
+ return pthread_getspecific(key);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_setspecific(hg_thread_key_t key, const void *value)
+{
+#ifdef _WIN32
+ if (!TlsSetValue(key, (LPVOID)value))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_setspecific(key, value))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_H */
diff --git a/src/mercury/src/util/mercury_thread_annotation.h b/src/mercury/src/util/mercury_thread_annotation.h
new file mode 100644
index 0000000..f8613a4
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_annotation.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_ANNOTATION_H
+#define MERCURY_THREAD_ANNOTATION_H
+
+/* Enable thread safety attributes only with clang.
+ * The attributes can be safely erased when compiling with other compilers. */
+#if defined(__clang__) && (__clang_major__ > 3)
+#define HG_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define HG_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+#define HG_LOCK_CAPABILITY(x) HG_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define HG_LOCK_ACQUIRE(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define HG_LOCK_ACQUIRE_SHARED(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define HG_LOCK_RELEASE(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define HG_LOCK_RELEASE_SHARED(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define HG_LOCK_TRY_ACQUIRE(...) HG_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define HG_LOCK_TRY_ACQUIRE_SHARED(...) \
+ HG_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define HG_LOCK_NO_THREAD_SAFETY_ANALYSIS HG_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+#endif /* MERCURY_THREAD_ANNOTATION_H */
diff --git a/src/mercury/src/util/mercury_thread_condition.c b/src/mercury/src/util/mercury_thread_condition.c
new file mode 100644
index 0000000..35133ea
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_condition.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_thread_condition.h"
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_cond_init(hg_thread_cond_t *cond)
+{
+#ifdef _WIN32
+ InitializeConditionVariable(cond);
+#else
+ pthread_condattr_t attr;
+
+ pthread_condattr_init(&attr);
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ /* Must set clock ID if using different clock
+ * (CLOCK_MONOTONIC_COARSE not supported here) */
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+#endif
+ if (pthread_cond_init(cond, &attr))
+ return HG_UTIL_FAIL;
+ pthread_condattr_destroy(&attr);
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_cond_destroy(hg_thread_cond_t *cond)
+{
+#ifndef _WIN32
+ if (pthread_cond_destroy(cond))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
diff --git a/src/mercury/src/util/mercury_thread_condition.h b/src/mercury/src/util/mercury_thread_condition.h
new file mode 100644
index 0000000..c1a3d61
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_condition.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_CONDITION_H
+#define MERCURY_THREAD_CONDITION_H
+
+#include "mercury_thread_mutex.h"
+
+#ifdef _WIN32
+typedef CONDITION_VARIABLE hg_thread_cond_t;
+#else
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+#include <time.h>
+#elif defined(HG_UTIL_HAS_SYSTIME_H)
+#include <sys/time.h>
+#endif
+#include <stdlib.h>
+typedef pthread_cond_t hg_thread_cond_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the condition.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_cond_init(hg_thread_cond_t *cond);
+
+/**
+ * Destroy the condition.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_cond_destroy(hg_thread_cond_t *cond);
+
+/**
+ * Wake one thread waiting for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_signal(hg_thread_cond_t *cond);
+
+/**
+ * Wake all the threads waiting for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_broadcast(hg_thread_cond_t *cond);
+
+/**
+ * Wait for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex);
+
+/**
+ * Wait timeout ms for the condition to change.
+ *
+ * \param cond [IN/OUT] pointer to condition object
+ * \param mutex [IN/OUT] pointer to mutex object
+ * \param timeout [IN] timeout (in milliseconds)
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex,
+ unsigned int timeout);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_signal(hg_thread_cond_t *cond)
+{
+#ifdef _WIN32
+ WakeConditionVariable(cond);
+#else
+ if (pthread_cond_signal(cond))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_broadcast(hg_thread_cond_t *cond)
+{
+#ifdef _WIN32
+ WakeAllConditionVariable(cond);
+#else
+ if (pthread_cond_broadcast(cond))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex)
+{
+#ifdef _WIN32
+ if (!SleepConditionVariableCS(cond, mutex, INFINITE))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_cond_wait(cond, mutex))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex, unsigned int timeout)
+{
+#ifdef _WIN32
+ if (!SleepConditionVariableCS(cond, mutex, timeout))
+ return HG_UTIL_FAIL;
+#else
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ struct timespec now;
+#else
+ struct timeval now;
+#endif
+ struct timespec abs_timeout;
+ ldiv_t ld;
+
+ /* Need to convert timeout (ms) to absolute time */
+#if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+
+ /* Get sec / nsec */
+ ld = ldiv(now.tv_nsec + timeout * 1000000L, 1000000000L);
+ abs_timeout.tv_nsec = ld.rem;
+#elif defined(HG_UTIL_HAS_SYSTIME_H)
+ gettimeofday(&now, NULL);
+
+ /* Get sec / usec */
+ ld = ldiv(now.tv_usec + timeout * 1000L, 1000000L);
+ abs_timeout.tv_nsec = ld.rem * 1000L;
+#endif
+ abs_timeout.tv_sec = now.tv_sec + ld.quot;
+
+ if (pthread_cond_timedwait(cond, mutex, &abs_timeout))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_CONDITION_H */
diff --git a/src/mercury/src/util/mercury_thread_mutex.c b/src/mercury/src/util/mercury_thread_mutex.c
new file mode 100644
index 0000000..5a5d978
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_mutex.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_thread_mutex.h"
+
+#include "mercury_util_error.h"
+
+#include <string.h>
+
+#ifndef _WIN32
+static int
+hg_thread_mutex_init_posix(hg_thread_mutex_t *mutex, int kind)
+{
+ pthread_mutexattr_t mutex_attr;
+ int ret = HG_UTIL_SUCCESS;
+ int rc;
+
+ rc = pthread_mutexattr_init(&mutex_attr);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutexattr_init() failed (%s)",
+ strerror(rc));
+
+ /* Keep mutex mode as normal and do not expect error checking */
+ rc = pthread_mutexattr_settype(&mutex_attr, kind);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutexattr_settype() failed (%s)",
+ strerror(rc));
+
+ rc = pthread_mutex_init(mutex, &mutex_attr);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutex_init() failed (%s)", strerror(rc));
+
+done:
+ rc = pthread_mutexattr_destroy(&mutex_attr);
+ HG_UTIL_CHECK_ERROR_DONE(rc != 0, "pthread_mutexattr_destroy() failed (%s)", strerror(rc));
+
+ return ret;
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_mutex_init(hg_thread_mutex_t *mutex)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#ifdef _WIN32
+ InitializeCriticalSection(mutex);
+#else
+ ret = hg_thread_mutex_init_posix(mutex, PTHREAD_MUTEX_NORMAL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_mutex_init_fast(hg_thread_mutex_t *mutex)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#ifdef HG_UTIL_HAS_PTHREAD_MUTEX_ADAPTIVE_NP
+ /* Set type to PTHREAD_MUTEX_ADAPTIVE_NP to improve performance */
+ ret = hg_thread_mutex_init_posix(mutex, PTHREAD_MUTEX_ADAPTIVE_NP);
+#else
+ ret = hg_thread_mutex_init_posix(mutex, PTHREAD_MUTEX_NORMAL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_mutex_destroy(hg_thread_mutex_t *mutex)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#ifdef _WIN32
+ DeleteCriticalSection(mutex);
+#else
+ int rc;
+
+ rc = pthread_mutex_destroy(mutex);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_mutex_destroy() failed (%s)",
+ strerror(rc));
+
+done:
+#endif
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_thread_mutex.h b/src/mercury/src/util/mercury_thread_mutex.h
new file mode 100644
index 0000000..b400952
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_mutex.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_MUTEX_H
+#define MERCURY_THREAD_MUTEX_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#define HG_THREAD_MUTEX_INITIALIZER NULL
+typedef CRITICAL_SECTION hg_thread_mutex_t;
+#else
+#include <pthread.h>
+#define HG_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+typedef pthread_mutex_t HG_LOCK_CAPABILITY("mutex") hg_thread_mutex_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_mutex_init(hg_thread_mutex_t *mutex);
+
+/**
+ * Initialize the mutex, asking for "fast" mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_mutex_init_fast(hg_thread_mutex_t *mutex);
+
+/**
+ * Destroy the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_mutex_destroy(hg_thread_mutex_t *mutex);
+
+/**
+ * Lock the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ */
+static HG_UTIL_INLINE void hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_ACQUIRE(*mutex);
+
+/**
+ * Try locking the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex)
+ HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *mutex);
+
+/**
+ * Unlock the mutex.
+ *
+ * \param mutex [IN/OUT] pointer to mutex object
+ */
+static HG_UTIL_INLINE void hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_RELEASE(*mutex);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_mutex_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ EnterCriticalSection(mutex);
+#else
+ (void)pthread_mutex_lock(mutex);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_mutex_try_lock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ if (!TryEnterCriticalSection(mutex))
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_mutex_trylock(mutex))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_mutex_unlock(hg_thread_mutex_t *mutex) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ LeaveCriticalSection(mutex);
+#else
+ (void)pthread_mutex_unlock(mutex);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_MUTEX_H */
diff --git a/src/mercury/src/util/mercury_thread_pool.c b/src/mercury/src/util/mercury_thread_pool.c
new file mode 100644
index 0000000..eb2d7da
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_pool.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_thread_pool.h"
+
+#include "mercury_util_error.h"
+
+#include <stdlib.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/************************************/
+/* Local Type and Struct Definition */
+/************************************/
+
+struct hg_thread_pool_private {
+ struct hg_thread_pool pool;
+ unsigned int thread_count;
+ hg_thread_t * threads;
+};
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+/**
+ * Worker thread run by the thread pool
+ */
+static HG_THREAD_RETURN_TYPE hg_thread_pool_worker(void *args);
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/*---------------------------------------------------------------------------*/
+static HG_THREAD_RETURN_TYPE
+hg_thread_pool_worker(void *args)
+{
+ hg_thread_ret_t ret = 0;
+ hg_thread_pool_t * pool = (hg_thread_pool_t *)args;
+ struct hg_thread_work *work;
+
+ while (1) {
+ hg_thread_mutex_lock(&pool->mutex);
+
+ /* If not shutting down and nothing to do, worker sleeps */
+ while (!pool->shutdown && HG_QUEUE_IS_EMPTY(&pool->queue)) {
+ int rc;
+
+ pool->sleeping_worker_count++;
+
+ rc = hg_thread_cond_wait(&pool->cond, &pool->mutex);
+ HG_UTIL_CHECK_ERROR_NORET(rc != HG_UTIL_SUCCESS, unlock,
+ "Thread cannot wait on condition variable");
+
+ pool->sleeping_worker_count--;
+ }
+
+ if (pool->shutdown && HG_QUEUE_IS_EMPTY(&pool->queue))
+ goto unlock;
+
+ /* Grab our task */
+ work = HG_QUEUE_FIRST(&pool->queue);
+ HG_QUEUE_POP_HEAD(&pool->queue, entry);
+
+ /* Unlock */
+ hg_thread_mutex_unlock(&pool->mutex);
+
+ /* Get to work */
+ (*work->func)(work->args);
+ }
+
+unlock:
+ hg_thread_mutex_unlock(&pool->mutex);
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_pool_init(unsigned int thread_count, hg_thread_pool_t **pool_ptr)
+{
+ int ret = HG_UTIL_SUCCESS, rc;
+ struct hg_thread_pool_private *priv_pool = NULL;
+ unsigned int i;
+
+ HG_UTIL_CHECK_ERROR(pool_ptr == NULL, error, ret, HG_UTIL_FAIL, "NULL pointer");
+
+ priv_pool = (struct hg_thread_pool_private *)malloc(sizeof(struct hg_thread_pool_private));
+ HG_UTIL_CHECK_ERROR(priv_pool == NULL, error, ret, HG_UTIL_FAIL, "Could not allocate thread pool");
+
+ priv_pool->pool.sleeping_worker_count = 0;
+ priv_pool->thread_count = thread_count;
+ priv_pool->threads = NULL;
+ HG_QUEUE_INIT(&priv_pool->pool.queue);
+ priv_pool->pool.shutdown = 0;
+
+ rc = hg_thread_mutex_init(&priv_pool->pool.mutex);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, error, ret, HG_UTIL_FAIL, "Could not initialize mutex");
+
+ rc = hg_thread_cond_init(&priv_pool->pool.cond);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, error, ret, HG_UTIL_FAIL,
+ "Could not initialize thread condition");
+
+ priv_pool->threads = (hg_thread_t *)malloc(thread_count * sizeof(hg_thread_t));
+ HG_UTIL_CHECK_ERROR(!priv_pool->threads, error, ret, HG_UTIL_FAIL,
+ "Could not allocate thread pool array");
+
+ /* Start worker threads */
+ for (i = 0; i < thread_count; i++) {
+ rc = hg_thread_create(&priv_pool->threads[i], hg_thread_pool_worker, (void *)priv_pool);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, error, ret, HG_UTIL_FAIL, "Could not create thread");
+ }
+
+ *pool_ptr = (struct hg_thread_pool *)priv_pool;
+
+ return ret;
+
+error:
+ if (priv_pool)
+ hg_thread_pool_destroy((struct hg_thread_pool *)priv_pool);
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_pool_destroy(hg_thread_pool_t *pool)
+{
+ struct hg_thread_pool_private *priv_pool = (struct hg_thread_pool_private *)pool;
+ int ret = HG_UTIL_SUCCESS, rc;
+ unsigned int i;
+
+ if (!priv_pool)
+ goto done;
+
+ if (priv_pool->threads) {
+ hg_thread_mutex_lock(&priv_pool->pool.mutex);
+
+ priv_pool->pool.shutdown = 1;
+
+ rc = hg_thread_cond_broadcast(&priv_pool->pool.cond);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, error, ret, HG_UTIL_FAIL,
+ "Could not broadcast condition signal");
+
+ hg_thread_mutex_unlock(&priv_pool->pool.mutex);
+
+ for (i = 0; i < priv_pool->thread_count; i++) {
+ rc = hg_thread_join(priv_pool->threads[i]);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, done, ret, HG_UTIL_FAIL, "Could not join thread");
+ }
+ }
+
+ rc = hg_thread_mutex_destroy(&priv_pool->pool.mutex);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, done, ret, HG_UTIL_FAIL, "Could not destroy mutex");
+
+ rc = hg_thread_cond_destroy(&priv_pool->pool.cond);
+ HG_UTIL_CHECK_ERROR(rc != HG_UTIL_SUCCESS, done, ret, HG_UTIL_FAIL, "Could not destroy thread condition");
+
+ free(priv_pool->threads);
+ free(priv_pool);
+
+done:
+ return ret;
+
+error:
+ hg_thread_mutex_unlock(&priv_pool->pool.mutex);
+
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_thread_pool.h b/src/mercury/src/util/mercury_thread_pool.h
new file mode 100644
index 0000000..db973d1
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_pool.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_POOL_H
+#define MERCURY_THREAD_POOL_H
+
+#include "mercury_queue.h"
+#include "mercury_thread.h"
+#include "mercury_thread_condition.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+typedef struct hg_thread_pool hg_thread_pool_t;
+
+struct hg_thread_pool {
+ unsigned int sleeping_worker_count;
+ HG_QUEUE_HEAD(hg_thread_work) queue;
+ int shutdown;
+ hg_thread_mutex_t mutex;
+ hg_thread_cond_t cond;
+};
+
+struct hg_thread_work {
+ hg_thread_func_t func;
+ void * args;
+ HG_QUEUE_ENTRY(hg_thread_work) entry; /* Internal */
+};
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the thread pool.
+ *
+ * \param thread_count [IN] number of threads that will be created at
+ * initialization
+ * \param pool [OUT] pointer to pool object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_pool_init(unsigned int thread_count, hg_thread_pool_t **pool);
+
+/**
+ * Destroy the thread pool.
+ *
+ * \param pool [IN/OUT] pointer to pool object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_pool_destroy(hg_thread_pool_t *pool);
+
+/**
+ * Post work to the pool. Note that the operation may be queued depending on
+ * the number of threads and number of tasks already running.
+ *
+ * \param pool [IN/OUT] pointer to pool object
+ * \param work [IN] pointer to work struct
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_pool_post(hg_thread_pool_t *pool, struct hg_thread_work *work)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+ if (!pool || !work)
+ return HG_UTIL_FAIL;
+
+ if (!work->func)
+ return HG_UTIL_FAIL;
+
+ hg_thread_mutex_lock(&pool->mutex);
+
+ /* Are we shutting down ? */
+ if (pool->shutdown) {
+ ret = HG_UTIL_FAIL;
+ goto unlock;
+ }
+
+ /* Add task to task queue */
+ HG_QUEUE_PUSH_TAIL(&pool->queue, work, entry);
+
+ /* Wake up sleeping worker */
+ if (pool->sleeping_worker_count && (hg_thread_cond_signal(&pool->cond) != HG_UTIL_SUCCESS))
+ ret = HG_UTIL_FAIL;
+
+unlock:
+ hg_thread_mutex_unlock(&pool->mutex);
+
+ return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_POOL_H */
diff --git a/src/mercury/src/util/mercury_thread_rwlock.c b/src/mercury/src/util/mercury_thread_rwlock.c
new file mode 100644
index 0000000..9ef8889
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_rwlock.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Copyright (C) 2017 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted for any purpose (including commercial purposes)
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the
+ * documentation and/or materials provided with the distribution.
+ *
+ * 3. In addition, redistributions of modified forms of the source or binary
+ * code must carry prominent notices stating that the original code was
+ * changed and the date of the change.
+ *
+ * 4. All publications or advertising materials mentioning features or use of
+ * this software are asked, but not required, to acknowledge that it was
+ * developed by Intel Corporation and credit the contributors.
+ *
+ * 5. Neither the name of Intel Corporation, nor the name of any Contributor
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mercury_thread_rwlock.h"
+
+#include "mercury_util_error.h"
+
+#include <string.h>
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_rwlock_init(hg_thread_rwlock_t *rwlock)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#ifdef _WIN32
+ InitializeSRWLock(rwlock);
+#else
+ int rc = pthread_rwlock_init(rwlock, NULL);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_rwlock_init() failed (%s)", strerror(rc));
+
+done:
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_rwlock_destroy(hg_thread_rwlock_t *rwlock)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#ifdef _WIN32
+ /* nothing to do */
+#else
+ int rc = pthread_rwlock_destroy(rwlock);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_rwlock_destroy() failed (%s)",
+ strerror(rc));
+
+done:
+#endif
+
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_thread_rwlock.h b/src/mercury/src/util/mercury_thread_rwlock.h
new file mode 100644
index 0000000..f03d2aa
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_rwlock.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Copyright (C) 2017 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted for any purpose (including commercial purposes)
+ * provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the
+ * documentation and/or materials provided with the distribution.
+ *
+ * 3. In addition, redistributions of modified forms of the source or binary
+ * code must carry prominent notices stating that the original code was
+ * changed and the date of the change.
+ *
+ * 4. All publications or advertising materials mentioning features or use of
+ * this software are asked, but not required, to acknowledge that it was
+ * developed by Intel Corporation and credit the contributors.
+ *
+ * 5. Neither the name of Intel Corporation, nor the name of any Contributor
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MERCURY_THREAD_RWLOCK_H
+#define MERCURY_THREAD_RWLOCK_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#ifdef _WIN32
+#include <windows.h>
+typedef PSRWLOCK hg_thread_rwlock_t;
+#else
+#include <pthread.h>
+typedef pthread_rwlock_t HG_LOCK_CAPABILITY("rwlock") hg_thread_rwlock_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_rwlock_init(hg_thread_rwlock_t *rwlock);
+
+/**
+ * Destroy the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_rwlock_destroy(hg_thread_rwlock_t *rwlock);
+
+/**
+ * Take a read lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_rdlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_ACQUIRE_SHARED(*rwlock);
+
+/**
+ * Try to take a read lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_rwlock_try_rdlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_TRY_ACQUIRE_SHARED(HG_UTIL_SUCCESS, *rwlock);
+
+/**
+ * Release the read lock of the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_release_rdlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_RELEASE_SHARED(*rwlock);
+
+/**
+ * Take a write lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_ACQUIRE(*rwlock);
+
+/**
+ * Try to take a write lock for the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_rwlock_try_wrlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *rwlock);
+
+/**
+ * Release the write lock of the rwlock.
+ *
+ * \param rwlock [IN/OUT] pointer to rwlock object
+ */
+static HG_UTIL_INLINE void hg_thread_rwlock_release_wrlock(hg_thread_rwlock_t *rwlock)
+ HG_LOCK_RELEASE(*rwlock);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_rdlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ AcquireSRWLockShared(rwlock);
+#else
+ (void)pthread_rwlock_rdlock(rwlock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_rwlock_try_rdlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ if (TryAcquireSRWLockShared(rwlock) == 0)
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_rwlock_tryrdlock(rwlock))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_release_rdlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ ReleaseSRWLockShared(rwlock);
+#else
+ (void)pthread_rwlock_unlock(rwlock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ ReleaseSRWLockExclusive(rwlock);
+#else
+ (void)pthread_rwlock_wrlock(rwlock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_rwlock_try_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ if (TryAcquireSRWLockExclusive(rwlock) == 0)
+ return HG_UTIL_FAIL;
+#else
+ if (pthread_rwlock_trywrlock(rwlock))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_rwlock_release_wrlock(hg_thread_rwlock_t *rwlock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#ifdef _WIN32
+ ReleaseSRWLockExclusive(rwlock);
+#else
+ (void)pthread_rwlock_unlock(rwlock);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_RWLOCK_H */
diff --git a/src/mercury/src/util/mercury_thread_spin.c b/src/mercury/src/util/mercury_thread_spin.c
new file mode 100644
index 0000000..c96f9fb
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_spin.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_thread_spin.h"
+
+#include "mercury_util_error.h"
+
+#include <string.h>
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_spin_init(hg_thread_spin_t *lock)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#if defined(_WIN32)
+ *lock = 0;
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ int rc = pthread_spin_init(lock, 0);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_spin_init() failed (%s)", strerror(rc));
+
+done:
+#else
+ ret = hg_thread_mutex_init_fast(lock);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+int
+hg_thread_spin_destroy(hg_thread_spin_t *lock)
+{
+ int ret = HG_UTIL_SUCCESS;
+
+#if defined(_WIN32)
+ (void)lock;
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ int rc = pthread_spin_destroy(lock);
+ HG_UTIL_CHECK_ERROR(rc != 0, done, ret, HG_UTIL_FAIL, "pthread_spin_destroy() failed (%s)", strerror(rc));
+
+done:
+#else
+ ret = hg_thread_mutex_destroy(lock);
+#endif
+
+ return ret;
+}
diff --git a/src/mercury/src/util/mercury_thread_spin.h b/src/mercury/src/util/mercury_thread_spin.h
new file mode 100644
index 0000000..36ce5f8
--- /dev/null
+++ b/src/mercury/src/util/mercury_thread_spin.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_THREAD_SPIN_H
+#define MERCURY_THREAD_SPIN_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+typedef volatile LONG hg_thread_spin_t;
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+#include <pthread.h>
+typedef pthread_spinlock_t HG_LOCK_CAPABILITY("spin") hg_thread_spin_t;
+#else
+/* Default to hg_thread_mutex_t if pthread_spinlock_t is not supported */
+#include "mercury_thread_mutex.h"
+typedef hg_thread_mutex_t HG_LOCK_CAPABILITY("mutex") hg_thread_spin_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the spin lock.
+ *
+ * \param lock [IN/OUT] pointer to lock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_spin_init(hg_thread_spin_t *lock);
+
+/**
+ * Destroy the spin lock.
+ *
+ * \param lock [IN/OUT] pointer to lock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+HG_UTIL_PUBLIC int hg_thread_spin_destroy(hg_thread_spin_t *lock);
+
+/**
+ * Lock the spin lock.
+ *
+ * \param lock [IN/OUT] pointer to lock object
+ */
+static HG_UTIL_INLINE void hg_thread_spin_lock(hg_thread_spin_t *lock) HG_LOCK_ACQUIRE(*lock);
+
+/**
+ * Try locking the spin lock.
+ *
+ * \param mutex [IN/OUT] pointer to lock object
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_thread_spin_try_lock(hg_thread_spin_t *lock)
+ HG_LOCK_TRY_ACQUIRE(HG_UTIL_SUCCESS, *lock);
+
+/**
+ * Unlock the spin lock.
+ *
+ * \param mutex [IN/OUT] pointer to lock object
+ */
+static HG_UTIL_INLINE void hg_thread_spin_unlock(hg_thread_spin_t *lock) HG_LOCK_RELEASE(*lock);
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_spin_lock(hg_thread_spin_t *lock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#if defined(_WIN32)
+ while (InterlockedExchange(lock, EBUSY)) {
+ /* Don't lock while waiting */
+ while (*lock) {
+ YieldProcessor();
+
+ /* Compiler barrier. Prevent caching of *lock */
+ MemoryBarrier();
+ }
+ }
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ (void)pthread_spin_lock(lock);
+#else
+ hg_thread_mutex_lock(lock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_thread_spin_try_lock(hg_thread_spin_t *lock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#if defined(_WIN32)
+ return InterlockedExchange(lock, EBUSY);
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ if (pthread_spin_trylock(lock))
+ return HG_UTIL_FAIL;
+
+ return HG_UTIL_SUCCESS;
+#else
+ return hg_thread_mutex_try_lock(lock);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_thread_spin_unlock(hg_thread_spin_t *lock) HG_LOCK_NO_THREAD_SAFETY_ANALYSIS
+{
+#if defined(_WIN32)
+ /* Compiler barrier. The store below acts with release semantics */
+ MemoryBarrier();
+ *lock = 0;
+#elif defined(HG_UTIL_HAS_PTHREAD_SPINLOCK_T)
+ (void)pthread_spin_unlock(lock);
+#else
+ hg_thread_mutex_unlock(lock);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_THREAD_SPIN_H */
diff --git a/src/mercury/src/util/mercury_time.h b/src/mercury/src/util/mercury_time.h
new file mode 100644
index 0000000..f158638
--- /dev/null
+++ b/src/mercury/src/util/mercury_time.h
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_TIME_H
+#define MERCURY_TIME_H
+
+#include "mercury_util_config.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+#include <time.h>
+#elif defined(__APPLE__) && defined(HG_UTIL_HAS_SYSTIME_H)
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#else
+#include <stdio.h>
+#include <unistd.h>
+#if defined(HG_UTIL_HAS_SYSTIME_H)
+#include <sys/time.h>
+#else
+#error "Not supported on this platform."
+#endif
+#endif
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+typedef struct timespec hg_time_t;
+#else
+typedef struct hg_time hg_time_t;
+
+struct hg_time {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get an elapsed time on the calling processor.
+ *
+ * \param tv [OUT] pointer to returned time structure
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_time_get_current(hg_time_t *tv);
+
+/**
+ * Get an elapsed time on the calling processor (resolution is ms).
+ *
+ * \param tv [OUT] pointer to returned time structure
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_time_get_current_ms(hg_time_t *tv);
+
+/**
+ * Convert hg_time_t to double.
+ *
+ * \param tv [IN] time structure
+ *
+ * \return Converted time in seconds
+ */
+static HG_UTIL_INLINE double hg_time_to_double(hg_time_t tv);
+
+/**
+ * Convert double to hg_time_t.
+ *
+ * \param d [IN] time in seconds
+ *
+ * \return Converted time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_from_double(double d);
+
+/**
+ * Convert (integer) milliseconds to hg_time_t.
+ *
+ * \param ms [IN] time in milliseconds
+ *
+ * \return Converted time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_from_ms(unsigned int ms);
+
+/**
+ * Convert hg_time_t to (integer) milliseconds.
+ *
+ * \param tv [IN] time structure
+ *
+ * \return Time in milliseconds
+ */
+static HG_UTIL_INLINE unsigned int hg_time_to_ms(hg_time_t tv);
+
+/**
+ * Compare time values.
+ *
+ * \param in1 [IN] time structure
+ * \param in2 [IN] time structure
+ *
+ * \return 1 if in1 < in2, 0 otherwise
+ */
+static HG_UTIL_INLINE int hg_time_less(hg_time_t in1, hg_time_t in2);
+
+/**
+ * Diff time values and return the number of seconds elapsed between
+ * time \in2 and time \in1.
+ *
+ * \param in2 [IN] time structure
+ * \param in1 [IN] time structure
+ *
+ * \return Subtracted time
+ */
+static HG_UTIL_INLINE double hg_time_diff(hg_time_t in2, hg_time_t in1);
+
+/**
+ * Add time values.
+ *
+ * \param in1 [IN] time structure
+ * \param in2 [IN] time structure
+ *
+ * \return Summed time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_add(hg_time_t in1, hg_time_t in2);
+
+/**
+ * Subtract time values.
+ *
+ * \param in1 [IN] time structure
+ * \param in2 [IN] time structure
+ *
+ * \return Subtracted time structure
+ */
+static HG_UTIL_INLINE hg_time_t hg_time_subtract(hg_time_t in1, hg_time_t in2);
+
+/**
+ * Sleep until the time specified in rqt has elapsed.
+ *
+ * \param reqt [IN] time structure
+ *
+ * \return Non-negative on success or negative on failure
+ */
+static HG_UTIL_INLINE int hg_time_sleep(const hg_time_t rqt);
+
+/**
+ * Get a string containing current time/date stamp.
+ *
+ * \return Valid string or NULL on failure
+ */
+static HG_UTIL_INLINE char *hg_time_stamp(void);
+
+/*---------------------------------------------------------------------------*/
+#ifdef _WIN32
+static HG_UTIL_INLINE LARGE_INTEGER
+get_FILETIME_offset(void)
+{
+ SYSTEMTIME s;
+ FILETIME f;
+ LARGE_INTEGER t;
+
+ s.wYear = 1970;
+ s.wMonth = 1;
+ s.wDay = 1;
+ s.wHour = 0;
+ s.wMinute = 0;
+ s.wSecond = 0;
+ s.wMilliseconds = 0;
+ SystemTimeToFileTime(&s, &f);
+ t.QuadPart = f.dwHighDateTime;
+ t.QuadPart <<= 32;
+ t.QuadPart |= f.dwLowDateTime;
+
+ return t;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ LARGE_INTEGER t;
+ FILETIME f;
+ double t_usec;
+ static LARGE_INTEGER offset;
+ static double freq_to_usec;
+ static int initialized = 0;
+ static BOOL use_perf_counter = 0;
+
+ if (!initialized) {
+ LARGE_INTEGER perf_freq;
+ initialized = 1;
+ use_perf_counter = QueryPerformanceFrequency(&perf_freq);
+ if (use_perf_counter) {
+ QueryPerformanceCounter(&offset);
+ freq_to_usec = (double)perf_freq.QuadPart / 1000000.;
+ }
+ else {
+ offset = get_FILETIME_offset();
+ freq_to_usec = 10.;
+ }
+ }
+ if (use_perf_counter) {
+ QueryPerformanceCounter(&t);
+ }
+ else {
+ GetSystemTimeAsFileTime(&f);
+ t.QuadPart = f.dwHighDateTime;
+ t.QuadPart <<= 32;
+ t.QuadPart |= f.dwLowDateTime;
+ }
+
+ t.QuadPart -= offset.QuadPart;
+ t_usec = (double)t.QuadPart / freq_to_usec;
+ t.QuadPart = t_usec;
+ tv->tv_sec = t.QuadPart / 1000000;
+ tv->tv_usec = t.QuadPart % 1000000;
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+ return hg_time_get_current(tv);
+}
+
+/*---------------------------------------------------------------------------*/
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ clock_gettime(CLOCK_MONOTONIC, tv);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+/* ppc/32 and ppc/64 do not support CLOCK_MONOTONIC_COARSE in vdso */
+#if defined(__ppc64__) || defined(__ppc__) || defined(__PPC64__) || defined(__PPC__) || \
+ !defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE)
+ clock_gettime(CLOCK_MONOTONIC, tv);
+#else
+ /* We don't need fine grain time stamps, _COARSE resolution is 1ms */
+ clock_gettime(CLOCK_MONOTONIC_COARSE, tv);
+#endif
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+#elif defined(__APPLE__) && defined(HG_UTIL_HAS_SYSTIME_H)
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ static uint64_t monotonic_timebase_factor = 0;
+ uint64_t monotonic_nsec;
+
+ if (monotonic_timebase_factor == 0) {
+ mach_timebase_info_data_t timebase_info;
+
+ (void)mach_timebase_info(&timebase_info);
+ monotonic_timebase_factor = timebase_info.numer / timebase_info.denom;
+ }
+ monotonic_nsec = (mach_absolute_time() * monotonic_timebase_factor);
+ tv->tv_sec = (long)(monotonic_nsec / 1000000000);
+ tv->tv_usec = (long)((monotonic_nsec - (uint64_t)tv->tv_sec) / 1000);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+ return hg_time_get_current(tv);
+}
+
+#else
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current(hg_time_t *tv)
+{
+ gettimeofday((struct timeval *)tv, NULL);
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_get_current_ms(hg_time_t *tv)
+{
+ return hg_time_get_current(tv);
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE double
+hg_time_to_double(hg_time_t tv)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return (double)tv.tv_sec + (double)(tv.tv_nsec) * 0.000000001;
+#else
+ return (double)tv.tv_sec + (double)(tv.tv_usec) * 0.000001;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_from_double(double d)
+{
+ hg_time_t tv;
+
+ tv.tv_sec = (long)d;
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ tv.tv_nsec = (long)((d - (double)(tv.tv_sec)) * 1000000000);
+#else
+ tv.tv_usec = (long)((d - (double)(tv.tv_sec)) * 1000000);
+#endif
+
+ return tv;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE unsigned int
+hg_time_to_ms(hg_time_t tv)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return (unsigned int)(tv.tv_sec * 1000 + tv.tv_nsec / 1000000);
+#else
+ return (unsigned int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_from_ms(unsigned int ms)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return (hg_time_t){.tv_sec = ms / 1000, .tv_nsec = (ms - (ms / 1000) * 1000) * 1000000};
+#else
+ return (hg_time_t){.tv_sec = ms / 1000, .tv_usec = (ms - (ms / 1000) * 1000) * 1000};
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_less(hg_time_t in1, hg_time_t in2)
+{
+ return ((in1.tv_sec < in2.tv_sec) || ((in1.tv_sec == in2.tv_sec) &&
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ (in1.tv_nsec < in2.tv_nsec)));
+#else
+ (in1.tv_usec < in2.tv_usec)));
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE double
+hg_time_diff(hg_time_t in2, hg_time_t in1)
+{
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ return ((double)in2.tv_sec + (double)(in2.tv_nsec) * 0.000000001) -
+ ((double)in1.tv_sec + (double)(in1.tv_nsec) * 0.000000001);
+#else
+ return ((double)in2.tv_sec + (double)(in2.tv_usec) * 0.000001) -
+ ((double)in1.tv_sec + (double)(in1.tv_usec) * 0.000001);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_add(hg_time_t in1, hg_time_t in2)
+{
+ hg_time_t out;
+
+ out.tv_sec = in1.tv_sec + in2.tv_sec;
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ out.tv_nsec = in1.tv_nsec + in2.tv_nsec;
+ if (out.tv_nsec > 1000000000) {
+ out.tv_nsec -= 1000000000;
+ out.tv_sec += 1;
+ }
+#else
+ out.tv_usec = in1.tv_usec + in2.tv_usec;
+ if (out.tv_usec > 1000000) {
+ out.tv_usec -= 1000000;
+ out.tv_sec += 1;
+ }
+#endif
+
+ return out;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE hg_time_t
+hg_time_subtract(hg_time_t in1, hg_time_t in2)
+{
+ hg_time_t out;
+
+ out.tv_sec = in1.tv_sec - in2.tv_sec;
+#if defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ out.tv_nsec = in1.tv_nsec - in2.tv_nsec;
+ if (out.tv_nsec < 0) {
+ out.tv_nsec += 1000000000;
+ out.tv_sec -= 1;
+ }
+#else
+ out.tv_usec = in1.tv_usec - in2.tv_usec;
+ if (out.tv_usec < 0) {
+ out.tv_usec += 1000000;
+ out.tv_sec -= 1;
+ }
+#endif
+
+ return out;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int
+hg_time_sleep(const hg_time_t rqt)
+{
+#ifdef _WIN32
+ DWORD dwMilliseconds = (DWORD)(hg_time_to_double(rqt) / 1000);
+
+ Sleep(dwMilliseconds);
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ if (nanosleep(&rqt, NULL))
+ return HG_UTIL_FAIL;
+#else
+ useconds_t usec = (useconds_t)rqt.tv_sec * 1000000 + (useconds_t)rqt.tv_usec;
+
+ if (usleep(usec))
+ return HG_UTIL_FAIL;
+#endif
+
+ return HG_UTIL_SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+#define HG_UTIL_STAMP_MAX 128
+static HG_UTIL_INLINE char *
+hg_time_stamp(void)
+{
+ static char buf[HG_UTIL_STAMP_MAX] = {'\0'};
+
+#if defined(_WIN32)
+ /* TODO not implemented */
+#elif defined(HG_UTIL_HAS_TIME_H) && defined(HG_UTIL_HAS_CLOCK_GETTIME)
+ struct tm *local_time;
+ time_t t;
+
+ t = time(NULL);
+ local_time = localtime(&t);
+ if (local_time == NULL)
+ return NULL;
+
+ if (strftime(buf, HG_UTIL_STAMP_MAX, "%a, %d %b %Y %T %Z", local_time) == 0)
+ return NULL;
+#else
+ struct timeval tv;
+ struct timezone tz;
+ unsigned long days, hours, minutes, seconds;
+
+ gettimeofday(&tv, &tz);
+ days = (unsigned long)tv.tv_sec / (3600 * 24);
+ hours = ((unsigned long)tv.tv_sec - days * 24 * 3600) / 3600;
+ minutes = ((unsigned long)tv.tv_sec - days * 24 * 3600 - hours * 3600) / 60;
+ seconds = (unsigned long)tv.tv_sec - days * 24 * 3600 - hours * 3600 - minutes * 60;
+ hours -= (unsigned long)tz.tz_minuteswest / 60;
+
+ snprintf(buf, HG_UTIL_STAMP_MAX, "%02lu:%02lu:%02lu (GMT-%d)", hours, minutes, seconds,
+ tz.tz_minuteswest / 60);
+#endif
+
+ return buf;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_TIME_H */
diff --git a/src/mercury/src/util/mercury_util.c b/src/mercury/src/util/mercury_util.c
new file mode 100644
index 0000000..ced8979
--- /dev/null
+++ b/src/mercury/src/util/mercury_util.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#include "mercury_util.h"
+
+#include "mercury_util_error.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Name of this subsystem */
+#define HG_UTIL_SUBSYS_NAME hg_util
+#define HG_UTIL_STRINGIFY1(x) HG_UTIL_STRINGIFY(x)
+#define HG_UTIL_SUBSYS_NAME_STRING HG_UTIL_STRINGIFY1(HG_UTIL_SUBSYS_NAME)
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+/* Default error log mask */
+HG_LOG_SUBSYS_DECL_REGISTER(HG_UTIL_SUBSYS_NAME, hg);
+
+/*---------------------------------------------------------------------------*/
+void
+HG_Util_set_log_level(const char *level)
+{
+ hg_log_set_subsys_level(HG_UTIL_SUBSYS_NAME_STRING, hg_log_name_to_level(level));
+}
diff --git a/src/mercury/src/util/mercury_util.h b/src/mercury/src/util/mercury_util.h
new file mode 100644
index 0000000..1e36e26
--- /dev/null
+++ b/src/mercury/src/util/mercury_util.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_UTIL_LOG_H
+#define MERCURY_UTIL_LOG_H
+
+#include "mercury_util_config.h"
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*********************/
+/* Public Prototypes */
+/*********************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Set the log level for HG util. That setting is valid for all HG classes.
+ *
+ * \param level [IN] level string, valid values are:
+ * "none", "error", "warning", "debug"
+ */
+HG_UTIL_PUBLIC void HG_Util_set_log_level(const char *level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_UTIL_LOG_H */
diff --git a/src/mercury/src/util/mercury_util_config.h b/src/mercury/src/util/mercury_util_config.h
new file mode 100644
index 0000000..8237b4d
--- /dev/null
+++ b/src/mercury/src/util/mercury_util_config.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Generated file. Only edit mercury_util_config.h.in. */
+
+#ifndef MERCURY_UTIL_CONFIG_H
+#define MERCURY_UTIL_CONFIG_H
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* Type definitions */
+#ifdef _WIN32
+typedef signed __int64 hg_util_int64_t;
+typedef signed __int32 hg_util_int32_t;
+typedef signed __int16 hg_util_int16_t;
+typedef signed __int8 hg_util_int8_t;
+typedef unsigned __int64 hg_util_uint64_t;
+typedef unsigned __int32 hg_util_uint32_t;
+typedef unsigned __int16 hg_util_uint16_t;
+typedef unsigned __int8 hg_util_uint8_t;
+#else
+#include <stddef.h>
+#include <stdint.h>
+typedef int64_t hg_util_int64_t;
+typedef int32_t hg_util_int32_t;
+typedef int16_t hg_util_int16_t;
+typedef int8_t hg_util_int8_t;
+typedef uint64_t hg_util_uint64_t;
+typedef uint32_t hg_util_uint32_t;
+typedef uint16_t hg_util_uint16_t;
+typedef uint8_t hg_util_uint8_t;
+#endif
+typedef hg_util_uint8_t hg_util_bool_t;
+typedef hg_util_uint64_t hg_util_ptr_t;
+
+/* True / false */
+#define HG_UTIL_TRUE 1
+#define HG_UTIL_FALSE 0
+
+/* Return codes */
+#define HG_UTIL_SUCCESS 0
+#define HG_UTIL_FAIL -1
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Visibility of symbols */
+#if defined(_WIN32)
+#define HG_UTIL_ABI_IMPORT __declspec(dllimport)
+#define HG_UTIL_ABI_EXPORT __declspec(dllexport)
+#define HG_UTIL_ABI_HIDDEN
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+#define HG_UTIL_ABI_IMPORT __attribute__((visibility("default")))
+#define HG_UTIL_ABI_EXPORT __attribute__((visibility("default")))
+#define HG_UTIL_ABI_HIDDEN __attribute__((visibility("hidden")))
+#else
+#define HG_UTIL_ABI_IMPORT
+#define HG_UTIL_ABI_EXPORT
+#define HG_UTIL_ABI_HIDDEN
+#endif
+
+/* Inline macro */
+#ifdef _WIN32
+#define HG_UTIL_INLINE __inline
+#else
+#define HG_UTIL_INLINE __inline__
+#endif
+
+/* Check format arguments */
+#if defined(__GNUC__)
+#define HG_UTIL_PRINTF_LIKE(_fmt, _firstarg) __attribute__((format(printf, _fmt, _firstarg)))
+#else
+#define HG_UTIL_PRINTF_LIKE(_fmt, _firstarg)
+#endif
+
+/* Shared libraries */
+/* #undef HG_UTIL_BUILD_SHARED_LIBS */
+#ifdef HG_UTIL_BUILD_SHARED_LIBS
+#ifdef mercury_util_EXPORTS
+#define HG_UTIL_PUBLIC HG_UTIL_ABI_EXPORT
+#else
+#define HG_UTIL_PUBLIC HG_UTIL_ABI_IMPORT
+#endif
+#define HG_UTIL_PRIVATE HG_UTIL_ABI_HIDDEN
+#else
+#define HG_UTIL_PUBLIC
+#define HG_UTIL_PRIVATE
+#endif
+
+/* Define if has __attribute__((constructor)) */
+#define HG_UTIL_HAS_ATTR_CONSTRUCTOR
+
+/* Define if has __attribute__((constructor(priority))) */
+#define HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+
+/* Define if has 'clock_gettime()' */
+#define HG_UTIL_HAS_CLOCK_GETTIME
+
+/* Define if has CLOCK_MONOTONIC_COARSE */
+#define HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE
+
+/* Define is has debug */
+/* #undef HG_UTIL_HAS_DEBUG */
+
+/* Define if has eventfd_t type */
+#define HG_UTIL_HAS_EVENTFD_T
+
+/* Define if has colored output */
+/* #undef HG_UTIL_HAS_LOG_COLOR */
+
+/* Define if has <opa_primitives.h> */
+/* #undef HG_UTIL_HAS_OPA_PRIMITIVES_H */
+
+/* Define if has 'pthread_condattr_setclock()' */
+#define HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK
+
+/* Define if has PTHREAD_MUTEX_ADAPTIVE_NP */
+#define HG_UTIL_HAS_PTHREAD_MUTEX_ADAPTIVE_NP
+
+/* Define if has pthread_spinlock_t type */
+#define HG_UTIL_HAS_PTHREAD_SPINLOCK_T
+
+/* Define if has <stdatomic.h> */
+#define HG_UTIL_HAS_STDATOMIC_H
+
+/* Define type size of atomic_long */
+#define HG_UTIL_ATOMIC_LONG_WIDTH 8
+
+/* Define if has <sys/epoll.h> */
+#define HG_UTIL_HAS_SYSEPOLL_H
+
+/* Define if has <sys/event.h> */
+/* #undef HG_UTIL_HAS_SYSEVENT_H */
+
+/* Define if has <sys/eventfd.h> */
+#define HG_UTIL_HAS_SYSEVENTFD_H
+
+/* Define if has <sys/time.h> */
+#define HG_UTIL_HAS_SYSTIME_H
+
+/* Define if has <time.h> */
+#define HG_UTIL_HAS_TIME_H
+
+#endif /* MERCURY_UTIL_CONFIG_H */
diff --git a/src/mercury/src/util/mercury_util_config.h.in b/src/mercury/src/util/mercury_util_config.h.in
new file mode 100644
index 0000000..f3a04cd
--- /dev/null
+++ b/src/mercury/src/util/mercury_util_config.h.in
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+/* Generated file. Only edit mercury_util_config.h.in. */
+
+#ifndef MERCURY_UTIL_CONFIG_H
+#define MERCURY_UTIL_CONFIG_H
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/* Type definitions */
+#ifdef _WIN32
+typedef signed __int64 hg_util_int64_t;
+typedef signed __int32 hg_util_int32_t;
+typedef signed __int16 hg_util_int16_t;
+typedef signed __int8 hg_util_int8_t;
+typedef unsigned __int64 hg_util_uint64_t;
+typedef unsigned __int32 hg_util_uint32_t;
+typedef unsigned __int16 hg_util_uint16_t;
+typedef unsigned __int8 hg_util_uint8_t;
+#else
+# include <stddef.h>
+# include <stdint.h>
+typedef int64_t hg_util_int64_t;
+typedef int32_t hg_util_int32_t;
+typedef int16_t hg_util_int16_t;
+typedef int8_t hg_util_int8_t;
+typedef uint64_t hg_util_uint64_t;
+typedef uint32_t hg_util_uint32_t;
+typedef uint16_t hg_util_uint16_t;
+typedef uint8_t hg_util_uint8_t;
+#endif
+typedef hg_util_uint8_t hg_util_bool_t;
+typedef hg_util_uint64_t hg_util_ptr_t;
+
+/* True / false */
+#define HG_UTIL_TRUE 1
+#define HG_UTIL_FALSE 0
+
+/* Return codes */
+#define HG_UTIL_SUCCESS 0
+#define HG_UTIL_FAIL -1
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Visibility of symbols */
+#if defined(_WIN32)
+# define HG_UTIL_ABI_IMPORT __declspec(dllimport)
+# define HG_UTIL_ABI_EXPORT __declspec(dllexport)
+# define HG_UTIL_ABI_HIDDEN
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+# define HG_UTIL_ABI_IMPORT __attribute__((visibility("default")))
+# define HG_UTIL_ABI_EXPORT __attribute__((visibility("default")))
+# define HG_UTIL_ABI_HIDDEN __attribute__((visibility("hidden")))
+#else
+# define HG_UTIL_ABI_IMPORT
+# define HG_UTIL_ABI_EXPORT
+# define HG_UTIL_ABI_HIDDEN
+#endif
+
+/* Inline macro */
+#ifdef _WIN32
+# define HG_UTIL_INLINE __inline
+#else
+# define HG_UTIL_INLINE __inline__
+#endif
+
+/* Check format arguments */
+#if defined(__GNUC__)
+# define HG_UTIL_PRINTF_LIKE(_fmt, _firstarg) \
+ __attribute__((format(printf, _fmt, _firstarg)))
+#else
+# define HG_UTIL_PRINTF_LIKE(_fmt, _firstarg)
+#endif
+
+/* Shared libraries */
+#cmakedefine HG_UTIL_BUILD_SHARED_LIBS
+#ifdef HG_UTIL_BUILD_SHARED_LIBS
+# ifdef mercury_util_EXPORTS
+# define HG_UTIL_PUBLIC HG_UTIL_ABI_EXPORT
+# else
+# define HG_UTIL_PUBLIC HG_UTIL_ABI_IMPORT
+# endif
+# define HG_UTIL_PRIVATE HG_UTIL_ABI_HIDDEN
+#else
+# define HG_UTIL_PUBLIC
+# define HG_UTIL_PRIVATE
+#endif
+
+/* Define if has __attribute__((constructor)) */
+#cmakedefine HG_UTIL_HAS_ATTR_CONSTRUCTOR
+
+/* Define if has __attribute__((constructor(priority))) */
+#cmakedefine HG_UTIL_HAS_ATTR_CONSTRUCTOR_PRIORITY
+
+/* Define if has 'clock_gettime()' */
+#cmakedefine HG_UTIL_HAS_CLOCK_GETTIME
+
+/* Define if has CLOCK_MONOTONIC_COARSE */
+#cmakedefine HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE
+
+/* Define is has debug */
+#cmakedefine HG_UTIL_HAS_DEBUG
+
+/* Define if has eventfd_t type */
+#cmakedefine HG_UTIL_HAS_EVENTFD_T
+
+/* Define if has colored output */
+#cmakedefine HG_UTIL_HAS_LOG_COLOR
+
+/* Define if has <opa_primitives.h> */
+#cmakedefine HG_UTIL_HAS_OPA_PRIMITIVES_H
+
+/* Define if has 'pthread_condattr_setclock()' */
+#cmakedefine HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK
+
+/* Define if has PTHREAD_MUTEX_ADAPTIVE_NP */
+#cmakedefine HG_UTIL_HAS_PTHREAD_MUTEX_ADAPTIVE_NP
+
+/* Define if has pthread_spinlock_t type */
+#cmakedefine HG_UTIL_HAS_PTHREAD_SPINLOCK_T
+
+/* Define if has <stdatomic.h> */
+#cmakedefine HG_UTIL_HAS_STDATOMIC_H
+
+/* Define type size of atomic_long */
+#cmakedefine HG_UTIL_ATOMIC_LONG_WIDTH @HG_UTIL_ATOMIC_LONG_WIDTH@
+
+/* Define if has <sys/epoll.h> */
+#cmakedefine HG_UTIL_HAS_SYSEPOLL_H
+
+/* Define if has <sys/event.h> */
+#cmakedefine HG_UTIL_HAS_SYSEVENT_H
+
+/* Define if has <sys/eventfd.h> */
+#cmakedefine HG_UTIL_HAS_SYSEVENTFD_H
+
+/* Define if has <sys/time.h> */
+#cmakedefine HG_UTIL_HAS_SYSTIME_H
+
+/* Define if has <time.h> */
+#cmakedefine HG_UTIL_HAS_TIME_H
+
+#endif /* MERCURY_UTIL_CONFIG_H */
diff --git a/src/mercury/src/util/mercury_util_error.h b/src/mercury/src/util/mercury_util_error.h
new file mode 100644
index 0000000..bcf51b7
--- /dev/null
+++ b/src/mercury/src/util/mercury_util_error.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2013-2020 Argonne National Laboratory, Department of Energy,
+ * UChicago Argonne, LLC and The HDF Group.
+ * All rights reserved.
+ *
+ * The full copyright notice, including terms governing use, modification,
+ * and redistribution, is contained in the COPYING file that can be
+ * found at the root of the source code distribution tree.
+ */
+
+#ifndef MERCURY_UTIL_ERROR_H
+#define MERCURY_UTIL_ERROR_H
+
+#include "mercury_util_config.h"
+
+/* Default error macro */
+#include <mercury_log.h>
+extern HG_UTIL_PRIVATE HG_LOG_OUTLET_DECL(hg_util);
+#define HG_UTIL_LOG_ERROR(...) HG_LOG_WRITE(hg_util, HG_LOG_LEVEL_ERROR, __VA_ARGS__)
+#define HG_UTIL_LOG_WARNING(...) HG_LOG_WRITE(hg_util, HG_LOG_LEVEL_WARNING, __VA_ARGS__)
+#ifdef HG_UTIL_HAS_DEBUG
+#define HG_UTIL_LOG_DEBUG(...) HG_LOG_WRITE(hg_util, HG_LOG_LEVEL_DEBUG, __VA_ARGS__)
+#else
+#define HG_UTIL_LOG_DEBUG(...) (void)0
+#endif
+
+/* Branch predictor hints */
+#ifndef _WIN32
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+/* Error macros */
+#define HG_UTIL_GOTO_DONE(label, ret, ret_val) \
+ do { \
+ ret = ret_val; \
+ goto label; \
+ } while (0)
+
+#define HG_UTIL_GOTO_ERROR(label, ret, err_val, ...) \
+ do { \
+ HG_UTIL_LOG_ERROR(__VA_ARGS__); \
+ ret = err_val; \
+ goto label; \
+ } while (0)
+
+/* Check for cond, set ret to err_val and goto label */
+#define HG_UTIL_CHECK_ERROR(cond, label, ret, err_val, ...) \
+ do { \
+ if (unlikely(cond)) { \
+ HG_UTIL_LOG_ERROR(__VA_ARGS__); \
+ ret = err_val; \
+ goto label; \
+ } \
+ } while (0)
+
+#define HG_UTIL_CHECK_ERROR_NORET(cond, label, ...) \
+ do { \
+ if (unlikely(cond)) { \
+ HG_UTIL_LOG_ERROR(__VA_ARGS__); \
+ goto label; \
+ } \
+ } while (0)
+
+#define HG_UTIL_CHECK_ERROR_DONE(cond, ...) \
+ do { \
+ if (unlikely(cond)) { \
+ HG_UTIL_LOG_ERROR(__VA_ARGS__); \
+ } \
+ } while (0)
+
+/* Check for cond and print warning */
+#define HG_UTIL_CHECK_WARNING(cond, ...) \
+ do { \
+ if (unlikely(cond)) { \
+ HG_UTIL_LOG_WARNING(__VA_ARGS__); \
+ } \
+ } while (0)
+
+#endif /* MERCURY_UTIL_ERROR_H */
diff --git a/src/mercury/version.txt b/src/mercury/version.txt
new file mode 100644
index 0000000..0c271bc
--- /dev/null
+++ b/src/mercury/version.txt
@@ -0,0 +1 @@
+2.1.0rc1