util.h raw

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