Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
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 <array>
9#include <capnp/schema.h>
10#include <cassert>
11#include <cstdlib>
12#include <cstring>
13#include <exception>
14#include <functional>
15#include <kj/async-io.h>
16#include <kj/memory.h>
17#include <kj/string-tree.h>
18#include <mutex>
19#include <string>
20#include <tuple>
21#include <typeinfo>
22#include <type_traits>
23#include <utility>
24#include <variant>
25#include <vector>
26
27#if __has_include(<cxxabi.h>)
28#include <cxxabi.h>
29#include <memory>
30#endif
31
32namespace mp {
33
35
36// std::cmp_less_equal/cmp_greater_equal only accept integer types (C++20 §[utility.intcmp]).
37// These wrappers fall back to regular comparison for floating-point types.
38template <typename A, typename B>
39constexpr bool safe_less_equal(A a, B b)
40{
41 if constexpr (std::is_floating_point_v<A> || std::is_floating_point_v<B>) return a <= b;
42 else return std::cmp_less_equal(a, b);
43}
44template <typename A, typename B>
45constexpr bool safe_greater_equal(A a, B b)
46{
47 if constexpr (std::is_floating_point_v<A> || std::is_floating_point_v<B>) return a >= b;
48 else return std::cmp_greater_equal(a, b);
49}
50
55template <typename... Types>
57{
58 static constexpr size_t size = sizeof...(Types);
59};
60
69template <template <typename...> class Class, typename... Types, typename... Args>
70Class<Types..., std::remove_reference_t<Args>...> Make(Args&&... args)
71{
72 return Class<Types..., std::remove_reference_t<Args>...>{std::forward<Args>(args)...};
73}
74
80template <std::size_t index, typename List, typename _First = TypeList<>, bool done = index == 0>
81struct Split;
82
84template <typename _Second, typename _First>
86{
87 using First = _First;
88 using Second = _Second;
89};
90
92template <std::size_t index, typename Type, typename... _Second, typename... _First>
93struct Split<index, TypeList<Type, _Second...>, TypeList<_First...>, false>
94{
95 using _Next = Split<index - 1, TypeList<_Second...>, TypeList<_First..., Type>>;
96 using First = typename _Next::First;
97 using Second = typename _Next::Second;
98};
99
101template <typename Callable>
102using ResultOf = decltype(std::declval<Callable>()());
103
105template <typename T>
106using RemoveCvRef = std::remove_cv_t<std::remove_reference_t<T>>;
107
109template <typename T>
110using Decay = std::decay_t<T>;
111
114template <typename T, typename U>
115concept FieldTypeIs = std::is_same_v<decltype(std::declval<T>().get()), U>;
116
119template <typename T>
120concept InterfaceField = requires { typename Decay<decltype(std::declval<T>().get())>::Calls; };
121
123template <typename SfinaeExpr, typename Result_>
125{
127};
128
130template <typename SfinaeExpr, typename Result = void>
132
141template <int priority>
142struct Priority : Priority<priority - 1>
143{
144};
145
147template <>
148struct Priority<0>
149{
150};
151
153template <typename T>
154const char* TypeName()
155{
156 // DisplayName string looks like
157 // "interfaces/capnp/common.capnp:ChainNotifications.resendWalletTransactions$Results"
158 // This discards the part of the string before the first ':' character.
159 // Another alternative would be to use the displayNamePrefixLength field,
160 // but this discards everything before the last '.' character, throwing away
161 // the object name, which is useful.
162 const char* display_name = ::capnp::Schema::from<T>().getProto().getDisplayName().cStr();
163 const char* short_name = strchr(display_name, ':');
164 return short_name ? short_name + 1 : display_name;
165}
166
168template <typename T>
170 std::variant<T*, T> data;
171
172 template <typename... Args>
173 PtrOrValue(T* ptr, Args&&... args) : data(std::in_place_type<T*>, ptr)
174 {
175 if (!ptr) data.template emplace<T>(std::forward<Args>(args)...);
176 }
177
178 T& operator*() { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
179 T* operator->() { return &**this; }
180 T& operator*() const { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
181 T* operator->() const { return &**this; }
182};
183
184// Annotated mutex and lock class (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
185#if defined(__clang__) && (!defined(SWIG))
186#define MP_TSA(x) __attribute__((x))
187#else
188#define MP_TSA(x) // no-op
189#endif
190
191#define MP_CAPABILITY(x) MP_TSA(capability(x))
192#define MP_SCOPED_CAPABILITY MP_TSA(scoped_lockable)
193#define MP_REQUIRES(x) MP_TSA(requires_capability(x))
194#define MP_ACQUIRE(...) MP_TSA(acquire_capability(__VA_ARGS__))
195#define MP_RELEASE(...) MP_TSA(release_capability(__VA_ARGS__))
196#define MP_ASSERT_CAPABILITY(x) MP_TSA(assert_capability(x))
197#define MP_GUARDED_BY(x) MP_TSA(guarded_by(x))
198#define MP_NO_TSA MP_TSA(no_thread_safety_analysis)
199
200class MP_CAPABILITY("mutex") Mutex {
201public:
202 void lock() MP_ACQUIRE() { m_mutex.lock(); }
203 void unlock() MP_RELEASE() { m_mutex.unlock(); }
204
205 std::mutex m_mutex;
206};
207
209public:
210 explicit Lock(Mutex& m) MP_ACQUIRE(m) : m_lock(m.m_mutex) {}
212 void unlock() MP_RELEASE() { m_lock.unlock(); }
213 void lock() MP_ACQUIRE() { m_lock.lock(); }
215 {
216 assert(m_lock.mutex() == &mutex.m_mutex);
217 assert(m_lock);
218 }
219
220 std::unique_lock<std::mutex> m_lock;
221};
222
223template<typename T>
229
230// CTAD for Clang 16: GuardedRef{mutex, x} -> GuardedRef<decltype(x)>
231template <class U>
233
235template <typename Lock>
237{
238 UnlockGuard(Lock& lock) : m_lock(lock) { m_lock.unlock(); }
241};
242
243template <typename Lock, typename Callback>
244void Unlock(Lock& lock, Callback&& callback)
245{
246 const UnlockGuard<Lock> unlock(lock);
247 callback();
248}
249
259template <typename Fn, typename After>
260decltype(auto) TryFinally(Fn&& fn, After&& after)
261{
262 bool success{false};
263 using R = std::invoke_result_t<Fn>;
264 try {
265 if constexpr (std::is_void_v<R>) {
266 std::forward<Fn>(fn)();
267 success = true;
268 std::forward<After>(after)();
269 return;
270 } else {
271 decltype(auto) result = std::forward<Fn>(fn)();
272 success = true;
273 std::forward<After>(after)();
274 return result;
275 }
276 } catch (...) {
277 if (!success) std::forward<After>(after)();
278 throw;
279 }
280}
281
283void SetOsThreadName(const char* name);
284
286std::string ThreadName(const char* exe_name);
287
290std::string LogEscape(const kj::StringTree& string, size_t max_size);
291
292using Stream = kj::Own<kj::AsyncIoStream>;
293
295using SocketId = int;
296inline constexpr SocketId SocketError{-1};
297
300using SpawnConnectInfo = std::string;
301
303using SpawnConnectInfoToArgsFn = std::function<std::vector<std::string>(const SpawnConnectInfo&)>;
304
309std::tuple<ProcessId, SocketId> SpawnProcess(SpawnConnectInfoToArgsFn&& connect_info_to_args);
310
314
317std::array<SocketId, 2> SocketPair();
318
321ProcessId StartProcess(const std::vector<std::string>& args);
322
325
326inline char* CharCast(char* c) { return c; }
327inline char* CharCast(unsigned char* c) { return (char*)c; }
328inline const char* CharCast(const char* c) { return c; }
329inline const char* CharCast(const unsigned char* c) { return (const char*)c; }
330
331#if __has_include(<cxxabi.h>) // GCC & Clang ─ use <cxxabi.h> to demangle
332inline std::string _demangle(const char* m)
333{
334 int status = 0;
335 std::unique_ptr<char, void(*)(void*)> p{
336 abi::__cxa_demangle(m, /*output_buffer=*/nullptr, /*length=*/nullptr, &status), std::free};
337 return (status == 0 && p) ? p.get() : m; // fall back on mangled if needed
338}
339#else // MSVC or other ─ no demangling available
340inline std::string _demangle(const char* m) { return m; }
341#endif
342
343template<class T>
344std::string CxxTypeName(const T& /*unused*/)
345{
346#ifdef __cpp_rtti
347 return _demangle(typeid(std::decay_t<T>).name());
348#else
349 return "<type information unavailable without rtti>";
350#endif
351}
352
354struct InterruptException final : std::exception {
355 explicit InterruptException(std::string message) : m_message(std::move(message)) {}
356 const char* what() const noexcept override { return m_message.c_str(); }
357 std::string m_message;
358};
359
360class CancelProbe;
361
369{
370public:
371 inline ~CancelMonitor();
372 inline void promiseDestroyed(CancelProbe& probe);
373
374 bool m_canceled{false};
375 std::function<void()> m_on_cancel;
377};
378
381{
382public:
384 {
385 assert(!monitor.m_probe);
386 monitor.m_probe = this;
387 }
389 {
391 }
393};
394
396{
397 if (m_probe) {
398 assert(m_probe->m_monitor == this);
399 m_probe->m_monitor = nullptr;
400 m_probe = nullptr;
401 }
402}
403
405{
406 // If promise is being destroyed, assume the promise has been canceled. In
407 // theory this method could be called when a promise was fulfilled or
408 // rejected rather than canceled, but it's safe to assume that's not the
409 // case because the CancelMonitor class is meant to be used inside code
410 // fulfilling or rejecting the promise and destroyed before doing so.
411 assert(m_probe == &probe);
412 m_canceled = true;
414 m_probe = nullptr;
415}
416} // namespace mp
417
418#endif // MP_UTIL_H
ArgsManager & args
Definition bitcoind.cpp:280
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition sync.h:100
Helper class that detects when a promise is canceled.
Definition util.h:369
void promiseDestroyed(CancelProbe &probe)
Definition util.h:404
bool m_canceled
Definition util.h:374
std::function< void()> m_on_cancel
Definition util.h:375
CancelProbe * m_probe
Definition util.h:376
Helper object to attach to a promise and update a CancelMonitor.
Definition util.h:381
CancelMonitor * m_monitor
Definition util.h:392
CancelProbe(CancelMonitor &monitor)
Definition util.h:383
void assert_locked(Mutex &mutex) MP_ASSERT_CAPABILITY() MP_ASSERT_CAPABILITY(mutex)
Definition util.h:214
void unlock() MP_RELEASE()
Definition util.h:212
Lock(Mutex &m) MP_ACQUIRE(m)
Definition util.h:210
~Lock() MP_RELEASE()=default
std::unique_lock< std::mutex > m_lock
Definition util.h:220
void lock() MP_ACQUIRE()
Definition util.h:213
Concept satisfied when T's .get() method returns exactly type U.
Definition util.h:115
Concept satisfied when T's .get() method returns a capnp interface type (i.e., a type that exposes a ...
Definition util.h:120
#define T(expected, seed, data)
#define MP_RELEASE(...)
Definition util.h:195
#define MP_SCOPED_CAPABILITY
Definition util.h:192
#define MP_ACQUIRE(...)
Definition util.h:194
#define MP_CAPABILITY(x)
Definition util.h:191
#define MP_ASSERT_CAPABILITY(x)
Definition util.h:196
Functions to serialize / deserialize common bitcoin types.
constexpr bool safe_less_equal(A a, B b)
Generic utility functions used by capnp code.
Definition util.h:39
void Unlock(Lock &lock, Callback &&callback)
Definition util.h:244
std::string CxxTypeName(const T &)
Definition util.h:344
const char * TypeName()
Return capnp type name with filename prefix removed.
Definition util.h:154
std::string _demangle(const char *m)
Definition util.h:340
decltype(auto) TryFinally(Fn &&fn, After &&after)
Invoke a function and run a follow-up action before returning the original result.
Definition util.h:260
int ProcessId
Definition util.h:294
void SetOsThreadName(const char *name)
Set the OS-level name of the current thread.
Definition util.cpp:180
ProcessId StartProcess(const std::vector< std::string > &args)
Start a process and return its process id.
Definition util.cpp:361
kj::Own< kj::AsyncIoStream > Stream
Definition util.h:292
SocketId StartSpawned(const SpawnConnectInfo &connect_info)
Initialize spawned child process using the SpawnConnectInfo string passed to it, returning a socket i...
Definition util.cpp:342
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
Definition util.cpp:197
typename _Require< SfinaeExpr, Result >::Result Require
SFINAE helper, basically the same as to C++17's void_t, but allowing types other than void to be retu...
Definition util.h:131
int WaitProcess(ProcessId pid)
Wait for a process to exit and return its exit code.
Definition util.cpp:371
int SocketId
Definition util.h:295
Class< Types..., std::remove_reference_t< Args >... > Make(Args &&... args)
Construct a template class value by deducing template arguments from the types of constructor argumen...
Definition util.h:70
constexpr bool safe_greater_equal(A a, B b)
Definition util.h:45
std::tuple< ProcessId, SocketId > SpawnProcess(SpawnConnectInfoToArgsFn &&connect_info_to_args)
Spawn a new process that communicates with the current process over a socket pair.
Definition util.cpp:252
std::decay_t< T > Decay
Type helper abbreviating std::decay.
Definition util.h:110
std::array< SocketId, 2 > SocketPair()
Create a socket pair that can be used to communicate within a process or between parent and child pro...
Definition util.cpp:352
std::remove_cv_t< std::remove_reference_t< T > > RemoveCvRef
Substitutue for std::remove_cvref_t.
Definition util.h:106
decltype(std::declval< Callable >()()) ResultOf
Type helper giving return type of a callable type.
Definition util.h:102
constexpr SocketId SocketError
Definition util.h:296
char * CharCast(char *c)
Definition util.h:326
std::string SpawnConnectInfo
Information about parent process passed to child process as a command-line argument.
Definition util.h:300
std::string LogEscape(const kj::StringTree &string, size_t max_size)
Escape binary string for use in log so it doesn't trigger unicode decode errors in python unit tests.
Definition util.cpp:228
std::function< std::vector< std::string >(const SpawnConnectInfo &)> SpawnConnectInfoToArgsFn
Callback type used by SpawnProcess below.
Definition util.h:303
const char * name
Definition rest.cpp:71
SFINAE helper, see using Require below.
Definition util.h:125
Result_ Result
Definition util.h:126
T &ref MP_GUARDED_BY(mutex)
Mutex & mutex
Definition util.h:226
Exception thrown from code executing an IPC call that is interrupted.
Definition util.h:354
const char * what() const noexcept override
Definition util.h:356
InterruptException(std::string message)
Definition util.h:355
std::string m_message
Definition util.h:357
Function parameter type for prioritizing overloaded function calls that would otherwise be ambiguous.
Definition util.h:143
Convenient wrapper around std::variant<T*, T>
Definition util.h:169
T & operator*()
Definition util.h:178
T * operator->() const
Definition util.h:181
std::variant< T *, T > data
Definition util.h:170
T & operator*() const
Definition util.h:180
T * operator->()
Definition util.h:179
PtrOrValue(T *ptr, Args &&... args)
Definition util.h:173
Type helper splitting a TypeList into two halves at position index.
Definition util.h:81
Type holding a list of types.
Definition util.h:57
static constexpr size_t size
Definition util.h:58
Analog to std::lock_guard that unlocks instead of locks.
Definition util.h:237
UnlockGuard(Lock &lock)
Definition util.h:238
Lock & m_lock
Definition util.h:240
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
#define B
assert(!tx.IsCoinBase())