LCOV - code coverage report
Current view: top level - src/ipc/libmultiprocess/include/mp - util.h (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 80.3 % 61 49
Test Date: 2026-03-16 05:20:51 Functions: 16.8 % 570 96
Branches: 5.2 % 2136 112

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #ifndef MP_UTIL_H
       6                 :             : #define MP_UTIL_H
       7                 :             : 
       8                 :             : #include <capnp/schema.h>
       9                 :             : #include <cassert>
      10                 :             : #include <cstddef>
      11                 :             : #include <cstring>
      12                 :             : #include <exception>
      13                 :             : #include <functional>
      14                 :             : #include <kj/string-tree.h>
      15                 :             : #include <mutex>
      16                 :             : #include <string>
      17                 :             : #include <tuple>
      18                 :             : #include <type_traits>
      19                 :             : #include <utility>
      20                 :             : #include <variant>
      21                 :             : #include <vector>
      22                 :             : 
      23                 :             : namespace mp {
      24                 :             : 
      25                 :             : //! Generic utility functions used by capnp code.
      26                 :             : 
      27                 :             : //! Type holding a list of types.
      28                 :             : //!
      29                 :             : //! Example:
      30                 :             : //!   TypeList<int, bool, void>
      31                 :             : template <typename... Types>
      32                 :             : struct TypeList
      33                 :             : {
      34                 :             :     static constexpr size_t size = sizeof...(Types);
      35                 :             : };
      36                 :             : 
      37                 :             : //! Construct a template class value by deducing template arguments from the
      38                 :             : //! types of constructor arguments, so they don't need to be specified manually.
      39                 :             : //!
      40                 :             : //! Uses of this can go away with class template deduction in C++17
      41                 :             : //! (https://en.cppreference.com/w/cpp/language/class_template_argument_deduction)
      42                 :             : //!
      43                 :             : //! Example:
      44                 :             : //!   Make<std::pair>(5, true) // Constructs std::pair<int, bool>(5, true);
      45                 :             : template <template <typename...> class Class, typename... Types, typename... Args>
      46                 :         185 : Class<Types..., std::remove_reference_t<Args>...> Make(Args&&... args)
      47                 :             : {
      48                 :         185 :     return Class<Types..., std::remove_reference_t<Args>...>{std::forward<Args>(args)...};
      49                 :             : }
      50                 :             : 
      51                 :             : //! Type helper splitting a TypeList into two halves at position index.
      52                 :             : //!
      53                 :             : //! Example:
      54                 :             : //!   is_same<TypeList<int, double>, Split<2, TypeList<int, double, float, bool>>::First>
      55                 :             : //!   is_same<TypeList<float, bool>, Split<2, TypeList<int, double, float, bool>>::Second>
      56                 :             : template <std::size_t index, typename List, typename _First = TypeList<>, bool done = index == 0>
      57                 :             : struct Split;
      58                 :             : 
      59                 :             : //! Specialization of above (base case)
      60                 :             : template <typename _Second, typename _First>
      61                 :             : struct Split<0, _Second, _First, true>
      62                 :             : {
      63                 :             :     using First = _First;
      64                 :             :     using Second = _Second;
      65                 :             : };
      66                 :             : 
      67                 :             : //! Specialization of above (recursive case)
      68                 :             : template <std::size_t index, typename Type, typename... _Second, typename... _First>
      69                 :             : struct Split<index, TypeList<Type, _Second...>, TypeList<_First...>, false>
      70                 :             : {
      71                 :             :     using _Next = Split<index - 1, TypeList<_Second...>, TypeList<_First..., Type>>;
      72                 :             :     using First = typename _Next::First;
      73                 :             :     using Second = typename _Next::Second;
      74                 :             : };
      75                 :             : 
      76                 :             : //! Type helper giving return type of a callable type.
      77                 :             : template <typename Callable>
      78                 :             : using ResultOf = decltype(std::declval<Callable>()());
      79                 :             : 
      80                 :             : //! Substitutue for std::remove_cvref_t
      81                 :             : template <typename T>
      82                 :             : using RemoveCvRef = std::remove_cv_t<std::remove_reference_t<T>>;
      83                 :             : 
      84                 :             : //! Type helper abbreviating std::decay.
      85                 :             : template <typename T>
      86                 :             : using Decay = std::decay_t<T>;
      87                 :             : 
      88                 :             : //! SFINAE helper, see using Require below.
      89                 :             : template <typename SfinaeExpr, typename Result_>
      90                 :             : struct _Require
      91                 :             : {
      92                 :             :     using Result = Result_;
      93                 :             : };
      94                 :             : 
      95                 :             : //! SFINAE helper, basically the same as to C++17's void_t, but allowing types other than void to be returned.
      96                 :             : template <typename SfinaeExpr, typename Result = void>
      97                 :             : using Require = typename _Require<SfinaeExpr, Result>::Result;
      98                 :             : 
      99                 :             : //! Function parameter type for prioritizing overloaded function calls that
     100                 :             : //! would otherwise be ambiguous.
     101                 :             : //!
     102                 :             : //! Example:
     103                 :             : //!   auto foo(Priority<1>) -> std::enable_if<>;
     104                 :             : //!   auto foo(Priority<0>) -> void;
     105                 :             : //!
     106                 :             : //!   foo(Priority<1>());   // Calls higher priority overload if enabled.
     107                 :             : template <int priority>
     108                 :             : struct Priority : Priority<priority - 1>
     109                 :             : {
     110                 :             : };
     111                 :             : 
     112                 :             : //! Specialization of above (base case)
     113                 :             : template <>
     114                 :             : struct Priority<0>
     115                 :             : {
     116                 :             : };
     117                 :             : 
     118                 :             : //! Return capnp type name with filename prefix removed.
     119                 :             : template <typename T>
     120                 :         120 : const char* TypeName()
     121                 :             : {
     122                 :             :     // DisplayName string looks like
     123                 :             :     // "interfaces/capnp/common.capnp:ChainNotifications.resendWalletTransactions$Results"
     124                 :             :     // This discards the part of the string before the first ':' character.
     125                 :             :     // Another alternative would be to use the displayNamePrefixLength field,
     126                 :             :     // but this discards everything before the last '.' character, throwing away
     127                 :             :     // the object name, which is useful.
     128         [ +  - ]:         120 :     const char* display_name = ::capnp::Schema::from<T>().getProto().getDisplayName().cStr();
     129                 :         120 :     const char* short_name = strchr(display_name, ':');
     130         [ +  - ]:         120 :     return short_name ? short_name + 1 : display_name;
     131                 :             : }
     132                 :             : 
     133                 :             : //! Convenient wrapper around std::variant<T*, T>
     134                 :             : template <typename T>
     135                 :         426 : struct PtrOrValue {
     136                 :             :     std::variant<T*, T> data;
     137                 :             : 
     138                 :             :     template <typename... Args>
     139   [ +  +  +  + ]:         426 :     PtrOrValue(T* ptr, Args&&... args) : data(ptr ? ptr : std::variant<T*, T>{std::in_place_type<T>, std::forward<Args>(args)...}) {}
     140                 :             : 
     141   [ +  +  -  + ]:         431 :     T& operator*() { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
     142   [ +  -  +  -  :         431 :     T* operator->() { return &**this; }
             +  -  +  - ]
     143                 :             :     T& operator*() const { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
     144                 :             :     T* operator->() const { return &**this; }
     145                 :             : };
     146                 :             : 
     147                 :             : // Annotated mutex and lock class (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
     148                 :             : #if defined(__clang__) && (!defined(SWIG))
     149                 :             : #define MP_TSA(x)   __attribute__((x))
     150                 :             : #else
     151                 :             : #define MP_TSA(x)   // no-op
     152                 :             : #endif
     153                 :             : 
     154                 :             : #define MP_CAPABILITY(x)        MP_TSA(capability(x))
     155                 :             : #define MP_SCOPED_CAPABILITY    MP_TSA(scoped_lockable)
     156                 :             : #define MP_REQUIRES(x)          MP_TSA(requires_capability(x))
     157                 :             : #define MP_ACQUIRE(...)         MP_TSA(acquire_capability(__VA_ARGS__))
     158                 :             : #define MP_RELEASE(...)         MP_TSA(release_capability(__VA_ARGS__))
     159                 :             : #define MP_ASSERT_CAPABILITY(x) MP_TSA(assert_capability(x))
     160                 :             : #define MP_GUARDED_BY(x)        MP_TSA(guarded_by(x))
     161                 :             : #define MP_NO_TSA               MP_TSA(no_thread_safety_analysis)
     162                 :             : 
     163                 :          10 : class MP_CAPABILITY("mutex") Mutex {
     164                 :             : public:
     165                 :             :     void lock() MP_ACQUIRE() { m_mutex.lock(); }
     166                 :             :     void unlock() MP_RELEASE() { m_mutex.unlock(); }
     167                 :             : 
     168                 :             :     std::mutex m_mutex;
     169                 :             : };
     170                 :             : 
     171                 :             : class MP_SCOPED_CAPABILITY Lock {
     172                 :             : public:
     173   [ +  -  +  -  :         774 :     explicit Lock(Mutex& m) MP_ACQUIRE(m) : m_lock(m.m_mutex) {}
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  -  
          +  -  +  -  +  
          -  #  #  #  #  
             #  #  #  # ]
           [ -  -  -  -  
          -  -  -  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ +  -  +  -  
          -  -  +  -  +  
          -  +  -  -  +  
          +  -  +  +  +  
          -  +  -  -  +  
          +  -  +  -  +  
           - ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     174   [ +  -  -  -  :        1453 :     ~Lock() MP_RELEASE() = default;
          -  -  +  -  -  
          -  +  -  -  -  
          -  -  +  -  -  
          -  +  -  -  -  
          -  -  +  -  -  
          -  +  -  -  -  
          -  -  +  -  -  
          -  +  -  -  -  
          -  -  +  -  -  
          -  +  -  -  -  
          -  -  +  -  -  
          -  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  -  
          -  -  -  -  +  
          -  -  -  +  -  
          -  -  -  -  +  
          -  -  -  #  #  
           #  # ][ +  -  
          -  -  +  -  -  
          -  +  -  +  -  
          -  +  -  -  +  
          -  +  -  -  +  
          -  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  +  
          -  -  -  -  -  
          +  -  -  -  +  
          -  -  -  -  -  
          +  -  -  -  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           # ][ +  +  +  
          -  -  -  +  -  
          +  -  -  -  -  
          -  +  -  +  +  
          -  -  +  -  +  
          -  -  -  +  -  
          -  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  -  -  -  -  
          +  -  -  -  +  
          -  +  -  -  -  
             +  -  -  - ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  #  # ][ #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     175         [ +  - ]:         144 :     void unlock() MP_RELEASE() { m_lock.unlock(); }
     176         [ +  - ]:         143 :     void lock() MP_ACQUIRE() { m_lock.lock(); }
     177                 :         426 :     void assert_locked(Mutex& mutex) MP_ASSERT_CAPABILITY() MP_ASSERT_CAPABILITY(mutex)
     178                 :             :     {
     179         [ -  + ]:         426 :         assert(m_lock.mutex() == &mutex.m_mutex);
     180         [ -  + ]:         426 :         assert(m_lock);
     181                 :         426 :     }
     182                 :             : 
     183                 :             :     std::unique_lock<std::mutex> m_lock;
     184                 :             : };
     185                 :             : 
     186                 :             : template<typename T>
     187                 :             : struct GuardedRef
     188                 :             : {
     189                 :             :     Mutex& mutex;
     190                 :             :     T& ref MP_GUARDED_BY(mutex);
     191                 :             : };
     192                 :             : 
     193                 :             : // CTAD for Clang 16: GuardedRef{mutex, x} -> GuardedRef<decltype(x)>
     194                 :             : template <class U>
     195                 :             : GuardedRef(Mutex&, U&) -> GuardedRef<U>;
     196                 :             : 
     197                 :             : //! Analog to std::lock_guard that unlocks instead of locks.
     198                 :             : template <typename Lock>
     199                 :             : struct UnlockGuard
     200                 :             : {
     201                 :         566 :     UnlockGuard(Lock& lock) : m_lock(lock) { m_lock.unlock(); }
     202                 :         142 :     ~UnlockGuard() { m_lock.lock(); }
     203                 :             :     Lock& m_lock;
     204                 :             : };
     205                 :             : 
     206                 :             : template <typename Lock, typename Callback>
     207                 :         283 : void Unlock(Lock& lock, Callback&& callback)
     208                 :             : {
     209         [ +  - ]:         283 :     const UnlockGuard<Lock> unlock(lock);
     210         [ +  - ]:         283 :     callback();
     211                 :         283 : }
     212                 :             : 
     213                 :             : //! Invoke a function and run a follow-up action before returning the original
     214                 :             : //! result.
     215                 :             : //!
     216                 :             : //! This can be used similarly to KJ_DEFER to run cleanup code, but works better
     217                 :             : //! if the cleanup function can throw because it avoids clang bug
     218                 :             : //! https://github.com/llvm/llvm-project/issues/12658 which skips calling
     219                 :             : //! destructors in that case and can lead to memory leaks. Also, if both
     220                 :             : //! functions throw, this lets one exception take precedence instead of
     221                 :             : //! terminating due to having two active exceptions.
     222                 :             : template <typename Fn, typename After>
     223                 :          24 : decltype(auto) TryFinally(Fn&& fn, After&& after)
     224                 :             : {
     225         [ +  - ]:          24 :     bool success{false};
     226                 :             :     using R = std::invoke_result_t<Fn>;
     227                 :             :     try {
     228                 :             :         if constexpr (std::is_void_v<R>) {
     229         [ #  # ]:           6 :             std::forward<Fn>(fn)();
     230                 :           6 :             success = true;
     231         [ +  - ]:           6 :             std::forward<After>(after)();
     232                 :           6 :             return;
     233                 :             :         } else {
     234         [ +  - ]:          18 :             decltype(auto) result = std::forward<Fn>(fn)();
     235                 :          18 :             success = true;
     236         [ +  - ]:          18 :             std::forward<After>(after)();
     237                 :          18 :             return result;
     238                 :           0 :         }
     239                 :           0 :     } catch (...) {
     240   [ -  -  -  - ]:           0 :         if (!success) std::forward<After>(after)();
     241                 :           0 :         throw;
     242                 :             :     }
     243                 :             : }
     244                 :             : 
     245                 :             : //! Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
     246                 :             : std::string ThreadName(const char* exe_name);
     247                 :             : 
     248                 :             : //! Escape binary string for use in log so it doesn't trigger unicode decode
     249                 :             : //! errors in python unit tests.
     250                 :             : std::string LogEscape(const kj::StringTree& string, size_t max_size);
     251                 :             : 
     252                 :             : //! Callback type used by SpawnProcess below.
     253                 :             : using FdToArgsFn = std::function<std::vector<std::string>(int fd)>;
     254                 :             : 
     255                 :             : //! Spawn a new process that communicates with the current process over a socket
     256                 :             : //! pair. Returns pid through an output argument, and file descriptor for the
     257                 :             : //! local side of the socket.
     258                 :             : //! The fd_to_args callback is invoked in the parent process before fork().
     259                 :             : //! It must not rely on child pid/state, and must return the command line
     260                 :             : //! arguments that should be used to execute the process. Embed the remote file
     261                 :             : //! descriptor number in whatever format the child process expects.
     262                 :             : int SpawnProcess(int& pid, FdToArgsFn&& fd_to_args);
     263                 :             : 
     264                 :             : //! Call execvp with vector args.
     265                 :             : //! Not safe to call in a post-fork child of a multi-threaded process.
     266                 :             : //! Currently only used by mpgen at build time.
     267                 :             : void ExecProcess(const std::vector<std::string>& args);
     268                 :             : 
     269                 :             : //! Wait for a process to exit and return its exit code.
     270                 :             : int WaitProcess(int pid);
     271                 :             : 
     272                 :             : inline char* CharCast(char* c) { return c; }
     273                 :             : inline char* CharCast(unsigned char* c) { return (char*)c; }
     274                 :             : inline const char* CharCast(const char* c) { return c; }
     275                 :             : inline const char* CharCast(const unsigned char* c) { return (const char*)c; }
     276                 :             : 
     277                 :             : //! Exception thrown from code executing an IPC call that is interrupted.
     278                 :             : struct InterruptException final : std::exception {
     279                 :           0 :     explicit InterruptException(std::string message) : m_message(std::move(message)) {}
     280   [ #  #  #  #  :           0 :     const char* what() const noexcept override { return m_message.c_str(); }
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
           [ #  #  #  # ]
           [ #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     281                 :             :     std::string m_message;
     282                 :             : };
     283                 :             : 
     284                 :             : class CancelProbe;
     285                 :             : 
     286                 :             : //! Helper class that detects when a promise is canceled. Used to detect
     287                 :             : //! canceled requests and prevent potential crashes on unclean disconnects.
     288                 :             : //!
     289                 :             : //! In the future, this could also be used to support a way for wrapped C++
     290                 :             : //! methods to detect cancellation (like approach #4 in
     291                 :             : //! https://github.com/bitcoin/bitcoin/issues/33575).
     292                 :          18 : class CancelMonitor
     293                 :             : {
     294                 :             : public:
     295                 :             :     inline ~CancelMonitor();
     296                 :             :     inline void promiseDestroyed(CancelProbe& probe);
     297                 :             : 
     298                 :             :     bool m_canceled{false};
     299                 :             :     std::function<void()> m_on_cancel;
     300                 :             :     CancelProbe* m_probe{nullptr};
     301                 :             : };
     302                 :             : 
     303                 :             : //! Helper object to attach to a promise and update a CancelMonitor.
     304                 :             : class CancelProbe
     305                 :             : {
     306                 :             : public:
     307                 :          18 :     CancelProbe(CancelMonitor& monitor) : m_monitor(&monitor)
     308                 :             :     {
     309         [ -  + ]:          18 :         assert(!monitor.m_probe);
     310                 :          18 :         monitor.m_probe = this;
     311                 :          18 :     }
     312                 :          18 :     ~CancelProbe()
     313                 :             :     {
     314         [ -  + ]:          18 :         if (m_monitor) m_monitor->promiseDestroyed(*this);
     315                 :          18 :     }
     316                 :             :     CancelMonitor* m_monitor;
     317                 :             : };
     318                 :             : 
     319                 :          18 : CancelMonitor::~CancelMonitor()
     320                 :             : {
     321         [ +  - ]:          18 :     if (m_probe) {
     322         [ -  + ]:          18 :         assert(m_probe->m_monitor == this);
     323                 :          18 :         m_probe->m_monitor = nullptr;
     324                 :          18 :         m_probe = nullptr;
     325                 :             :     }
     326                 :          18 : }
     327                 :             : 
     328                 :           0 : void CancelMonitor::promiseDestroyed(CancelProbe& probe)
     329                 :             : {
     330                 :             :     // If promise is being destroyed, assume the promise has been canceled. In
     331                 :             :     // theory this method could be called when a promise was fulfilled or
     332                 :             :     // rejected rather than canceled, but it's safe to assume that's not the
     333                 :             :     // case because the CancelMonitor class is meant to be used inside code
     334                 :             :     // fulfilling or rejecting the promise and destroyed before doing so.
     335         [ #  # ]:           0 :     assert(m_probe == &probe);
     336                 :           0 :     m_canceled = true;
     337         [ #  # ]:           0 :     if (m_on_cancel) m_on_cancel();
     338                 :           0 :     m_probe = nullptr;
     339                 :           0 : }
     340                 :             : } // namespace mp
     341                 :             : 
     342                 :             : #endif // MP_UTIL_H
        

Generated by: LCOV version 2.0-1