Skip to content

Commit

Permalink
merge bitcoin#19340: Preserve the LockData initial state if "potentia…
Browse files Browse the repository at this point in the history
…l deadlock detected" exception thrown
  • Loading branch information
kwvg committed Oct 8, 2021
1 parent 6bf96e2 commit da19a4c
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 9 deletions.
22 changes: 19 additions & 3 deletions src/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,17 @@ static void push_lock(void* c, const CLockLocation& locklocation)
const LockPair p1 = std::make_pair(i.first, c);
if (lockdata.lockorders.count(p1))
continue;
lockdata.lockorders.emplace(p1, lock_stack);

const LockPair p2 = std::make_pair(c, i.first);
if (lockdata.lockorders.count(p2)) {
auto lock_stack_copy = lock_stack;
lock_stack.pop_back();
potential_deadlock_detected(p1, lockdata.lockorders[p2], lock_stack_copy);
// potential_deadlock_detected() does not return.
}

lockdata.lockorders.emplace(p1, lock_stack);
lockdata.invlockorders.insert(p2);
if (lockdata.lockorders.count(p2))
potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
}
}

Expand Down Expand Up @@ -262,6 +267,17 @@ void DeleteLock(void* cs)
}
}

bool LockStackEmpty()
{
LockData& lockdata = GetLockData();
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
const auto it = lockdata.m_lock_stacks.find(std::this_thread::get_id());
if (it == lockdata.m_lock_stacks.end()) {
return true;
}
return it->second.empty();
}

bool g_debug_lockorder_abort = true;

#endif /* DEBUG_LOCKORDER */
14 changes: 8 additions & 6 deletions src/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ template <typename MutexType>
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs);
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
void DeleteLock(void* cs);
bool LockStackEmpty();

/**
* Call abort() if a potential lock order deadlock bug is detected, instead of
Expand All @@ -64,13 +65,14 @@ void DeleteLock(void* cs);
*/
extern bool g_debug_lockorder_abort;
#else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
void static inline LeaveCritical() {}
void static inline CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
inline void LeaveCritical() {}
inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
template <typename MutexType>
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
void static inline DeleteLock(void* cs) {}
inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
inline void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
inline void DeleteLock(void* cs) {}
inline bool LockStackEmpty() { return true; }
#endif
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
Expand Down
6 changes: 6 additions & 0 deletions src/test/sync_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
{
LOCK2(mutex1, mutex2);
}
BOOST_CHECK(LockStackEmpty());
bool error_thrown = false;
try {
LOCK2(mutex2, mutex1);
} catch (const std::logic_error& e) {
BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected");
error_thrown = true;
}
BOOST_CHECK(LockStackEmpty());
#ifdef DEBUG_LOCKORDER
BOOST_CHECK(error_thrown);
#else
Expand All @@ -40,9 +42,13 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected)

CCriticalSection rmutex1, rmutex2;
TestPotentialDeadLockDetected(rmutex1, rmutex2);
// The second test ensures that lock tracking data have not been broken by exception.
TestPotentialDeadLockDetected(rmutex1, rmutex2);

Mutex mutex1, mutex2;
TestPotentialDeadLockDetected(mutex1, mutex2);
// The second test ensures that lock tracking data have not been broken by exception.
TestPotentialDeadLockDetected(mutex1, mutex2);

#ifdef DEBUG_LOCKORDER
g_debug_lockorder_abort = prev;
Expand Down

0 comments on commit da19a4c

Please sign in to comment.