summaryrefslogtreecommitdiffstats
path: root/src/H5FDsubfiling/mercury
diff options
context:
space:
mode:
authorjhendersonHDF <jhenderson@hdfgroup.org>2022-07-22 20:03:12 (GMT)
committerGitHub <noreply@github.com>2022-07-22 20:03:12 (GMT)
commit27bb358f7ab1d23f3f8ce081c6b4f1602033e4d7 (patch)
treee8a69bdfbc16f9acf073ddb3ebff586eccfca009 /src/H5FDsubfiling/mercury
parent32caa567a26680c5f98d0ea0cc989c45c89dc654 (diff)
downloadhdf5-27bb358f7ab1d23f3f8ce081c6b4f1602033e4d7.zip
hdf5-27bb358f7ab1d23f3f8ce081c6b4f1602033e4d7.tar.gz
hdf5-27bb358f7ab1d23f3f8ce081c6b4f1602033e4d7.tar.bz2
Subfiling VFD (#1883)
* Added support for vector I/O calls to the VFD layer, and associated test code. Note that this includes the optimization to allow shortened sizes and types arrays to allow more space efficient representations of vectors in which all entries are of the same size and/or type. See the Selection I/o RFC for further details. Tested serial and parallel, debug and production on Charis. serial and parallel debug only on Jelly. * ran code formatter quick serial build and test on jelly * Add H5FD_read_selection() and H5FD_write_selection(). Currently only translate to scalar calls. Fix const buf in H5FD_write_vector(). * Format source * Fix comments * Add selection I/O to chunk code, used when: not using chunk cache, no datatype conversion, no I/O filters, no page buffer, not using collective I/O. Requires global variable H5_use_selection_io_g be set to TRUE. Implemented selection to vector I/O transaltion at the file driver layer. * Fix formatting unrelated to previous change to stop github from complaining. * Add full API support for selection I/O. Add tests for this. * Implement selection I/O for contiguous datasets. Fix bug in selection I/O translation. Add const qualifiers to some internal selection I/O routines to maintain const-correctness while avoiding memcpys. * Added vector read / write support to the MPIO VFD, with associated test code (see testpar/t_vfd.c). Note that this implementation does NOT support vector entries of size greater than 2 GB. This must be repaired before release, but it should be good enough for correctness testing. As MPIO requires vector I/O requests to be sorted in increasing address order, also added a vector sort utility in H5FDint.c This function is tested in passing by the MPIO vector I/O extension. In passing, repaired a bug in size / type vector extension management in H5FD_read/write_vector() Tested parallel debug and production on charis and Jelly. * Ran source code formatter * Add support for independent parallel I/O with selection I/O. Add HDF5_USE_SELECTION_IO env var to control selection I/O (default off). * Implement parallel collective support for selection I/O. * Fix comments and run formatter. * Update selection IO branch with develop (#1215) Merged branch 'develop' into selection_io * Sync with develop (#1262) Updated the branch with develop changes. * Implement big I/O support for vector I/O requests in the MPIO file driver. * Free arrays in H5FD__mpio_read/write_vector() as soon as they're not needed, to cut down on memory usage during I/O. * Address comments from code review. Fix const warnings with H5S_SEL_ITER_INIT(). * Committing clang-format changes * Feature/subfiling (#1464) * Initial checkin of merged sub-filing VFD. Passes regression tests (debug/shared/paralle) on Jelly. However, bugs and many compiler warnings remain -- not suitable for merge to develop. * Minor mods to src/H5FDsubfile_mpi.c to address errors reported by autogen.sh * Code formatting run -- no test * Merged my subfiling code fixes into the new selection_io_branch * Forgot to add the FindMERCURY.cmake file. This will probably disappear soon * attempting to make a more reliable subfile file open which doesn't return errors. For some unknown reason, the regular posix open will occasionally fail to create a subfile. Some better error handling for file close has been added. * added NULL option for H5FD_subfiling_config_t in H5Pset_fapl_subfiling (#1034) * NULL option automatically stacks IOC VFD for subfiling and returns a valid fapl. * added doxygen subfiling APIs * Various fixes which allow the IOR benchmark to run correctly * Lots of updates including the packaging up of the mercury_util source files to enable easier builds for our Benchmarking * Interim checkin of selection_io_with_subfiling_vfd branch Moddified testpar/t_vfd.c to test the subfiling vfd with default configuration. Must update this code to run with a variety of configurations -- most particularly multiple IO concentrators, and stripe depth small enough to test the other IO concentrators. testpar/t_vfd.c exposed a large number of race condidtions -- symtoms included: 1) Crashes (usually seg faults) 2) Heap corruption 3) Stack corruption 4) Double frees of heap space 5) Hangs 6) Out of order execution of I/O requests / violations of POSIX semantics 7) Swapped write requests Items 1 - 4 turned out to be primarily caused by file close issues -- specifically, the main I/O concentrator thread and its pool of worker threads were not being shut down properly on file close. Addressing this issue in combination with some other minor fixes seems to have addressed these issues. Items 5 & 6 appear to have been caused by issue of I/O requests to the thread pool in an order that did not maintain POSIX semantics. A rewrite of the I/O request dispatch code appears to have solved these issues. Item 7 seems to have been caused by multiple write requests from a given rank being read by the wrong worker thread. Code to issue "unique" tags for each write request via the ACK message appears to have cleaned this up. Note that the code is still in poor condtition. A partial list of known defects includes: a) Race condiditon on file close that allows superblock writes to arrive at the I/O concentrator after it has been shutdown. This defect is most evident when testpar/t_subfiling_vfd is run with 8 ranks. b) No error reporting from I/O concentrators -- must design and implement this. For now, mostly just asserts, which suggests that it should be run in debug mode. c) Much commented out and/or un-used code. d) Code orgnaization e) Build system with bits of Mercury is awkward -- think of shifting to pthreads with our own thread pool code. f) Need to add native support for vector and selection I/O to the subfiling VFD. g) Need to review, and posibly rework configuration code. h) Need to store subfile configuration data in a superblock extension message, and add code to use this data on file open. i) Test code is inadequate -- expect more issues as it is extended. In particular, there is no unit test code for the I/O request dispatch code. While I think it is correct at present, we need test code to verify this. Similarly, we need to test with multiple I/O concentrators and much smaller stripe depth. My actual code changes were limited to: src/H5FDioc.c src/H5FDioc_threads.c src/H5FDsubfile_int.c src/H5FDsubfile_mpi.c src/H5FDsubfiling.c src/H5FDsubfiling.h src/H5FDsubfiling_priv.h testpar/t_subfiling_vfd.c testpar/t_vfd.c I'm not sure what is going on with the deletions in src/mercury/src/util. Tested parallel/debug on Charis and Jelly * subfiling with selection IO (#1219) Merged branch 'selection_io' into subfiling branch. * Subfile name fixes (#1250) * fixed subfiling naming convention, and added leading zero to rank names. * Merge branch 'selection_io' into selection_io_with_subfiling_vfd (#1265) * Added script to join subfiles into a single HDF5 file (#1350) * Modified H5FD__subfiling_query() to report that the sub-filing VFD supports MPI This exposed issues with truncate and get EOF in the sub-filing VFD. I believe I have addressed these issues (get EOF not as fully tested as it should be), howeer, it exposed race conditions resulting in hangs. As of this writing, I have not been able to chase these down. Note that the tests that expose these race conditions are in testpar/t_subfiling_vfd.c, and are currently skipped. Unskip these tests to reproduce the race conditions. tested (to the extent possible) debug/parallel on charis and jelly. * Committing clang-format changes * fixed H5MM_free Co-authored-by: mainzer <mainzer#hdfgroup.org> Co-authored-by: jrmainzer <72230804+jrmainzer@users.noreply.github.com> Co-authored-by: Richard Warren <Richard.Warren@hdfgroup.org> Co-authored-by: Richard.Warren <richard.warren@jelly.ad.hdfgroup.org> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * Move Subfiling VFD components into H5FDsubfiling source directory * Update Autotools build and add H5_HAVE_SUBFILING_VFD macro to H5pubconf.h * Tidy up CMake build of subfiling sources * Merge branch 'develop' into feature/subfiling (#1539) Merge branch 'develop' into feature/subfiling * Add VFD interface version field to Subfiling and IOC VFDs * Merge branch 'develop' into feature/subfiling (#1557) Merge branch 'develop' into feature/subfiling * Merge branch 'develop' into feature/subfiling (#1563) Merge branch 'develop' into feature/subfiling * Tidy up merge artifacts after rebase on develop * Fix incorrect variable in mirror VFD utils CMake * Ensure VFD values are always defined * Add subfiling to CMake VFD_LIST if built * Mark MPI I/O driver self-initialization global as static * Add Subfiling VFD to predefined VFDs for HDF5_DRIVER env. variable * Initial progress towards separating private vs. public subfiling code * include libgen.h in t_vfd tests for correct dirname/basename * Committing clang-format changes * removed mercury option, included subfiling header path (#1577) Added subfiling status to configure output, installed h5fuse.sh to build directory for use in future tests. * added check for stdatomic.h (#1578) * added check for stdatomic.h with subfiling * added H5_HAVE_SUBFILING_VFD for cmake * fix old-style-definition warning (#1582) * fix old-style-definition warning * added test for enable parallel with subfiling VFD (#1586) Fails if subfiling VFD is not used with parallel support. * Subfiling/IOC VFD fixes and tidying (#1619) * Rename CMake option for Subfiling VFD to be consistent with other VFDs * Miscellaneous Subfiling fixes Add error message for unset MPI communicator Support dynamic loading of subfiling VFD with default configuration * Temporary fix for subfile name issue * Added subfile checks (#1634) * added subfile checks * Feature/subfiling (#1655) * Subfiling/IOC VFD cleanup Fix misuse of MPI_COMM_WORLD in IOC VFD Propagate Subfiling FAPL MPI settings down to IOC FAPL in default configuration case Cleanup IOC VFD debugging code Change sprintf to snprintf in a few places * Major work on separating Subfiling and IOC VFDs from each other * Re-write async_completion func to not overuse stack * Replace usage of MPI_COMM_WORLD with file's actual MPI communicator * Refactor H5FDsubfile_mpi.c * Remove empty file H5FDsubfile_mpi.c * Separate IOC VFD errors to its own error stack * Committing clang-format changes * Remove H5TRACE macros from H5FDioc.c * Integrate H5FDioc_threads.c with IOC error stack * Fix for subfile name generation Use number of I/O concentrators from existing subfiling configuration file, if one exists * Add temporary barrier in "Get EOF" operation to prevent races on EOF Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * Fix for retrieval of machine Host ID * Default to MPI_COMM_WORLD if no MPI params set * added libs rt and pthreads (#1673) * added libs rt and pthreads * Feature/subfiling (#1689) * More tidying of IOC VFD and subfiling debug code * Remove old unused log file code * Clear FID from active file map on failure * Fix bug in generation of subfile names when truncating file * Change subfile names to start from 1 instead of 0 * Use long long for user-specified stripe size from environment variable * Skip 0-sized I/Os in low-level IOC I/O routines * Don't update EOF on read * Convert printed warning about data size mismatch to assertion * Don't add base file address to I/O addresses twice Base address should already be applied as part of H5FDwrite/read_vector calls * Account for 0-sized I/O vector entries in subfile write/read functions * Rewrite init_indep_io for clarity * Correction for IOC wraparound calculations * Some corrections to iovec calculations * Remove temporary barrier on EOF retrieval * Complete work request queue entry on error instead of skipping over * Account for stripe size wraparound for sf_col_offset calculation * Committing clang-format changes Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * Re-write and fix bugs in I/O vector filling routines (#1703) * Rewrite I/O vector filling routines for clarity * Fix bug with iovec_fill_last when last I/O size is 0 * added subfiling_dir line read (#1714) * added subfiling_dir line read and use it * shellcheck fixes * I/O request dispatch logic update (#1731) Short-circuit I/O request dispatch when head of I/O queue is an in-progress get EOF or truncate operation. This prevents an issue where a write operation can be dispatched alongside a get EOF/truncate operation, whereas all I/O requests are supposed to be ineligible for dispatch until the get EOF/truncate is completed * h5fuse.sh.in clean-up (#1757) * Added command-line options * Committing clang-format changes * Align with changes from develop * Mimic MPI I/O VFD for EOF handling * Initialize context_id field for work request objects * Use logfile for some debugging information * Use atomic store to set IOC ready flag * Use separate communicator for sending file EOF data Minor IOC cleanup * Use H5_subfile_fid_to_context to get context ID for file in Subfiling VFD * IOVEC calculation fixes * Updates for debugging code * Minor fixes for threaded code * Committing clang-format changes * Use separate MPI communicator for barrier operations * Committing clang-format changes * Rewrite EOF routine to use nonblocking MPI communication * Committing clang-format changes * Always dispatch I/O work requests in IOC main loop * Return distinct MPI communicator to library when requested * Minor warning cleanup * Committing clang-format changes * Generate h5fuse.sh from h5fuse.sh.in in CMake * Send truncate messages to correct IOC rank * Committing clang-format changes * Miscellaneous cleanup Post some MPI receives before sends Free some duplicated MPI communicator/Info objects Remove unnecessary extra MPI_Barrier * Warning cleanup * Fix for leaked MPI communicator * Retrieve file EOF on single rank and bcast it * Fixes for a few failure paths * Cleanup of IOC file opens * Committing clang-format changes * Use plan MPI_Send for send of EOF messages * Always check MPI thread support level during Subfiling init * Committing clang-format changes * Handle a hang on failure when IOCs can't open subfiles * Committing clang-format changes * Refactor file open status consensus check * Committing clang-format changes * Fix for MPI_Comm_free being called after MPI_Finalize * Fix VFD test by setting MPI params before setting subfiling on FAPL * Update Subfiling VFD error handling and error stack usage * Improvements for Subfiling logfiles * Remove prototypes for currently unused routines * Disable I/O queue stat collecting by default * Remove unused serialization mutex variable * Update VFD testing to take subfiling VFD into account * Fix usage of global subfiling application layout object * Minor fixes for failure pathways * Keep track of the number of failures in an IOC I/O queue * Make sure not to exceed MPI_TAG_UB value for data communication messages * Committing clang-format changes * Update for rename of some H5FD 'ctl' opcodes * Always include Subfiling's public header files in hdf5.h * Remove old unused code and comments * Implement support for per-file I/O queues Allows the subfiling VFD to have multiple HDF5 files open simultaneously * Use simple MPI_Iprobe over unnecessary MPI_Improbe * Committing clang-format changes * Update HDF5 testing to query driver for H5FD_FEAT_DEFAULT_VFD_COMPATIBLE flag * Fix a few bugs related to file multi-opens * Avoid calling MPI routines if subfiling gets reinitialized * Fix issue when files are closed in a random order * Update HDF5 testing to query VFD for "using MPI" feature flag * Register atexit handler in subfiling VFD to call MPI_Finalize after HDF5 closes * Fail for collective I/O requests until support is implemented * Correct VOL test function prototypes * Minor cleanup of old code and comments * Update mercury dependency * Cleanup of subfiling configuration structure * Committing clang-format changes * Build system updates for Subfiling VFD * Fix possible hang on failure in t_vfd tests caused by mismatched MPI_Barrier calls * Copy subfiling IOC fapl in "fapl get" method * Mirror subfiling superblock writes to stub file for legacy POSIX-y HDF5 applications * Allow collective I/O for MPI_BYTE types and rank 0 bcast strategy * Committing clang-format changes * Use different scheme for subfiling write message MPI tag calculations * Committing clang-format changes * Avoid performing fstat calls on all MPI ranks * Add MPI_Barrier before finalizing IOC threads * Use try_lock in I/O queue dispatch to minimize contention from worker threads * Use simple Waitall for nonblocking I/O waits * Add configurable IOC main thread delay and try_lock option to I/O queue dispatch * Fix bug that could cause serialization of non-overlapping I/O requests * Temporarily treat collective subfiling vector I/O calls as independent * Removed unused mercury bits * Add stubs for subfiling and IOC file delete callback * Update VFD testing for Subfiling VFD * Work around HDF5 metadata cache bug for Subfiling VFD when MPI Comm size = 1 * Committing clang-format changes Co-authored-by: mainzer <mainzer#hdfgroup.org> Co-authored-by: Neil Fortner <nfortne2@hdfgroup.org> Co-authored-by: Scot Breitenfeld <brtnfld@hdfgroup.org> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: jrmainzer <72230804+jrmainzer@users.noreply.github.com> Co-authored-by: Richard Warren <Richard.Warren@hdfgroup.org> Co-authored-by: Richard.Warren <richard.warren@jelly.ad.hdfgroup.org>
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