summaryrefslogtreecommitdiffstats
path: root/src/H5FDsubfiling/mercury
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5FDsubfiling/mercury')
-rw-r--r--src/H5FDsubfiling/mercury/LICENSE.txt27
-rw-r--r--src/H5FDsubfiling/mercury/README.md230
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_atomic.h584
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h116
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_dlog.c308
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_dlog.h282
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_list.h113
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_log.c498
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_log.h333
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_queue.h115
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread.c162
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread.h225
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_annotation.h35
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c42
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h172
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c92
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h121
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.c175
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h114
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_time.h500
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_util.c47
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_util.h49
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_util_config.h116
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_util_config.h.in116
-rw-r--r--src/H5FDsubfiling/mercury/src/util/mercury_util_error.h79
-rw-r--r--src/H5FDsubfiling/mercury/src/util/version.txt1
-rw-r--r--src/H5FDsubfiling/mercury/version.txt1
27 files changed, 4653 insertions, 0 deletions
diff --git a/src/H5FDsubfiling/mercury/LICENSE.txt b/src/H5FDsubfiling/mercury/LICENSE.txt
new file mode 100644
index 0000000..d3f4203
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2013-2021, UChicago Argonne, LLC and The HDF Group.
+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 copyright holder 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 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 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.
diff --git a/src/H5FDsubfiling/mercury/README.md b/src/H5FDsubfiling/mercury/README.md
new file mode 100644
index 0000000..d159548
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/README.md
@@ -0,0 +1,230 @@
+Mercury
+=======
+[![Build status][github-ci-svg]][github-ci-link]
+[![Latest version][mercury-release-svg]][mercury-release-link]
+[![Spack version][spack-release-svg]][spack-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.
+Mercury is a core component of the [Mochi][mochi-link] ecosystem of
+microservices.
+
+Please see the accompanying LICENSE.txt 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`.
+
+The UCX plugin is also available as an alternative transport on platforms
+for which libfabric is either not available or not recommended to use,
+currently supported protocols are tcp and verbs.
+
+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 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 OFI libfabric plugin, please refer to the libfabric build
+instructions available on this [page][libfabric].
+
+To make use of the UCX plugin, please refer to the UCX build
+instructions available on this [page][ucx].
+
+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://github.com/radix-io/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.
+
+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.
+
+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:
+
+ 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
+ NA_USE_UCX 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` environment
+ variable 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. Specific subsystems can be selected using
+ the `HG_LOG_SUBSYS` environment variable.
+
+[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
+[ucx]: https://openucx.readthedocs.io/en/master/running.html#ucx-build-and-install
+[github-ci-svg]: https://github.com/mercury-hpc/mercury/actions/workflows/ci.yml/badge.svg?branch=master
+[github-ci-link]: https://github.com/mercury-hpc/mercury/actions/workflows/ci.yml
+[mercury-release-svg]: https://img.shields.io/github/release/mercury-hpc/mercury/all.svg
+[mercury-release-link]: https://github.com/mercury-hpc/mercury/releases
+[spack-release-svg]: https://img.shields.io/spack/v/mercury.svg
+[spack-release-link]: https://spack.readthedocs.io/en/latest/package_list.html#mercury
+[yama]: https://www.kernel.org/doc/Documentation/security/Yama.txt
+[mochi-link]: https://github.com/mochi-hpc/
+
diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_atomic.h b/src/H5FDsubfiling/mercury/src/util/mercury_atomic.h
new file mode 100644
index 0000000..54562ad
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_atomic.h
@@ -0,0 +1,584 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MERCURY_ATOMIC_H
+#define MERCURY_ATOMIC_H
+
+#include "mercury_util_config.h"
+
+#if defined(_WIN32)
+#define _WINSOCKAPI_
+#include <windows.h>
+typedef struct {
+ volatile LONG value;
+} hg_atomic_int32_t;
+typedef struct {
+ volatile LONGLONG value;
+} hg_atomic_int64_t;
+/* clang-format off */
+# define HG_ATOMIC_VAR_INIT(x) {(x)}
+/* clang-format on */
+#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 int32_t value;
+} hg_atomic_int32_t;
+typedef struct {
+ volatile int64_t value;
+} hg_atomic_int64_t;
+/* clang-format off */
+# define HG_ATOMIC_VAR_INIT(x) {(x)}
+/* clang-format on */
+#else /* GCC 4.7 */
+#if !defined(__GNUC__) || ((__GNUC__ < 4) && (__GNUC_MINOR__ < 7))
+#error "GCC version >= 4.7 required to support built-in atomics."
+#endif
+/* builtins do not require volatile */
+typedef int32_t hg_atomic_int32_t;
+typedef int64_t hg_atomic_int64_t;
+#define HG_ATOMIC_VAR_INIT(x) (x)
+#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, 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, 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 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 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 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 int32_t hg_atomic_or32(hg_atomic_int32_t *ptr, 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 int32_t hg_atomic_xor32(hg_atomic_int32_t *ptr, 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 int32_t hg_atomic_and32(hg_atomic_int32_t *ptr, 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 true if swapped or false
+ */
+static HG_UTIL_INLINE bool hg_atomic_cas32(hg_atomic_int32_t *ptr, int32_t compare_value, 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, 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, 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 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 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 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 int64_t hg_atomic_or64(hg_atomic_int64_t *ptr, 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 int64_t hg_atomic_xor64(hg_atomic_int64_t *ptr, 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 int64_t hg_atomic_and64(hg_atomic_int64_t *ptr, 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 true if swapped or false
+ */
+static HG_UTIL_INLINE bool hg_atomic_cas64(hg_atomic_int64_t *ptr, int64_t compare_value, 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, int32_t value)
+{
+#if defined(HG_UTIL_HAS_STDATOMIC_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, int32_t value)
+{
+#if defined(_WIN32)
+ ptr->value = value;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_store_explicit(ptr, value, memory_order_release);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+ __atomic_store_n(ptr, value, __ATOMIC_RELEASE);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int32_t
+hg_atomic_get32(hg_atomic_int32_t *ptr)
+{
+ int32_t ret;
+
+#if defined(_WIN32)
+ ret = ptr->value;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_load_explicit(ptr, memory_order_acquire);
+#elif defined(__APPLE__)
+ ret = ptr->value;
+#else
+ ret = __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int32_t
+hg_atomic_incr32(hg_atomic_int32_t *ptr)
+{
+ int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedIncrementNoFence(&ptr->value);
+#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
+ ret = __atomic_fetch_add(ptr, 1, __ATOMIC_ACQ_REL) + 1;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int32_t
+hg_atomic_decr32(hg_atomic_int32_t *ptr)
+{
+ int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedDecrementNoFence(&ptr->value);
+#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
+ ret = __atomic_fetch_sub(ptr, 1, __ATOMIC_ACQ_REL) - 1;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int32_t
+hg_atomic_or32(hg_atomic_int32_t *ptr, int32_t value)
+{
+ int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedOrNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_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
+ ret = __atomic_fetch_or(ptr, value, __ATOMIC_ACQ_REL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int32_t
+hg_atomic_xor32(hg_atomic_int32_t *ptr, int32_t value)
+{
+ int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedXorNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_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
+ ret = __atomic_fetch_xor(ptr, value, __ATOMIC_ACQ_REL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int32_t
+hg_atomic_and32(hg_atomic_int32_t *ptr, int32_t value)
+{
+ int32_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedAndNoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_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
+ ret = __atomic_fetch_and(ptr, value, __ATOMIC_ACQ_REL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE bool
+hg_atomic_cas32(hg_atomic_int32_t *ptr, int32_t compare_value, int32_t swap_value)
+{
+ bool ret;
+
+#if defined(_WIN32)
+ ret = (compare_value == InterlockedCompareExchangeNoFence(&ptr->value, swap_value, compare_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
+ ret = __atomic_compare_exchange_n(ptr, &compare_value, swap_value, false, __ATOMIC_ACQ_REL,
+ __ATOMIC_ACQUIRE);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_init64(hg_atomic_int64_t *ptr, int64_t value)
+{
+#if defined(HG_UTIL_HAS_STDATOMIC_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, int64_t value)
+{
+#if defined(_WIN32)
+ ptr->value = value;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_store_explicit(ptr, value, memory_order_release);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+ __atomic_store_n(ptr, value, __ATOMIC_RELEASE);
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int64_t
+hg_atomic_get64(hg_atomic_int64_t *ptr)
+{
+ int64_t ret;
+
+#if defined(_WIN32)
+ ret = ptr->value;
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_load_explicit(ptr, memory_order_acquire);
+#elif defined(__APPLE__)
+ ptr->value = value;
+#else
+ ret = __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int64_t
+hg_atomic_incr64(hg_atomic_int64_t *ptr)
+{
+ int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedIncrementNoFence64(&ptr->value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_add_explicit(ptr, (int64_t)1, memory_order_acq_rel) + 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicIncrement64(&ptr->value);
+#else
+ ret = __atomic_fetch_add(ptr, (int64_t)1, __ATOMIC_ACQ_REL) + 1;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int64_t
+hg_atomic_decr64(hg_atomic_int64_t *ptr)
+{
+ int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedDecrementNoFence64(&ptr->value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_sub_explicit(ptr, (int64_t)1, memory_order_acq_rel) - 1;
+#elif defined(__APPLE__)
+ ret = OSAtomicDecrement64(&ptr->value);
+#else
+ ret = __atomic_fetch_sub(ptr, (int64_t)1, __ATOMIC_ACQ_REL) - 1;
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int64_t
+hg_atomic_or64(hg_atomic_int64_t *ptr, int64_t value)
+{
+ int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedOr64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_or_explicit(ptr, value, memory_order_acq_rel);
+#else
+ ret = __atomic_fetch_or(ptr, value, __ATOMIC_ACQ_REL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int64_t
+hg_atomic_xor64(hg_atomic_int64_t *ptr, int64_t value)
+{
+ int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedXor64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_xor_explicit(ptr, value, memory_order_acq_rel);
+#else
+ ret = __atomic_fetch_xor(ptr, value, __ATOMIC_ACQ_REL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE int64_t
+hg_atomic_and64(hg_atomic_int64_t *ptr, int64_t value)
+{
+ int64_t ret;
+
+#if defined(_WIN32)
+ ret = InterlockedAnd64NoFence(&ptr->value, value);
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ ret = atomic_fetch_and_explicit(ptr, value, memory_order_acq_rel);
+#else
+ ret = __atomic_fetch_and(ptr, value, __ATOMIC_ACQ_REL);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE bool
+hg_atomic_cas64(hg_atomic_int64_t *ptr, int64_t compare_value, int64_t swap_value)
+{
+ bool ret;
+
+#if defined(_WIN32)
+ ret = (compare_value == InterlockedCompareExchangeNoFence64(&ptr->value, swap_value, compare_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
+ ret = __atomic_compare_exchange_n(ptr, &compare_value, swap_value, false, __ATOMIC_ACQ_REL,
+ __ATOMIC_ACQUIRE);
+#endif
+
+ return ret;
+}
+
+/*---------------------------------------------------------------------------*/
+static HG_UTIL_INLINE void
+hg_atomic_fence(void)
+{
+#if defined(_WIN32)
+ MemoryBarrier();
+#elif defined(HG_UTIL_HAS_STDATOMIC_H)
+ atomic_thread_fence(memory_order_acq_rel);
+#elif defined(__APPLE__)
+ OSMemoryBarrier();
+#else
+ __atomic_thread_fence(__ATOMIC_ACQ_REL);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MERCURY_ATOMIC_H */
diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h b/src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h
new file mode 100644
index 0000000..2406ba8
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_compiler_attributes.h
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MERCURY_COMPILER_ATTRIBUTES_H
+#define MERCURY_COMPILER_ATTRIBUTES_H
+
+/*************************************/
+/* Public Type and Struct Definition */
+/*************************************/
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/*
+ * __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
+ * In the meantime, to support gcc < 5, we implement __has_attribute
+ * by hand.
+ */
+#if !defined(__has_attribute) && defined(__GNUC__) && (__GNUC__ >= 4)
+#define __has_attribute(x) __GCC4_has_attribute_##x
+#define __GCC4_has_attribute___visibility__ 1
+#define __GCC4_has_attribute___warn_unused_result__ 1
+#define __GCC4_has_attribute___unused__ 1
+#define __GCC4_has_attribute___format__ 1
+#define __GCC4_has_attribute___fallthrough__ 0
+#endif
+
+/* Visibility of symbols */
+#if defined(_WIN32)
+#define HG_ATTR_ABI_IMPORT __declspec(dllimport)
+#define HG_ATTR_ABI_EXPORT __declspec(dllexport)
+#define HG_ATTR_ABI_HIDDEN
+#elif __has_attribute(__visibility__)
+#define HG_ATTR_ABI_IMPORT __attribute__((__visibility__("default")))
+#define HG_ATTR_ABI_EXPORT __attribute__((__visibility__("default")))
+#define HG_ATTR_ABI_HIDDEN __attribute__((__visibility__("hidden")))
+#else
+#define HG_ATTR_ABI_IMPORT
+#define HG_ATTR_ABI_EXPORT
+#define HG_ATTR_ABI_HIDDEN
+#endif
+
+/* Unused return values */
+#if defined(_WIN32)
+#define HG_ATTR_WARN_UNUSED_RESULT _Check_return_
+#elif __has_attribute(__warn_unused_result__)
+#define HG_ATTR_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+#else
+#define HG_ATTR_WARN_UNUSED_RESULT
+#endif
+
+/* Remove warnings when plugin does not use callback arguments */
+#if defined(_WIN32)
+#define HG_ATTR_UNUSED
+#elif __has_attribute(__unused__)
+#define HG_ATTR_UNUSED __attribute__((__unused__))
+#else
+#define HG_ATTR_UNUSED
+#endif
+
+/* Alignment (not optional) */
+#if defined(_WIN32)
+#define HG_ATTR_ALIGNED(x, a) __declspec(align(a)) x
+#else
+#define HG_ATTR_ALIGNED(x, a) x __attribute__((__aligned__(a)))
+#endif
+
+/* Packed (not optional) */
+#if defined(_WIN32)
+#define HG_ATTR_PACKED_PUSH __pragma(pack(push, 1))
+#define HG_ATTR_PACKED_POP __pragma(pack(pop))
+#else
+#define HG_ATTR_PACKED_PUSH
+#define HG_ATTR_PACKED_POP __attribute__((__packed__))
+#endif
+#define HG_ATTR_PACKED(x) HG_ATTR_PACKED_PUSH x HG_ATTR_PACKED_POP
+
+/* Check format arguments */
+#if defined(_WIN32)
+#define HG_ATTR_PRINTF(_fmt, _firstarg)
+#elif __has_attribute(__format__)
+#define HG_ATTR_PRINTF(_fmt, _firstarg) __attribute__((__format__(printf, _fmt, _firstarg)))
+#else
+#define HG_ATTR_PRINTF(_fmt, _firstarg)
+#endif
+
+/* Constructor (not optional) */
+#if defined(_WIN32)
+#define HG_ATTR_CONSTRUCTOR
+#define HG_ATTR_CONSTRUCTOR_PRIORITY(x)
+#else
+#define HG_ATTR_CONSTRUCTOR __attribute__((__constructor__))
+#define HG_ATTR_CONSTRUCTOR_PRIORITY(x) __attribute__((__constructor__(x)))
+#endif
+
+/* Destructor (not optional) */
+#if defined(_WIN32)
+#define HG_ATTR_DESTRUCTOR
+#else
+#define HG_ATTR_DESTRUCTOR __attribute__((__destructor__))
+#endif
+
+/* Fallthrough (prevent icc from throwing warnings) */
+#if defined(_WIN32) /* clang-format off */
+# define HG_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */ /* clang-format on */
+#elif __has_attribute(__fallthrough__) && !defined(__INTEL_COMPILER)
+#define HG_ATTR_FALLTHROUGH __attribute__((__fallthrough__))
+#else /* clang-format off */
+# define HG_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
+#endif /* clang-format on */
+
+#endif /* MERCURY_COMPILER_ATTRIBUTES_H */
diff --git a/src/H5FDsubfiling/mercury/src/util/mercury_dlog.c b/src/H5FDsubfiling/mercury/src/util/mercury_dlog.c
new file mode 100644
index 0000000..7dd5104
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_dlog.c
@@ -0,0 +1,308 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "mercury_dlog.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <process.h>
+#else
+#include <unistd.h>
+#endif
+
+/****************/
+/* 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_counters(struct hg_dlog *d, int (*log_func)(FILE *, const char *, ...), FILE *stream,
+ int trylock)
+{
+ 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 (!HG_LIST_IS_EMPTY(&d->cnts32) || !HG_LIST_IS_EMPTY(&d->cnts64)) {
+ log_func(stream,
+ "### ----------------------\n"
+ "### (%s) counter log summary\n"
+ "### ----------------------\n",
+ (d->dlog_magic + strlen(HG_DLOG_STDMAGIC)));
+
+ 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");
+ }
+
+ hg_thread_mutex_unlock(&d->dlock);
+}
+
+/*---------------------------------------------------------------------------*/
+void
+hg_dlog_dump_file(struct hg_dlog *d, const char *base, int addpid, int trylock)
+{
+ char buf[2048];
+ int pid;
+ FILE * fp = NULL;
+ unsigned int left, idx;
+ struct hg_dlog_dcount32 *dc32;
+ struct hg_dlog_dcount64 *dc64;
+
+#ifdef _WIN32
+ pid = _getpid();
+#else
+ pid = getpid();
+#endif
+
+ 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/H5FDsubfiling/mercury/src/util/mercury_dlog.h b/src/H5FDsubfiling/mercury/src/util/mercury_dlog.h
new file mode 100644
index 0000000..0027fde
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_dlog.h
@@ -0,0 +1,282 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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 counters 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_counters(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/H5FDsubfiling/mercury/src/util/mercury_list.h b/src/H5FDsubfiling/mercury/src/util/mercury_list.h
new file mode 100644
index 0000000..7b66c23
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_list.h
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* 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/H5FDsubfiling/mercury/src/util/mercury_log.c b/src/H5FDsubfiling/mercury/src/util/mercury_log.c
new file mode 100644
index 0000000..def1abe
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_log.c
@@ -0,0 +1,498 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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 HG_ATTR_CONSTRUCTOR_PRIORITY(101)
+#else
+#define HG_UTIL_CONSTRUCTOR_1
+#endif
+
+/* Destructor (used to finalize log outlets) */
+#define HG_UTIL_DESTRUCTOR HG_ATTR_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 hg_log_func_t hg_log_func_g = 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 bool hg_log_init_g = 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 && !(outlet->parent && outlet->parent->debug_log)) {
+ if (outlet->level >= HG_LOG_LEVEL_MIN_DEBUG) {
+ FILE *stream = hg_log_streams_g[outlet->level] ? hg_log_streams_g[outlet->level]
+ : *hg_log_std_streams_g[outlet->level];
+ hg_dlog_dump_counters(outlet->debug_log, hg_log_func_g, stream, 0);
+ }
+ 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 || strcasecmp("none", log_level) == 0)
+ 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(hg_log_func_t log_func)
+{
+ hg_log_func_g = log_func;
+}
+
+/*---------------------------------------------------------------------------*/
+hg_log_func_t
+hg_log_get_func(void)
+{
+ return hg_log_func_g;
+}
+
+/*---------------------------------------------------------------------------*/
+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 = 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/H5FDsubfiling/mercury/src/util/mercury_log.h b/src/H5FDsubfiling/mercury/src/util/mercury_log.h
new file mode 100644
index 0000000..a550d97
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_log.h
@@ -0,0 +1,333 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MERCURY_LOG_H
+#define MERCURY_LOG_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_dlog.h"
+#include "mercury_queue.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 HG_ATTR_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 (log_level == HG_LOG_LEVEL_DEBUG && 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 >= log_level) \
+ hg_log_write(&HG_LOG_OUTLET(name), log_level, __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } while (0)
+
+#define HG_LOG_WRITE_DEBUG_EXT(name, header, ...) \
+ do { \
+ if (HG_LOG_OUTLET(name).level == HG_LOG_LEVEL_DEBUG) { \
+ hg_log_func_t log_func = hg_log_get_func(); \
+ hg_log_write(&HG_LOG_OUTLET(name), HG_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __func__, header); \
+ log_func(hg_log_get_stream_debug(), __VA_ARGS__); \
+ log_func(hg_log_get_stream_debug(), "---\n"); \
+ } \
+ } 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 */
+};
+
+/* Log function */
+typedef int (*hg_log_func_t)(FILE *stream, const char *format, ...);
+
+/*********************/
+/* 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(hg_log_func_t log_func);
+
+/**
+ * Get the logging function.
+ *
+ * \return pointer pointer to function
+ */
+HG_UTIL_PUBLIC hg_log_func_t hg_log_get_func(void);
+
+/**
+ * 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(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/H5FDsubfiling/mercury/src/util/mercury_queue.h b/src/H5FDsubfiling/mercury/src/util/mercury_queue.h
new file mode 100644
index 0000000..07d977f
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_queue.h
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* 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/H5FDsubfiling/mercury/src/util/mercury_thread.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c
new file mode 100644
index 0000000..858434f
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.c
@@ -0,0 +1,162 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "mercury_thread.h"
+
+#if !defined(_WIN32) && !defined(__APPLE__)
+#include <sched.h>
+#endif
+
+/*---------------------------------------------------------------------------*/
+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
+ sched_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/H5FDsubfiling/mercury/src/util/mercury_thread.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h
new file mode 100644
index 0000000..185d997
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread.h
@@ -0,0 +1,225 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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
+#define _WINSOCKAPI_
+#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 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/H5FDsubfiling/mercury/src/util/mercury_thread_annotation.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_annotation.h
new file mode 100644
index 0000000..50056a1
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_annotation.h
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c
new file mode 100644
index 0000000..9eed4c1
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.c
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h
new file mode 100644
index 0000000..1435667
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_condition.h
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c
new file mode 100644
index 0000000..c60ca94
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.c
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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;
+
+#if defined(_WIN32)
+ ret = hg_thread_mutex_init(mutex);
+#elif defined(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/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h
new file mode 100644
index 0000000..61d74a3
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_mutex.h
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MERCURY_THREAD_MUTEX_H
+#define MERCURY_THREAD_MUTEX_H
+
+#include "mercury_util_config.h"
+
+#include "mercury_thread_annotation.h"
+
+#ifdef _WIN32
+#define _WINSOCKAPI_
+#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/H5FDsubfiling/mercury/src/util/mercury_thread_pool.c b/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.c
new file mode 100644
index 0000000..76248d1
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.c
@@ -0,0 +1,175 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h b/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h
new file mode 100644
index 0000000..b399f66
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_thread_pool.h
@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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/H5FDsubfiling/mercury/src/util/mercury_time.h b/src/H5FDsubfiling/mercury/src/util/mercury_time.h
new file mode 100644
index 0000000..ba82a8a
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_time.h
@@ -0,0 +1,500 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MERCURY_TIME_H
+#define MERCURY_TIME_H
+
+#include "mercury_util_config.h"
+
+#if defined(_WIN32)
+#define _WINSOCKAPI_
+#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 = (LONGLONG)t_usec;
+ tv->tv_sec = (long)(t.QuadPart / 1000000);
+ tv->tv_usec = (long)(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 + 999999) / 1000000));
+#else
+ return (unsigned int)(tv.tv_sec * 1000 + ((tv.tv_usec + 999) / 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/H5FDsubfiling/mercury/src/util/mercury_util.c b/src/H5FDsubfiling/mercury/src/util/mercury_util.c
new file mode 100644
index 0000000..b9c1101
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_util.c
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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_version_get(unsigned int *major, unsigned int *minor, unsigned int *patch)
+{
+ if (major)
+ *major = HG_UTIL_VERSION_MAJOR;
+ if (minor)
+ *minor = HG_UTIL_VERSION_MINOR;
+ if (patch)
+ *patch = HG_UTIL_VERSION_PATCH;
+}
+
+/*---------------------------------------------------------------------------*/
+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/H5FDsubfiling/mercury/src/util/mercury_util.h b/src/H5FDsubfiling/mercury/src/util/mercury_util.h
new file mode 100644
index 0000000..aad9a11
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_util.h
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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
+
+/**
+ * Get HG util version number.
+ *
+ * \param major [OUT] pointer to unsigned integer
+ * \param minor [OUT] pointer to unsigned integer
+ * \param patch [OUT] pointer to unsigned integer
+ */
+HG_UTIL_PUBLIC void HG_Util_version_get(unsigned int *major, unsigned int *minor, unsigned int *patch);
+
+/**
+ * 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/H5FDsubfiling/mercury/src/util/mercury_util_config.h b/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h
new file mode 100644
index 0000000..41972df
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* 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 */
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Reflects any major or incompatible public API changes */
+#define HG_UTIL_VERSION_MAJOR 3
+/* Reflects any minor backwards compatible API or functionality addition */
+#define HG_UTIL_VERSION_MINOR 0
+/* Reflects any backwards compatible bug fixes */
+#define HG_UTIL_VERSION_PATCH 0
+
+/* Return codes */
+#define HG_UTIL_SUCCESS 0
+#define HG_UTIL_FAIL -1
+
+#include <mercury_compiler_attributes.h>
+
+/* Inline macro */
+#ifdef _WIN32
+#define HG_UTIL_INLINE __inline
+#else
+#define HG_UTIL_INLINE __inline__
+#endif
+
+/* Alignment */
+#define HG_UTIL_ALIGNED(x, a) HG_ATTR_ALIGNED(x, a)
+
+/* Check format arguments */
+#define HG_UTIL_PRINTF(_fmt, _firstarg) HG_ATTR_PRINTF(_fmt, _firstarg)
+
+/* Shared libraries */
+/* #undef HG_UTIL_BUILD_SHARED_LIBS */
+#ifdef HG_UTIL_BUILD_SHARED_LIBS
+#ifdef mercury_util_EXPORTS
+#define HG_UTIL_PUBLIC HG_ATTR_ABI_EXPORT
+#else
+#define HG_UTIL_PUBLIC HG_ATTR_ABI_IMPORT
+#endif
+#define HG_UTIL_PRIVATE HG_ATTR_ABI_HIDDEN
+#else
+#define HG_UTIL_PUBLIC
+#define HG_UTIL_PRIVATE
+#endif
+
+/* 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 '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/param.h> */
+#define HG_UTIL_HAS_SYSPARAM_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/H5FDsubfiling/mercury/src/util/mercury_util_config.h.in b/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h.in
new file mode 100644
index 0000000..d20e0e6
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_util_config.h.in
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* 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 */
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/*****************/
+/* Public Macros */
+/*****************/
+
+/* Reflects any major or incompatible public API changes */
+#define HG_UTIL_VERSION_MAJOR @MERCURY_UTIL_VERSION_MAJOR@
+/* Reflects any minor backwards compatible API or functionality addition */
+#define HG_UTIL_VERSION_MINOR @MERCURY_UTIL_VERSION_MINOR@
+/* Reflects any backwards compatible bug fixes */
+#define HG_UTIL_VERSION_PATCH @MERCURY_UTIL_VERSION_PATCH@
+
+/* Return codes */
+#define HG_UTIL_SUCCESS 0
+#define HG_UTIL_FAIL -1
+
+#include <mercury_compiler_attributes.h>
+
+/* Inline macro */
+#ifdef _WIN32
+# define HG_UTIL_INLINE __inline
+#else
+# define HG_UTIL_INLINE __inline__
+#endif
+
+/* Alignment */
+#define HG_UTIL_ALIGNED(x, a) HG_ATTR_ALIGNED(x, a)
+
+/* Check format arguments */
+#define HG_UTIL_PRINTF(_fmt, _firstarg) HG_ATTR_PRINTF(_fmt, _firstarg)
+
+/* Shared libraries */
+#cmakedefine HG_UTIL_BUILD_SHARED_LIBS
+#ifdef HG_UTIL_BUILD_SHARED_LIBS
+# ifdef mercury_util_EXPORTS
+# define HG_UTIL_PUBLIC HG_ATTR_ABI_EXPORT
+# else
+# define HG_UTIL_PUBLIC HG_ATTR_ABI_IMPORT
+# endif
+# define HG_UTIL_PRIVATE HG_ATTR_ABI_HIDDEN
+#else
+# define HG_UTIL_PUBLIC
+# define HG_UTIL_PRIVATE
+#endif
+
+/* 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 '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/param.h> */
+#cmakedefine HG_UTIL_HAS_SYSPARAM_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/H5FDsubfiling/mercury/src/util/mercury_util_error.h b/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h
new file mode 100644
index 0000000..9004c5a
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/mercury_util_error.h
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#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/H5FDsubfiling/mercury/src/util/version.txt b/src/H5FDsubfiling/mercury/src/util/version.txt
new file mode 100644
index 0000000..4a36342
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/src/util/version.txt
@@ -0,0 +1 @@
+3.0.0
diff --git a/src/H5FDsubfiling/mercury/version.txt b/src/H5FDsubfiling/mercury/version.txt
new file mode 100644
index 0000000..676a2fb
--- /dev/null
+++ b/src/H5FDsubfiling/mercury/version.txt
@@ -0,0 +1 @@
+2.2.0rc6