/workdir/bitcoin/src/sync.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-2022 The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #ifndef BITCOIN_SYNC_H |
7 | | #define BITCOIN_SYNC_H |
8 | | |
9 | | #ifdef DEBUG_LOCKCONTENTION |
10 | | #include <logging.h> |
11 | | #include <logging/timer.h> |
12 | | #endif |
13 | | |
14 | | #include <threadsafety.h> // IWYU pragma: export |
15 | | #include <util/macros.h> |
16 | | |
17 | | #include <condition_variable> |
18 | | #include <mutex> |
19 | | #include <string> |
20 | | #include <thread> |
21 | | |
22 | | //////////////////////////////////////////////// |
23 | | // // |
24 | | // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE // |
25 | | // // |
26 | | //////////////////////////////////////////////// |
27 | | |
28 | | /* |
29 | | RecursiveMutex mutex; |
30 | | std::recursive_mutex mutex; |
31 | | |
32 | | LOCK(mutex); |
33 | | std::unique_lock<std::recursive_mutex> criticalblock(mutex); |
34 | | |
35 | | LOCK2(mutex1, mutex2); |
36 | | std::unique_lock<std::recursive_mutex> criticalblock1(mutex1); |
37 | | std::unique_lock<std::recursive_mutex> criticalblock2(mutex2); |
38 | | |
39 | | TRY_LOCK(mutex, name); |
40 | | std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t); |
41 | | |
42 | | ENTER_CRITICAL_SECTION(mutex); // no RAII |
43 | | mutex.lock(); |
44 | | |
45 | | LEAVE_CRITICAL_SECTION(mutex); // no RAII |
46 | | mutex.unlock(); |
47 | | */ |
48 | | |
49 | | /////////////////////////////// |
50 | | // // |
51 | | // THE ACTUAL IMPLEMENTATION // |
52 | | // // |
53 | | /////////////////////////////// |
54 | | |
55 | | #ifdef DEBUG_LOCKORDER |
56 | | template <typename MutexType> |
57 | | void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false); |
58 | | void LeaveCritical(); |
59 | | void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line); |
60 | | template <typename MutexType> |
61 | | void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs); |
62 | | template <typename MutexType> |
63 | | void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs); |
64 | | void DeleteLock(void* cs); |
65 | | bool LockStackEmpty(); |
66 | | |
67 | | /** |
68 | | * Call abort() if a potential lock order deadlock bug is detected, instead of |
69 | | * just logging information and throwing a logic_error. Defaults to true, and |
70 | | * set to false in DEBUG_LOCKORDER unit tests. |
71 | | */ |
72 | | extern bool g_debug_lockorder_abort; |
73 | | #else |
74 | | template <typename MutexType> |
75 | 717k | inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {} void EnterCritical<std::recursive_mutex>(char const*, char const*, int, std::recursive_mutex*, bool) Line | Count | Source | 75 | 211k | inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {} |
void EnterCritical<std::mutex>(char const*, char const*, int, std::mutex*, bool) Line | Count | Source | 75 | 505k | inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {} |
Unexecuted instantiation: void EnterCritical<AnnotatedMixin<std::mutex> >(char const*, char const*, int, AnnotatedMixin<std::mutex>*, bool) Unexecuted instantiation: void EnterCritical<AnnotatedMixin<std::recursive_mutex> >(char const*, char const*, int, AnnotatedMixin<std::recursive_mutex>*, bool) |
76 | 717k | inline void LeaveCritical() {} |
77 | 290 | inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {} |
78 | | template <typename MutexType> |
79 | 291k | inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {} void AssertLockHeldInternal<AnnotatedMixin<std::recursive_mutex> >(char const*, char const*, int, AnnotatedMixin<std::recursive_mutex>*) Line | Count | Source | 79 | 137k | inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {} |
void AssertLockHeldInternal<AnnotatedMixin<std::mutex> >(char const*, char const*, int, AnnotatedMixin<std::mutex>*) Line | Count | Source | 79 | 154k | inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {} |
|
80 | | template <typename MutexType> |
81 | 261k | void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {} void AssertLockNotHeldInternal<AnnotatedMixin<std::mutex> >(char const*, char const*, int, AnnotatedMixin<std::mutex>*) Line | Count | Source | 81 | 252k | void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {} |
void AssertLockNotHeldInternal<AnnotatedMixin<std::recursive_mutex> >(char const*, char const*, int, AnnotatedMixin<std::recursive_mutex>*) Line | Count | Source | 81 | 8.72k | void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {} |
Unexecuted instantiation: void AssertLockNotHeldInternal<GlobalMutex>(char const*, char const*, int, GlobalMutex*) |
82 | 13.3k | inline void DeleteLock(void* cs) {} |
83 | 0 | inline bool LockStackEmpty() { return true; } |
84 | | #endif |
85 | | |
86 | | /** |
87 | | * Template mixin that adds -Wthread-safety locking annotations and lock order |
88 | | * checking to a subset of the mutex API. |
89 | | */ |
90 | | template <typename PARENT> |
91 | | class LOCKABLE AnnotatedMixin : public PARENT |
92 | | { |
93 | | public: |
94 | 13.3k | ~AnnotatedMixin() { |
95 | 13.3k | DeleteLock((void*)this); |
96 | 13.3k | } AnnotatedMixin<std::recursive_mutex>::~AnnotatedMixin() Line | Count | Source | 94 | 1.16k | ~AnnotatedMixin() { | 95 | 1.16k | DeleteLock((void*)this); | 96 | 1.16k | } |
AnnotatedMixin<std::mutex>::~AnnotatedMixin() Line | Count | Source | 94 | 12.2k | ~AnnotatedMixin() { | 95 | 12.2k | DeleteLock((void*)this); | 96 | 12.2k | } |
|
97 | | |
98 | | void lock() EXCLUSIVE_LOCK_FUNCTION() |
99 | 0 | { |
100 | 0 | PARENT::lock(); |
101 | 0 | } Unexecuted instantiation: AnnotatedMixin<std::mutex>::lock() Unexecuted instantiation: AnnotatedMixin<std::recursive_mutex>::lock() |
102 | | |
103 | | void unlock() UNLOCK_FUNCTION() |
104 | 0 | { |
105 | 0 | PARENT::unlock(); |
106 | 0 | } Unexecuted instantiation: AnnotatedMixin<std::mutex>::unlock() Unexecuted instantiation: AnnotatedMixin<std::recursive_mutex>::unlock() |
107 | | |
108 | | bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) |
109 | | { |
110 | | return PARENT::try_lock(); |
111 | | } |
112 | | |
113 | | using unique_lock = std::unique_lock<PARENT>; |
114 | | #ifdef __clang__ |
115 | | //! For negative capabilities in the Clang Thread Safety Analysis. |
116 | | //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction |
117 | | //! with the ! operator, to indicate that a mutex should not be held. |
118 | | const AnnotatedMixin& operator!() const { return *this; } |
119 | | #endif // __clang__ |
120 | | }; |
121 | | |
122 | | /** |
123 | | * Wrapped mutex: supports recursive locking, but no waiting |
124 | | * TODO: We should move away from using the recursive lock by default. |
125 | | */ |
126 | | using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>; |
127 | | |
128 | | /** Wrapped mutex: supports waiting but not recursive locking */ |
129 | | using Mutex = AnnotatedMixin<std::mutex>; |
130 | | |
131 | | /** Different type to mark Mutex at global scope |
132 | | * |
133 | | * Thread safety analysis can't handle negative assertions about mutexes |
134 | | * with global scope well, so mark them with a separate type, and |
135 | | * eventually move all the mutexes into classes so they are not globally |
136 | | * visible. |
137 | | * |
138 | | * See: https://github.com/bitcoin/bitcoin/pull/20272#issuecomment-720755781 |
139 | | */ |
140 | | class GlobalMutex : public Mutex { }; |
141 | | |
142 | 291k | #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) |
143 | | |
144 | 252k | inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); } |
145 | 8.72k | inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } |
146 | 0 | inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } |
147 | 261k | #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) |
148 | | |
149 | | /** Wrapper around std::unique_lock style lock for MutexType. */ |
150 | | template <typename MutexType> |
151 | | class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock |
152 | | { |
153 | | private: |
154 | | using Base = typename MutexType::unique_lock; |
155 | | |
156 | | void Enter(const char* pszName, const char* pszFile, int nLine) |
157 | 717k | { |
158 | 717k | EnterCritical(pszName, pszFile, nLine, Base::mutex()); |
159 | | #ifdef DEBUG_LOCKCONTENTION |
160 | | if (Base::try_lock()) return; |
161 | | LOG_TIME_MICROS_WITH_CATEGORY(strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK); |
162 | | #endif |
163 | 717k | Base::lock(); |
164 | 717k | } UniqueLock<AnnotatedMixin<std::recursive_mutex> >::Enter(char const*, char const*, int) Line | Count | Source | 157 | 211k | { | 158 | 211k | EnterCritical(pszName, pszFile, nLine, Base::mutex()); | 159 | | #ifdef DEBUG_LOCKCONTENTION | 160 | | if (Base::try_lock()) return; | 161 | | LOG_TIME_MICROS_WITH_CATEGORY(strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK); | 162 | | #endif | 163 | 211k | Base::lock(); | 164 | 211k | } |
UniqueLock<AnnotatedMixin<std::mutex> >::Enter(char const*, char const*, int) Line | Count | Source | 157 | 505k | { | 158 | 505k | EnterCritical(pszName, pszFile, nLine, Base::mutex()); | 159 | | #ifdef DEBUG_LOCKCONTENTION | 160 | | if (Base::try_lock()) return; | 161 | | LOG_TIME_MICROS_WITH_CATEGORY(strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK); | 162 | | #endif | 163 | 505k | Base::lock(); | 164 | 505k | } |
Unexecuted instantiation: UniqueLock<GlobalMutex>::Enter(char const*, char const*, int) |
165 | | |
166 | | bool TryEnter(const char* pszName, const char* pszFile, int nLine) |
167 | 0 | { |
168 | 0 | EnterCritical(pszName, pszFile, nLine, Base::mutex(), true); |
169 | 0 | if (Base::try_lock()) { Branch (169:13): [True: 0, False: 0]
Branch (169:13): [True: 0, False: 0]
Branch (169:13): [True: 0, False: 0]
|
170 | 0 | return true; |
171 | 0 | } |
172 | 0 | LeaveCritical(); |
173 | 0 | return false; |
174 | 0 | } Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::recursive_mutex> >::TryEnter(char const*, char const*, int) Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::mutex> >::TryEnter(char const*, char const*, int) Unexecuted instantiation: UniqueLock<GlobalMutex>::TryEnter(char const*, char const*, int) |
175 | | |
176 | | public: |
177 | 717k | UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) |
178 | 717k | { |
179 | 717k | if (fTry) Branch (179:13): [True: 0, False: 211k]
Branch (179:13): [True: 0, False: 505k]
Branch (179:13): [True: 0, False: 0]
|
180 | 0 | TryEnter(pszName, pszFile, nLine); |
181 | 717k | else |
182 | 717k | Enter(pszName, pszFile, nLine); |
183 | 717k | } UniqueLock<AnnotatedMixin<std::recursive_mutex> >::UniqueLock(AnnotatedMixin<std::recursive_mutex>&, char const*, char const*, int, bool) Line | Count | Source | 177 | 211k | UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) | 178 | 211k | { | 179 | 211k | if (fTry) Branch (179:13): [True: 0, False: 211k]
| 180 | 0 | TryEnter(pszName, pszFile, nLine); | 181 | 211k | else | 182 | 211k | Enter(pszName, pszFile, nLine); | 183 | 211k | } |
UniqueLock<AnnotatedMixin<std::mutex> >::UniqueLock(AnnotatedMixin<std::mutex>&, char const*, char const*, int, bool) Line | Count | Source | 177 | 505k | UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) | 178 | 505k | { | 179 | 505k | if (fTry) Branch (179:13): [True: 0, False: 505k]
| 180 | 0 | TryEnter(pszName, pszFile, nLine); | 181 | 505k | else | 182 | 505k | Enter(pszName, pszFile, nLine); | 183 | 505k | } |
Unexecuted instantiation: UniqueLock<GlobalMutex>::UniqueLock(GlobalMutex&, char const*, char const*, int, bool) |
184 | | |
185 | | UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) |
186 | 0 | { |
187 | 0 | if (!pmutexIn) return; Branch (187:13): [True: 0, False: 0]
|
188 | | |
189 | 0 | *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock); |
190 | 0 | if (fTry) Branch (190:13): [True: 0, False: 0]
|
191 | 0 | TryEnter(pszName, pszFile, nLine); |
192 | 0 | else |
193 | 0 | Enter(pszName, pszFile, nLine); |
194 | 0 | } |
195 | | |
196 | | ~UniqueLock() UNLOCK_FUNCTION() |
197 | 717k | { |
198 | 717k | if (Base::owns_lock()) Branch (198:13): [True: 211k, False: 0]
Branch (198:13): [True: 505k, False: 290]
Branch (198:13): [True: 0, False: 0]
|
199 | 717k | LeaveCritical(); |
200 | 717k | } UniqueLock<AnnotatedMixin<std::recursive_mutex> >::~UniqueLock() Line | Count | Source | 197 | 211k | { | 198 | 211k | if (Base::owns_lock()) Branch (198:13): [True: 211k, False: 0]
| 199 | 211k | LeaveCritical(); | 200 | 211k | } |
UniqueLock<AnnotatedMixin<std::mutex> >::~UniqueLock() Line | Count | Source | 197 | 505k | { | 198 | 505k | if (Base::owns_lock()) Branch (198:13): [True: 505k, False: 290]
| 199 | 505k | LeaveCritical(); | 200 | 505k | } |
Unexecuted instantiation: UniqueLock<GlobalMutex>::~UniqueLock() |
201 | | |
202 | | operator bool() |
203 | 0 | { |
204 | 0 | return Base::owns_lock(); |
205 | 0 | } Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::mutex> >::operator bool() Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::recursive_mutex> >::operator bool() |
206 | | |
207 | | protected: |
208 | | // needed for reverse_lock |
209 | 290 | UniqueLock() = default; Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::recursive_mutex> >::UniqueLock() UniqueLock<AnnotatedMixin<std::mutex> >::UniqueLock() Line | Count | Source | 209 | 290 | UniqueLock() = default; |
|
210 | | |
211 | | public: |
212 | | /** |
213 | | * An RAII-style reverse lock. Unlocks on construction and locks on destruction. |
214 | | */ |
215 | | class reverse_lock { |
216 | | public: |
217 | 290 | explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) { |
218 | 290 | CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line); |
219 | 290 | lock.unlock(); |
220 | 290 | LeaveCritical(); |
221 | 290 | lock.swap(templock); |
222 | 290 | } Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::recursive_mutex> >::reverse_lock::reverse_lock(UniqueLock<AnnotatedMixin<std::recursive_mutex> >&, char const*, char const*, int) UniqueLock<AnnotatedMixin<std::mutex> >::reverse_lock::reverse_lock(UniqueLock<AnnotatedMixin<std::mutex> >&, char const*, char const*, int) Line | Count | Source | 217 | 290 | explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) { | 218 | 290 | CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line); | 219 | 290 | lock.unlock(); | 220 | 290 | LeaveCritical(); | 221 | 290 | lock.swap(templock); | 222 | 290 | } |
|
223 | | |
224 | 290 | ~reverse_lock() { |
225 | 290 | templock.swap(lock); |
226 | 290 | EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex()); |
227 | 290 | lock.lock(); |
228 | 290 | } Unexecuted instantiation: UniqueLock<AnnotatedMixin<std::recursive_mutex> >::reverse_lock::~reverse_lock() UniqueLock<AnnotatedMixin<std::mutex> >::reverse_lock::~reverse_lock() Line | Count | Source | 224 | 290 | ~reverse_lock() { | 225 | 290 | templock.swap(lock); | 226 | 290 | EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex()); | 227 | 290 | lock.lock(); | 228 | 290 | } |
|
229 | | |
230 | | private: |
231 | | reverse_lock(reverse_lock const&); |
232 | | reverse_lock& operator=(reverse_lock const&); |
233 | | |
234 | | UniqueLock& lock; |
235 | | UniqueLock templock; |
236 | | std::string lockname; |
237 | | const std::string file; |
238 | | const int line; |
239 | | }; |
240 | | friend class reverse_lock; |
241 | | }; |
242 | | |
243 | 289 | #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__) |
244 | | |
245 | | // When locking a Mutex, require negative capability to ensure the lock |
246 | | // is not already held |
247 | 546k | inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; } |
248 | 0 | inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; } |
249 | | |
250 | | // When locking a GlobalMutex or RecursiveMutex, just check it is not |
251 | | // locked in the surrounding scope. |
252 | | template <typename MutexType> |
253 | 234k | inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } AnnotatedMixin<std::recursive_mutex>& MaybeCheckNotHeld<AnnotatedMixin<std::recursive_mutex> >(AnnotatedMixin<std::recursive_mutex>&) Line | Count | Source | 253 | 234k | inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } |
Unexecuted instantiation: GlobalMutex& MaybeCheckNotHeld<GlobalMutex>(GlobalMutex&) |
254 | | template <typename MutexType> |
255 | 0 | inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } |
256 | | |
257 | 682k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) |
258 | | #define LOCK2(cs1, cs2) \ |
259 | 13.5k | UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \ |
260 | 13.5k | UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__) |
261 | 0 | #define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true) |
262 | 6.84k | #define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) |
263 | | |
264 | | #define ENTER_CRITICAL_SECTION(cs) \ |
265 | 0 | { \ |
266 | 0 | EnterCritical(#cs, __FILE__, __LINE__, &cs); \ |
267 | 0 | (cs).lock(); \ |
268 | 0 | } |
269 | | |
270 | | #define LEAVE_CRITICAL_SECTION(cs) \ |
271 | 0 | { \ |
272 | 0 | std::string lockname; \ |
273 | 0 | CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \ |
274 | 0 | (cs).unlock(); \ |
275 | 0 | LeaveCritical(); \ |
276 | 0 | } |
277 | | |
278 | | //! Run code while locking a mutex. |
279 | | //! |
280 | | //! Examples: |
281 | | //! |
282 | | //! WITH_LOCK(cs, shared_val = shared_val + 1); |
283 | | //! |
284 | | //! int val = WITH_LOCK(cs, return shared_val); |
285 | | //! |
286 | | //! Note: |
287 | | //! |
288 | | //! Since the return type deduction follows that of decltype(auto), while the |
289 | | //! deduced type of: |
290 | | //! |
291 | | //! WITH_LOCK(cs, return {int i = 1; return i;}); |
292 | | //! |
293 | | //! is int, the deduced type of: |
294 | | //! |
295 | | //! WITH_LOCK(cs, return {int j = 1; return (j);}); |
296 | | //! |
297 | | //! is &int, a reference to a local variable |
298 | | //! |
299 | | //! The above is detectable at compile-time with the -Wreturn-local-addr flag in |
300 | | //! gcc and the -Wreturn-stack-address flag in clang, both enabled by default. |
301 | 62.5k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) Unexecuted instantiation: AddrManDeterministic::AddrManDeterministic(NetGroupManager const&, FuzzedDataProvider&)::{lambda()#1}::operator()() const Unexecuted instantiation: block_index.cpp:block_index_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1::operator()() const Unexecuted instantiation: chain.cpp:chain_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0::operator()() const Unexecuted instantiation: checkqueue.cpp:CCheckQueue<(anonymous namespace)::DumbCheck>::~CCheckQueue()::{lambda()#1}::operator()() const p2p_headers_sync.cpp:p2p_headers_sync_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0::operator()() const Line | Count | Source | 301 | 290 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
p2p_headers_sync.cpp:p2p_headers_sync_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_5::operator()() const::{lambda()#1}::operator()() const Line | Count | Source | 301 | 8.53k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
V1Transport::ReceivedMessageComplete() const::{lambda()#1}::operator()() const Line | Count | Source | 301 | 26.1k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
Unexecuted instantiation: package_eval.cpp:(anonymous namespace)::tx_package_eval_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1::operator()() const Unexecuted instantiation: package_eval.cpp:(anonymous namespace)::tx_package_eval_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_2::operator()() const Unexecuted instantiation: package_eval.cpp:(anonymous namespace)::tx_package_eval_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_3::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::tx_pool_standard_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::tx_pool_standard_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_2::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::tx_pool_standard_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_5::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::tx_pool_standard_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_6::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::Finish(FuzzedDataProvider&, (anonymous namespace)::MockedTxPool&, Chainstate&)::$_0::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::Finish(FuzzedDataProvider&, (anonymous namespace)::MockedTxPool&, Chainstate&)::$_1::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::Finish(FuzzedDataProvider&, (anonymous namespace)::MockedTxPool&, Chainstate&)::$_2::operator()() const Unexecuted instantiation: tx_pool.cpp:(anonymous namespace)::tx_pool_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0::operator()() const Unexecuted instantiation: utxo_snapshot.cpp:(anonymous namespace)::utxo_snapshot_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_0::operator()() const Unexecuted instantiation: mining.cpp:MineBlock(node::NodeContext const&, std::shared_ptr<CBlock>&)::$_0::operator()() const CScheduler::stop()::{lambda()#1}::operator()() const Line | Count | Source | 301 | 1 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
Unexecuted instantiation: HTTPRequestTracker::AddRequest(evhttp_request*)::{lambda()#1}::operator()() const Unexecuted instantiation: HTTPRequestTracker::CountActiveConnections() const::{lambda()#1}::operator()() const Unexecuted instantiation: init.cpp:AppInitMain(node::NodeContext&, interfaces::BlockAndHeaderTipInfo*)::$_12::operator()() const Unexecuted instantiation: init.cpp:AppInitMain(node::NodeContext&, interfaces::BlockAndHeaderTipInfo*)::$_13::operator()() const Unexecuted instantiation: init.cpp:AppInitMain(node::NodeContext&, interfaces::BlockAndHeaderTipInfo*)::$_16::operator()() const Unexecuted instantiation: init.cpp:StartIndexBackgroundSync(node::NodeContext&)::$_0::operator()() const Unexecuted instantiation: base.cpp:BaseIndex::Init()::$_0::operator()() const Unexecuted instantiation: base.cpp:BaseIndex::Sync()::$_0::operator()() const Unexecuted instantiation: base.cpp:BaseIndex::SetBestBlockIndex(CBlockIndex const*)::$_0::operator()() const Unexecuted instantiation: coinstatsindex.cpp:CoinStatsIndex::CustomAppend(interfaces::BlockInfo const&)::$_0::operator()() const Unexecuted instantiation: blockfilterindex.cpp:BlockFilterIndex::CustomAppend(interfaces::BlockInfo const&)::$_0::operator()() const Unexecuted instantiation: coinstats.cpp:kernel::ComputeUTXOStats(kernel::CoinStatsHashType, CCoinsView*, node::BlockManager&, std::function<void ()> const&)::$_0::operator()() const Unexecuted instantiation: net.cpp:CConnman::AddConnection(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, ConnectionType, bool)::$_0::operator()() const Unexecuted instantiation: net.cpp:CConnman::SocketHandlerConnected(std::vector<CNode*, std::allocator<CNode*> > const&, std::unordered_map<std::shared_ptr<Sock const>, Sock::Events, Sock::HashSharedPtrSock, Sock::EqualSharedPtrSock, std::allocator<std::pair<std::shared_ptr<Sock const> const, Sock::Events> > > const&)::$_0::operator()() const net.cpp:CConnman::StopNodes()::$_0::operator()() const Line | Count | Source | 301 | 291 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
net_processing.cpp:(anonymous namespace)::Peer::GetTxRelay()::{lambda()#1}::operator()() const Line | Count | Source | 301 | 14.4k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
net_processing.cpp:(anonymous namespace)::PeerManagerImpl::GetNodeStateStats(long, CNodeStateStats&) const::$_0::operator()() const Line | Count | Source | 301 | 580 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_0::operator()() const Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_2::operator()() const Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessGetBlockData(CNode&, (anonymous namespace)::Peer&, CInv const&)::$_0::operator()() const Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessGetBlockData(CNode&, (anonymous namespace)::Peer&, CInv const&)::$_1::operator()() const Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_3::operator()() const Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_4::operator()() const Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_5::operator()() const net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessHeadersMessage(CNode&, (anonymous namespace)::Peer&, std::vector<CBlockHeader, std::allocator<CBlockHeader> >&&, bool)::$_0::operator()() const Line | Count | Source | 301 | 1.75k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
net_processing.cpp:(anonymous namespace)::PeerManagerImpl::HandleUnconnectingHeaders(CNode&, (anonymous namespace)::Peer&, std::vector<CBlockHeader, std::allocator<CBlockHeader> > const&)::$_0::operator()() const Line | Count | Source | 301 | 1.55k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
net_processing.cpp:(anonymous namespace)::PeerManagerImpl::HandleUnconnectingHeaders(CNode&, (anonymous namespace)::Peer&, std::vector<CBlockHeader, std::allocator<CBlockHeader> > const&)::$_1::operator()() const Line | Count | Source | 301 | 1.55k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_6::operator()() const Line | Count | Source | 301 | 6.84k | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
Unexecuted instantiation: net_processing.cpp:(anonymous namespace)::PeerManagerImpl::ProcessMessage(CNode&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, DataStream&, std::chrono::duration<long, std::ratio<1l, 1000000l> >, std::atomic<bool> const&)::$_7::operator()() const Unexecuted instantiation: blockstorage.cpp:node::BlockManager::WriteBlockIndexDB()::$_0::operator()() const Unexecuted instantiation: blockstorage.cpp:node::BlockManager::ScanAndUnlinkAlreadyPrunedFiles()::$_0::operator()() const Unexecuted instantiation: blockstorage.cpp:node::BlockManager::UndoReadFromDisk(CBlockUndo&, CBlockIndex const&) const::$_0::operator()() const Unexecuted instantiation: blockstorage.cpp:node::BlockManager::ReadBlockFromDisk(CBlock&, CBlockIndex const&) const::$_0::operator()() const Unexecuted instantiation: blockstorage.cpp:node::ImportBlocks(ChainstateManager&, std::vector<fs::path, std::allocator<fs::path> >)::$_0::operator()() const Unexecuted instantiation: blockstorage.cpp:node::ImportBlocks(ChainstateManager&, std::vector<fs::path, std::allocator<fs::path> >)::$_1::operator()() const Unexecuted instantiation: interfaces.cpp:node::(anonymous namespace)::NodeImpl::getBestBlockHash()::{lambda()#1}::operator()() const Unexecuted instantiation: interfaces.cpp:node::(anonymous namespace)::NodeImpl::getVerificationProgress()::{lambda()#1}::operator()() const Unexecuted instantiation: interfaces.cpp:node::(anonymous namespace)::ChainImpl::getHeight()::{lambda()#1}::operator()() const Unexecuted instantiation: interfaces.cpp:node::(anonymous namespace)::ChainImpl::blockFilterMatchesAny(BlockFilterType, uint256 const&, std::unordered_set<std::vector<unsigned char, std::allocator<unsigned char> >, ByteVectorHash, std::equal_to<std::vector<unsigned char, std::allocator<unsigned char> > >, std::allocator<std::vector<unsigned char, std::allocator<unsigned char> > > > const&)::{lambda()#1}::operator()() const Unexecuted instantiation: interfaces.cpp:node::(anonymous namespace)::ChainImpl::waitForNotificationsIfTipChanged(uint256 const&)::{lambda()#1}::operator()() const Unexecuted instantiation: miner.cpp:node::RegenerateCommitments(CBlock&, ChainstateManager&)::$_0::operator()() const warnings.cpp:node::Warnings::Set(std::variant<kernel::Warning, node::Warning>, bilingual_str)::$_0::operator()() const Line | Count | Source | 301 | 576 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
warnings.cpp:node::Warnings::Unset(std::variant<kernel::Warning, node::Warning>)::$_0::operator()() const Line | Count | Source | 301 | 4 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
Unexecuted instantiation: fees.cpp:FeeFilterRounder::round(long)::$_0::operator()() const Unexecuted instantiation: rest.cpp:rest_deploymentinfo(std::any const&, HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::$_0::operator()() const Unexecuted instantiation: blockchain.cpp:blockToJSON(node::BlockManager&, CBlock const&, CBlockIndex const&, CBlockIndex const&, TxVerbosity)::$_0::operator()() const Unexecuted instantiation: blockchain.cpp:getblockfrompeer()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#1}::operator()() const Unexecuted instantiation: blockchain.cpp:getblockfrompeer()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#2}::operator()() const Unexecuted instantiation: blockchain.cpp:getblockfrompeer()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#3}::operator()() const Unexecuted instantiation: blockchain.cpp:scanblocks()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#1}::operator()() const Unexecuted instantiation: mempool.cpp:submitpackage()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#1}::operator()() const Unexecuted instantiation: rawtransaction.cpp:getrawtransaction()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#1}::operator()() const Unexecuted instantiation: rawtransaction.cpp:getrawtransaction()::$_0::operator()(RPCHelpMan const&, JSONRPCRequest const&) const::{lambda()#2}::operator()() const Unexecuted instantiation: server.cpp:StopRPC()::$_0::operator()() const::{lambda()#1}::operator()() const Unexecuted instantiation: validation.cpp:Chainstate::ActivateBestChain(BlockValidationState&, std::shared_ptr<CBlock const>)::$_0::operator()() const Unexecuted instantiation: validation.cpp:Chainstate::ActivateBestChain(BlockValidationState&, std::shared_ptr<CBlock const>)::$_1::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::ProcessNewBlock(std::shared_ptr<CBlock const> const&, bool, bool, bool*)::$_0::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::ActivateSnapshot(AutoFile&, node::SnapshotMetadata const&, bool)::$_1::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::PopulateAndValidateSnapshot(Chainstate&, AutoFile&, node::SnapshotMetadata const&)::$_1::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::PopulateAndValidateSnapshot(Chainstate&, AutoFile&, node::SnapshotMetadata const&)::$_2::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::PopulateAndValidateSnapshot(Chainstate&, AutoFile&, node::SnapshotMetadata const&)::$_3::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::PopulateAndValidateSnapshot(Chainstate&, AutoFile&, node::SnapshotMetadata const&)::$_4::operator()() const Unexecuted instantiation: validation.cpp:ChainstateManager::PopulateAndValidateSnapshot(Chainstate&, AutoFile&, node::SnapshotMetadata const&)::$_5::operator()() const CCheckQueue<CScriptCheck>::~CCheckQueue()::{lambda()#1}::operator()() const Line | Count | Source | 301 | 1 | #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) |
Unexecuted instantiation: wallet.cpp:wallet::LoadWallet(wallet::WalletContext&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::optional<bool>, wallet::DatabaseOptions const&, wallet::DatabaseStatus&, bilingual_str&, std::vector<bilingual_str, std::allocator<bilingual_str> >&)::$_0::operator()[abi:cxx11]() const Unexecuted instantiation: wallet.cpp:wallet::LoadWallet(wallet::WalletContext&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::optional<bool>, wallet::DatabaseOptions const&, wallet::DatabaseStatus&, bilingual_str&, std::vector<bilingual_str, std::allocator<bilingual_str> >&)::$_1::operator()() const Unexecuted instantiation: wallet.cpp:wallet::CWallet::BlockUntilSyncedToCurrentChain() const::$_0::operator()() const Unexecuted instantiation: wallet.cpp:wallet::CWallet::RescanFromTime(long, wallet::WalletRescanReserver const&, bool)::$_0::operator()() const Unexecuted instantiation: wallet.cpp:wallet::CWallet::ScanForWalletTransactions(uint256 const&, int, std::optional<int>, wallet::WalletRescanReserver const&, bool, bool)::$_0::operator()() const Unexecuted instantiation: wallet.cpp:wallet::CWallet::ScanForWalletTransactions(uint256 const&, int, std::optional<int>, wallet::WalletRescanReserver const&, bool, bool)::$_1::operator()() const Unexecuted instantiation: wallet.cpp:wallet::CWallet::ScanForWalletTransactions(uint256 const&, int, std::optional<int>, wallet::WalletRescanReserver const&, bool, bool)::$_2::operator()() const Unexecuted instantiation: wallet.cpp:wallet::CWallet::postInitProcess()::$_0::operator()() const Unexecuted instantiation: backup.cpp:wallet::EnsureBlockDataFromTime(wallet::CWallet const&, long)::$_0::operator()() const Branch (301:89): [True: 0, False: 0]
Branch (301:89): [True: 0, False: 0]
|
302 | | |
303 | | /** An implementation of a semaphore. |
304 | | * |
305 | | * See https://en.wikipedia.org/wiki/Semaphore_(programming) |
306 | | */ |
307 | | class CSemaphore |
308 | | { |
309 | | private: |
310 | | std::condition_variable condition; |
311 | | std::mutex mutex; |
312 | | int value; |
313 | | |
314 | | public: |
315 | 0 | explicit CSemaphore(int init) noexcept : value(init) {} |
316 | | |
317 | | // Disallow default construct, copy, move. |
318 | | CSemaphore() = delete; |
319 | | CSemaphore(const CSemaphore&) = delete; |
320 | | CSemaphore(CSemaphore&&) = delete; |
321 | | CSemaphore& operator=(const CSemaphore&) = delete; |
322 | | CSemaphore& operator=(CSemaphore&&) = delete; |
323 | | |
324 | | void wait() noexcept |
325 | 0 | { |
326 | 0 | std::unique_lock<std::mutex> lock(mutex); |
327 | 0 | condition.wait(lock, [&]() { return value >= 1; }); |
328 | 0 | value--; |
329 | 0 | } |
330 | | |
331 | | bool try_wait() noexcept |
332 | 0 | { |
333 | 0 | std::lock_guard<std::mutex> lock(mutex); |
334 | 0 | if (value < 1) { Branch (334:13): [True: 0, False: 0]
|
335 | 0 | return false; |
336 | 0 | } |
337 | 0 | value--; |
338 | 0 | return true; |
339 | 0 | } |
340 | | |
341 | | void post() noexcept |
342 | 0 | { |
343 | 0 | { |
344 | 0 | std::lock_guard<std::mutex> lock(mutex); |
345 | 0 | value++; |
346 | 0 | } |
347 | 0 | condition.notify_one(); |
348 | 0 | } |
349 | | }; |
350 | | |
351 | | /** RAII-style semaphore lock */ |
352 | | class CSemaphoreGrant |
353 | | { |
354 | | private: |
355 | | CSemaphore* sem; |
356 | | bool fHaveGrant; |
357 | | |
358 | | public: |
359 | | void Acquire() noexcept |
360 | 0 | { |
361 | 0 | if (fHaveGrant) { Branch (361:13): [True: 0, False: 0]
|
362 | 0 | return; |
363 | 0 | } |
364 | 0 | sem->wait(); |
365 | 0 | fHaveGrant = true; |
366 | 0 | } |
367 | | |
368 | | void Release() noexcept |
369 | 870 | { |
370 | 870 | if (!fHaveGrant) { Branch (370:13): [True: 870, False: 0]
|
371 | 870 | return; |
372 | 870 | } |
373 | 0 | sem->post(); |
374 | 0 | fHaveGrant = false; |
375 | 0 | } |
376 | | |
377 | | bool TryAcquire() noexcept |
378 | 0 | { |
379 | 0 | if (!fHaveGrant && sem->try_wait()) { Branch (379:13): [True: 0, False: 0]
Branch (379:28): [True: 0, False: 0]
|
380 | 0 | fHaveGrant = true; |
381 | 0 | } |
382 | 0 | return fHaveGrant; |
383 | 0 | } |
384 | | |
385 | | // Disallow copy. |
386 | | CSemaphoreGrant(const CSemaphoreGrant&) = delete; |
387 | | CSemaphoreGrant& operator=(const CSemaphoreGrant&) = delete; |
388 | | |
389 | | // Allow move. |
390 | | CSemaphoreGrant(CSemaphoreGrant&& other) noexcept |
391 | 0 | { |
392 | 0 | sem = other.sem; |
393 | 0 | fHaveGrant = other.fHaveGrant; |
394 | 0 | other.fHaveGrant = false; |
395 | 0 | other.sem = nullptr; |
396 | 0 | } |
397 | | |
398 | | CSemaphoreGrant& operator=(CSemaphoreGrant&& other) noexcept |
399 | 0 | { |
400 | 0 | Release(); |
401 | 0 | sem = other.sem; |
402 | 0 | fHaveGrant = other.fHaveGrant; |
403 | 0 | other.fHaveGrant = false; |
404 | 0 | other.sem = nullptr; |
405 | 0 | return *this; |
406 | 0 | } |
407 | | |
408 | 870 | CSemaphoreGrant() noexcept : sem(nullptr), fHaveGrant(false) {} |
409 | | |
410 | 0 | explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) noexcept : sem(&sema), fHaveGrant(false) |
411 | 0 | { |
412 | 0 | if (fTry) { Branch (412:13): [True: 0, False: 0]
|
413 | 0 | TryAcquire(); |
414 | 0 | } else { |
415 | 0 | Acquire(); |
416 | 0 | } |
417 | 0 | } |
418 | | |
419 | | ~CSemaphoreGrant() |
420 | 870 | { |
421 | 870 | Release(); |
422 | 870 | } |
423 | | |
424 | | explicit operator bool() const noexcept |
425 | 0 | { |
426 | 0 | return fHaveGrant; |
427 | 0 | } |
428 | | }; |
429 | | |
430 | | #endif // BITCOIN_SYNC_H |