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