Branch data Line data Source code
# 1 : : // Copyright (c) 2011-2020 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 : : #if defined(HAVE_CONFIG_H)
# 6 : : #include <config/bitcoin-config.h>
# 7 : : #endif
# 8 : :
# 9 : : #include <sync.h>
# 10 : :
# 11 : : #include <logging.h>
# 12 : : #include <tinyformat.h>
# 13 : : #include <util/strencodings.h>
# 14 : : #include <util/threadnames.h>
# 15 : :
# 16 : : #include <map>
# 17 : : #include <mutex>
# 18 : : #include <set>
# 19 : : #include <system_error>
# 20 : : #include <thread>
# 21 : : #include <type_traits>
# 22 : : #include <unordered_map>
# 23 : : #include <utility>
# 24 : : #include <vector>
# 25 : :
# 26 : : #ifdef DEBUG_LOCKCONTENTION
# 27 : : #if !defined(HAVE_THREAD_LOCAL)
# 28 : : static_assert(false, "thread_local is not supported");
# 29 : : #endif
# 30 : : void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
# 31 : : {
# 32 : : LogPrintf("LOCKCONTENTION: %s\n", pszName);
# 33 : : LogPrintf("Locker: %s:%d\n", pszFile, nLine);
# 34 : : }
# 35 : : #endif /* DEBUG_LOCKCONTENTION */
# 36 : :
# 37 : : #ifdef DEBUG_LOCKORDER
# 38 : : //
# 39 : : // Early deadlock detection.
# 40 : : // Problem being solved:
# 41 : : // Thread 1 locks A, then B, then C
# 42 : : // Thread 2 locks D, then C, then A
# 43 : : // --> may result in deadlock between the two threads, depending on when they run.
# 44 : : // Solution implemented here:
# 45 : : // Keep track of pairs of locks: (A before B), (A before C), etc.
# 46 : : // Complain if any thread tries to lock in a different order.
# 47 : : //
# 48 : :
# 49 : : struct CLockLocation {
# 50 : : CLockLocation(
# 51 : : const char* pszName,
# 52 : : const char* pszFile,
# 53 : : int nLine,
# 54 : : bool fTryIn,
# 55 : : const std::string& thread_name)
# 56 : : : fTry(fTryIn),
# 57 : : mutexName(pszName),
# 58 : : sourceFile(pszFile),
# 59 : : m_thread_name(thread_name),
# 60 : 116480304 : sourceLine(nLine) {}
# 61 : :
# 62 : : std::string ToString() const
# 63 : 56 : {
# 64 : 56 : return strprintf(
# 65 : 56 : "'%s' in %s:%s%s (in thread '%s')",
# 66 [ - + ]: 56 : mutexName, sourceFile, sourceLine, (fTry ? " (TRY)" : ""), m_thread_name);
# 67 : 56 : }
# 68 : :
# 69 : : std::string Name() const
# 70 : 884377 : {
# 71 : 884377 : return mutexName;
# 72 : 884377 : }
# 73 : :
# 74 : : private:
# 75 : : bool fTry;
# 76 : : std::string mutexName;
# 77 : : std::string sourceFile;
# 78 : : const std::string& m_thread_name;
# 79 : : int sourceLine;
# 80 : : };
# 81 : :
# 82 : : using LockStackItem = std::pair<void*, CLockLocation>;
# 83 : : using LockStack = std::vector<LockStackItem>;
# 84 : : using LockStacks = std::unordered_map<std::thread::id, LockStack>;
# 85 : :
# 86 : : using LockPair = std::pair<void*, void*>;
# 87 : : using LockOrders = std::map<LockPair, LockStack>;
# 88 : : using InvLockOrders = std::set<LockPair>;
# 89 : :
# 90 : : struct LockData {
# 91 : : LockStacks m_lock_stacks;
# 92 : : LockOrders lockorders;
# 93 : : InvLockOrders invlockorders;
# 94 : : std::mutex dd_mutex;
# 95 : : };
# 96 : :
# 97 : 256926316 : LockData& GetLockData() {
# 98 : : // This approach guarantees that the object is not destroyed until after its last use.
# 99 : : // The operating system automatically reclaims all the memory in a program's heap when that program exits.
# 100 : : // Since the ~LockData() destructor is never called, the LockData class and all
# 101 : : // its subclasses must have implicitly-defined destructors.
# 102 : 256926316 : static LockData& lock_data = *new LockData();
# 103 : 256926316 : return lock_data;
# 104 : 256926316 : }
# 105 : :
# 106 : : static void potential_deadlock_detected(const LockPair& mismatch, const LockStack& s1, const LockStack& s2)
# 107 : 8 : {
# 108 : 8 : LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
# 109 : 8 : LogPrintf("Previous lock order was:\n");
# 110 [ + + ]: 16 : for (const LockStackItem& i : s1) {
# 111 [ + + ]: 16 : if (i.first == mismatch.first) {
# 112 : 8 : LogPrintf(" (1)"); /* Continued */
# 113 : 8 : }
# 114 [ + + ]: 16 : if (i.first == mismatch.second) {
# 115 : 8 : LogPrintf(" (2)"); /* Continued */
# 116 : 8 : }
# 117 : 16 : LogPrintf(" %s\n", i.second.ToString());
# 118 : 16 : }
# 119 : :
# 120 : 8 : std::string mutex_a, mutex_b;
# 121 : 8 : LogPrintf("Current lock order is:\n");
# 122 [ + + ]: 16 : for (const LockStackItem& i : s2) {
# 123 [ + + ]: 16 : if (i.first == mismatch.first) {
# 124 : 8 : LogPrintf(" (1)"); /* Continued */
# 125 : 8 : mutex_a = i.second.Name();
# 126 : 8 : }
# 127 [ + + ]: 16 : if (i.first == mismatch.second) {
# 128 : 8 : LogPrintf(" (2)"); /* Continued */
# 129 : 8 : mutex_b = i.second.Name();
# 130 : 8 : }
# 131 : 16 : LogPrintf(" %s\n", i.second.ToString());
# 132 : 16 : }
# 133 [ - + ]: 8 : if (g_debug_lockorder_abort) {
# 134 : 0 : tfm::format(std::cerr, "Assertion failed: detected inconsistent lock order for %s, details in debug log.\n", s2.back().second.ToString());
# 135 : 0 : abort();
# 136 : 0 : }
# 137 : 8 : throw std::logic_error(strprintf("potential deadlock detected: %s -> %s -> %s", mutex_b, mutex_a, mutex_b));
# 138 : 8 : }
# 139 : :
# 140 : : static void double_lock_detected(const void* mutex, const LockStack& lock_stack)
# 141 : 2 : {
# 142 : 2 : LogPrintf("DOUBLE LOCK DETECTED\n");
# 143 : 2 : LogPrintf("Lock order:\n");
# 144 [ + + ]: 4 : for (const LockStackItem& i : lock_stack) {
# 145 [ + - ]: 4 : if (i.first == mutex) {
# 146 : 4 : LogPrintf(" (*)"); /* Continued */
# 147 : 4 : }
# 148 : 4 : LogPrintf(" %s\n", i.second.ToString());
# 149 : 4 : }
# 150 [ - + ]: 2 : if (g_debug_lockorder_abort) {
# 151 : 0 : tfm::format(std::cerr,
# 152 : 0 : "Assertion failed: detected double lock for %s, details in debug log.\n",
# 153 : 0 : lock_stack.back().second.ToString());
# 154 : 0 : abort();
# 155 : 0 : }
# 156 : 2 : throw std::logic_error("double lock detected");
# 157 : 2 : }
# 158 : :
# 159 : : template <typename MutexType>
# 160 : : static void push_lock(MutexType* c, const CLockLocation& locklocation)
# 161 : 116484014 : {
# 162 : 116484014 : constexpr bool is_recursive_mutex =
# 163 : 116484014 : std::is_base_of<RecursiveMutex, MutexType>::value ||
# 164 : 116484014 : std::is_base_of<std::recursive_mutex, MutexType>::value;
# 165 : :
# 166 : 116484014 : LockData& lockdata = GetLockData();
# 167 : 116484014 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 168 : :
# 169 : 116484014 : LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
# 170 : 116484014 : lock_stack.emplace_back(c, locklocation);
# 171 [ + + ][ + + ]: 220684999 : for (size_t j = 0; j < lock_stack.size() - 1; ++j) {
# [ + + ][ + + ]
# 172 : 138756967 : const LockStackItem& i = lock_stack[j];
# 173 [ + + ][ - + ]: 138756967 : if (i.first == c) {
# [ + + ][ + + ]
# 174 : 34555984 : if (is_recursive_mutex) {
# 175 : 34555982 : break;
# 176 : 34555982 : }
# 177 : : // It is not a recursive mutex and it appears in the stack two times:
# 178 : : // at position `j` and at the end (which we added just before this loop).
# 179 : : // Can't allow locking the same (non-recursive) mutex two times from the
# 180 : : // same thread as that results in an undefined behavior.
# 181 : 2 : auto lock_stack_copy = lock_stack;
# 182 : 2 : lock_stack.pop_back();
# 183 : 2 : double_lock_detected(c, lock_stack_copy);
# 184 : : // double_lock_detected() does not return.
# 185 : 2 : }
# 186 : :
# 187 : 138756967 : const LockPair p1 = std::make_pair(i.first, c);
# 188 [ + + ][ + + ]: 104200985 : if (lockdata.lockorders.count(p1))
# [ + + ][ + + ]
# 189 : 104070327 : continue;
# 190 : :
# 191 : 130658 : const LockPair p2 = std::make_pair(c, i.first);
# 192 [ + + ][ - + ]: 130658 : if (lockdata.lockorders.count(p2)) {
# [ - + ][ + + ]
# 193 : 8 : auto lock_stack_copy = lock_stack;
# 194 : 8 : lock_stack.pop_back();
# 195 : 8 : potential_deadlock_detected(p1, lockdata.lockorders[p2], lock_stack_copy);
# 196 : : // potential_deadlock_detected() does not return.
# 197 : 8 : }
# 198 : :
# 199 : 130658 : lockdata.lockorders.emplace(p1, lock_stack);
# 200 : 130658 : lockdata.invlockorders.insert(p2);
# 201 : 130658 : }
# 202 : 116484014 : }
# 203 : :
# 204 : : static void pop_lock()
# 205 : 116483685 : {
# 206 : 116483685 : LockData& lockdata = GetLockData();
# 207 : 116483685 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 208 : :
# 209 : 116483685 : LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
# 210 : 116483685 : lock_stack.pop_back();
# 211 [ + + ]: 116483685 : if (lock_stack.empty()) {
# 212 : 46818139 : lockdata.m_lock_stacks.erase(std::this_thread::get_id());
# 213 : 46818139 : }
# 214 : 116483685 : }
# 215 : :
# 216 : : template <typename MutexType>
# 217 : : void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry)
# 218 : 116483301 : {
# 219 : 116483301 : push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName()));
# 220 : 116483301 : }
# 221 : : template void EnterCritical(const char*, const char*, int, Mutex*, bool);
# 222 : : template void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool);
# 223 : : template void EnterCritical(const char*, const char*, int, std::mutex*, bool);
# 224 : : template void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool);
# 225 : :
# 226 : : void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)
# 227 : 884371 : {
# 228 : 884371 : LockData& lockdata = GetLockData();
# 229 : 884371 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 230 : :
# 231 : 884371 : const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
# 232 [ + - ]: 884371 : if (!lock_stack.empty()) {
# 233 : 884371 : const auto& lastlock = lock_stack.back();
# 234 [ + + ]: 884371 : if (lastlock.first == cs) {
# 235 : 884361 : lockname = lastlock.second.Name();
# 236 : 884361 : return;
# 237 : 884361 : }
# 238 : 10 : }
# 239 : :
# 240 : 10 : LogPrintf("INCONSISTENT LOCK ORDER DETECTED\n");
# 241 : 10 : LogPrintf("Current lock order (least recent first) is:\n");
# 242 [ + + ]: 20 : for (const LockStackItem& i : lock_stack) {
# 243 : 20 : LogPrintf(" %s\n", i.second.ToString());
# 244 : 20 : }
# 245 [ - + ]: 10 : if (g_debug_lockorder_abort) {
# 246 : 0 : tfm::format(std::cerr, "%s:%s %s was not most recent critical section locked, details in debug log.\n", file, line, guardname);
# 247 : 0 : abort();
# 248 : 0 : }
# 249 : 10 : throw std::logic_error(strprintf("%s was not most recent critical section locked", guardname));
# 250 : 10 : }
# 251 : :
# 252 : : void LeaveCritical()
# 253 : 116483575 : {
# 254 : 116483575 : pop_lock();
# 255 : 116483575 : }
# 256 : :
# 257 : : std::string LocksHeld()
# 258 : 0 : {
# 259 : 0 : LockData& lockdata = GetLockData();
# 260 : 0 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 261 : :
# 262 : 0 : const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
# 263 : 0 : std::string result;
# 264 [ # # ]: 0 : for (const LockStackItem& i : lock_stack)
# 265 : 0 : result += i.second.ToString() + std::string("\n");
# 266 : 0 : return result;
# 267 : 0 : }
# 268 : :
# 269 : : static bool LockHeld(void* mutex)
# 270 : 23009292 : {
# 271 : 23009292 : LockData& lockdata = GetLockData();
# 272 : 23009292 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 273 : :
# 274 : 23009292 : const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
# 275 [ + + ]: 32271471 : for (const LockStackItem& i : lock_stack) {
# 276 [ + + ]: 32271471 : if (i.first == mutex) return true;
# 277 : 32271471 : }
# 278 : :
# 279 : 23009292 : return false;
# 280 : 23009292 : }
# 281 : :
# 282 : : template <typename MutexType>
# 283 : : void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)
# 284 : 22683884 : {
# 285 [ + + ][ # # ]: 22683964 : if (LockHeld(cs)) return;
# 286 :>1844*10^16 : tfm::format(std::cerr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld());
# 287 :>1844*10^16 : abort();
# 288 :>1844*10^16 : }
# 289 : : template void AssertLockHeldInternal(const char*, const char*, int, Mutex*);
# 290 : : template void AssertLockHeldInternal(const char*, const char*, int, RecursiveMutex*);
# 291 : :
# 292 : : template <typename MutexType>
# 293 : : void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs)
# 294 : 325428 : {
# 295 [ + + ][ # # ]: 325430 : if (!LockHeld(cs)) return;
# 296 :>1844*10^16 : tfm::format(std::cerr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld());
# 297 :>1844*10^16 : abort();
# 298 :>1844*10^16 : }
# 299 : : template void AssertLockNotHeldInternal(const char*, const char*, int, Mutex*);
# 300 : : template void AssertLockNotHeldInternal(const char*, const char*, int, RecursiveMutex*);
# 301 : :
# 302 : : void DeleteLock(void* cs)
# 303 : 94977 : {
# 304 : 94977 : LockData& lockdata = GetLockData();
# 305 : 94977 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 306 : 94977 : const LockPair item = std::make_pair(cs, nullptr);
# 307 : 94977 : LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
# 308 [ + + ][ + + ]: 165159 : while (it != lockdata.lockorders.end() && it->first.first == cs) {
# [ + + ]
# 309 : 70182 : const LockPair invitem = std::make_pair(it->first.second, it->first.first);
# 310 : 70182 : lockdata.invlockorders.erase(invitem);
# 311 : 70182 : lockdata.lockorders.erase(it++);
# 312 : 70182 : }
# 313 : 94977 : InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
# 314 [ + + ][ + + ]: 141571 : while (invit != lockdata.invlockorders.end() && invit->first == cs) {
# [ + + ]
# 315 : 46594 : const LockPair invinvitem = std::make_pair(invit->second, invit->first);
# 316 : 46594 : lockdata.lockorders.erase(invinvitem);
# 317 : 46594 : lockdata.invlockorders.erase(invit++);
# 318 : 46594 : }
# 319 : 94977 : }
# 320 : :
# 321 : : bool LockStackEmpty()
# 322 : 28 : {
# 323 : 28 : LockData& lockdata = GetLockData();
# 324 : 28 : std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
# 325 : 28 : const auto it = lockdata.m_lock_stacks.find(std::this_thread::get_id());
# 326 [ + - ]: 28 : if (it == lockdata.m_lock_stacks.end()) {
# 327 : 28 : return true;
# 328 : 28 : }
# 329 : 0 : return it->second.empty();
# 330 : 0 : }
# 331 : :
# 332 : : bool g_debug_lockorder_abort = true;
# 333 : :
# 334 : : #endif /* DEBUG_LOCKORDER */
|