diff options
Diffstat (limited to 'src/H5FDsubfiling/mercury')
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 |