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 <functional>
13 : : #include <kj/string-tree.h>
14 : : #include <mutex>
15 : : #include <string>
16 : : #include <tuple>
17 : : #include <type_traits>
18 : : #include <utility>
19 : : #include <variant>
20 : : #include <vector>
21 : :
22 : : namespace mp {
23 : :
24 : : //! Generic utility functions used by capnp code.
25 : :
26 : : //! Type holding a list of types.
27 : : //!
28 : : //! Example:
29 : : //! TypeList<int, bool, void>
30 : : template <typename... Types>
31 : : struct TypeList
32 : : {
33 : : static constexpr size_t size = sizeof...(Types);
34 : : };
35 : :
36 : : //! Construct a template class value by deducing template arguments from the
37 : : //! types of constructor arguments, so they don't need to be specified manually.
38 : : //!
39 : : //! Uses of this can go away with class template deduction in C++17
40 : : //! (https://en.cppreference.com/w/cpp/language/class_template_argument_deduction)
41 : : //!
42 : : //! Example:
43 : : //! Make<std::pair>(5, true) // Constructs std::pair<int, bool>(5, true);
44 : : template <template <typename...> class Class, typename... Types, typename... Args>
45 : 185 : Class<Types..., std::remove_reference_t<Args>...> Make(Args&&... args)
46 : : {
47 : 185 : return Class<Types..., std::remove_reference_t<Args>...>{std::forward<Args>(args)...};
48 : : }
49 : :
50 : : //! Type helper splitting a TypeList into two halves at position index.
51 : : //!
52 : : //! Example:
53 : : //! is_same<TypeList<int, double>, Split<2, TypeList<int, double, float, bool>>::First>
54 : : //! is_same<TypeList<float, bool>, Split<2, TypeList<int, double, float, bool>>::Second>
55 : : template <std::size_t index, typename List, typename _First = TypeList<>, bool done = index == 0>
56 : : struct Split;
57 : :
58 : : //! Specialization of above (base case)
59 : : template <typename _Second, typename _First>
60 : : struct Split<0, _Second, _First, true>
61 : : {
62 : : using First = _First;
63 : : using Second = _Second;
64 : : };
65 : :
66 : : //! Specialization of above (recursive case)
67 : : template <std::size_t index, typename Type, typename... _Second, typename... _First>
68 : : struct Split<index, TypeList<Type, _Second...>, TypeList<_First...>, false>
69 : : {
70 : : using _Next = Split<index - 1, TypeList<_Second...>, TypeList<_First..., Type>>;
71 : : using First = typename _Next::First;
72 : : using Second = typename _Next::Second;
73 : : };
74 : :
75 : : //! Type helper giving return type of a callable type.
76 : : template <typename Callable>
77 : : using ResultOf = decltype(std::declval<Callable>()());
78 : :
79 : : //! Substitutue for std::remove_cvref_t
80 : : template <typename T>
81 : : using RemoveCvRef = std::remove_cv_t<std::remove_reference_t<T>>;
82 : :
83 : : //! Type helper abbreviating std::decay.
84 : : template <typename T>
85 : : using Decay = std::decay_t<T>;
86 : :
87 : : //! SFINAE helper, see using Require below.
88 : : template <typename SfinaeExpr, typename Result_>
89 : : struct _Require
90 : : {
91 : : using Result = Result_;
92 : : };
93 : :
94 : : //! SFINAE helper, basically the same as to C++17's void_t, but allowing types other than void to be returned.
95 : : template <typename SfinaeExpr, typename Result = void>
96 : : using Require = typename _Require<SfinaeExpr, Result>::Result;
97 : :
98 : : //! Function parameter type for prioritizing overloaded function calls that
99 : : //! would otherwise be ambiguous.
100 : : //!
101 : : //! Example:
102 : : //! auto foo(Priority<1>) -> std::enable_if<>;
103 : : //! auto foo(Priority<0>) -> void;
104 : : //!
105 : : //! foo(Priority<1>()); // Calls higher priority overload if enabled.
106 : : template <int priority>
107 : : struct Priority : Priority<priority - 1>
108 : : {
109 : : };
110 : :
111 : : //! Specialization of above (base case)
112 : : template <>
113 : : struct Priority<0>
114 : : {
115 : : };
116 : :
117 : : //! Return capnp type name with filename prefix removed.
118 : : template <typename T>
119 : 120 : const char* TypeName()
120 : : {
121 : : // DisplayName string looks like
122 : : // "interfaces/capnp/common.capnp:ChainNotifications.resendWalletTransactions$Results"
123 : : // This discards the part of the string before the first ':' character.
124 : : // Another alternative would be to use the displayNamePrefixLength field,
125 : : // but this discards everything before the last '.' character, throwing away
126 : : // the object name, which is useful.
127 [ + - ]: 120 : const char* display_name = ::capnp::Schema::from<T>().getProto().getDisplayName().cStr();
128 : 120 : const char* short_name = strchr(display_name, ':');
129 [ + - ]: 120 : return short_name ? short_name + 1 : display_name;
130 : : }
131 : :
132 : : //! Convenient wrapper around std::variant<T*, T>
133 : : template <typename T>
134 : 330 : struct PtrOrValue {
135 : : std::variant<T*, T> data;
136 : :
137 : : template <typename... Args>
138 [ + + + + ]: 330 : PtrOrValue(T* ptr, Args&&... args) : data(ptr ? ptr : std::variant<T*, T>{std::in_place_type<T>, std::forward<Args>(args)...}) {}
139 : :
140 [ + + - + ]: 335 : T& operator*() { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
141 [ + - + - : 335 : T* operator->() { return &**this; }
+ - + - ]
142 : : T& operator*() const { return data.index() ? std::get<T>(data) : *std::get<T*>(data); }
143 : : T* operator->() const { return &**this; }
144 : : };
145 : :
146 : : // Annotated mutex and lock class (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
147 : : #if defined(__clang__) && (!defined(SWIG))
148 : : #define MP_TSA(x) __attribute__((x))
149 : : #else
150 : : #define MP_TSA(x) // no-op
151 : : #endif
152 : :
153 : : #define MP_CAPABILITY(x) MP_TSA(capability(x))
154 : : #define MP_SCOPED_CAPABILITY MP_TSA(scoped_lockable)
155 : : #define MP_REQUIRES(x) MP_TSA(requires_capability(x))
156 : : #define MP_ACQUIRE(...) MP_TSA(acquire_capability(__VA_ARGS__))
157 : : #define MP_RELEASE(...) MP_TSA(release_capability(__VA_ARGS__))
158 : : #define MP_ASSERT_CAPABILITY(x) MP_TSA(assert_capability(x))
159 : : #define MP_GUARDED_BY(x) MP_TSA(guarded_by(x))
160 : : #define MP_NO_TSA MP_TSA(no_thread_safety_analysis)
161 : :
162 : 3 : class MP_CAPABILITY("mutex") Mutex {
163 : : public:
164 : : void lock() MP_ACQUIRE() { m_mutex.lock(); }
165 : : void unlock() MP_RELEASE() { m_mutex.unlock(); }
166 : :
167 : : std::mutex m_mutex;
168 : : };
169 : :
170 : : class MP_SCOPED_CAPABILITY Lock {
171 : : public:
172 [ + - + - : 486 : explicit Lock(Mutex& m) MP_ACQUIRE(m) : m_lock(m.m_mutex) {}
- + + - +
+ + - + -
- + + - +
- + - ]
173 [ + + + - : 907 : ~Lock() MP_RELEASE() = default;
- - + - -
- + - + -
+ - + - +
- + - + -
- - - - +
- - - + -
+ - - - +
- - - ]
174 [ + - ]: 3 : void unlock() MP_RELEASE() { m_lock.unlock(); }
175 [ + - ]: 2 : void lock() MP_ACQUIRE() { m_lock.lock(); }
176 : 330 : void assert_locked(Mutex& mutex) MP_ASSERT_CAPABILITY() MP_ASSERT_CAPABILITY(mutex)
177 : : {
178 [ - + ]: 330 : assert(m_lock.mutex() == &mutex.m_mutex);
179 [ - + ]: 330 : assert(m_lock);
180 : 330 : }
181 : :
182 : : std::unique_lock<std::mutex> m_lock;
183 : : };
184 : :
185 : : //! Analog to std::lock_guard that unlocks instead of locks.
186 : : template <typename Lock>
187 : : struct UnlockGuard
188 : : {
189 : 404 : UnlockGuard(Lock& lock) : m_lock(lock) { m_lock.unlock(); }
190 : 106 : ~UnlockGuard() { m_lock.lock(); }
191 : : Lock& m_lock;
192 : : };
193 : :
194 : : template <typename Lock, typename Callback>
195 : 211 : void Unlock(Lock& lock, Callback&& callback)
196 : : {
197 [ + - ]: 211 : const UnlockGuard<Lock> unlock(lock);
198 [ + - ]: 211 : callback();
199 : 211 : }
200 : :
201 : : //! Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
202 : : std::string ThreadName(const char* exe_name);
203 : :
204 : : //! Escape binary string for use in log so it doesn't trigger unicode decode
205 : : //! errors in python unit tests.
206 : : std::string LogEscape(const kj::StringTree& string);
207 : :
208 : : //! Callback type used by SpawnProcess below.
209 : : using FdToArgsFn = std::function<std::vector<std::string>(int fd)>;
210 : :
211 : : //! Spawn a new process that communicates with the current process over a socket
212 : : //! pair. Returns pid through an output argument, and file descriptor for the
213 : : //! local side of the socket. Invokes fd_to_args callback with the remote file
214 : : //! descriptor number which returns the command line arguments that should be
215 : : //! used to execute the process, and which should have the remote file
216 : : //! descriptor embedded in whatever format the child process expects.
217 : : int SpawnProcess(int& pid, FdToArgsFn&& fd_to_args);
218 : :
219 : : //! Call execvp with vector args.
220 : : void ExecProcess(const std::vector<std::string>& args);
221 : :
222 : : //! Wait for a process to exit and return its exit code.
223 : : int WaitProcess(int pid);
224 : :
225 : : inline char* CharCast(char* c) { return c; }
226 : : inline char* CharCast(unsigned char* c) { return (char*)c; }
227 : : inline const char* CharCast(const char* c) { return c; }
228 : : inline const char* CharCast(const unsigned char* c) { return (const char*)c; }
229 : :
230 : : } // namespace mp
231 : :
232 : : #endif // MP_UTIL_H
|