16 #ifdef DEBUG_LOCKCONTENTION
17 #if !defined(HAVE_THREAD_LOCAL)
18 static_assert(
false,
"thread_local is not supported");
20 void PrintLockContention(
const char* pszName,
const char* pszFile,
int nLine)
22 LogPrintf(
"LOCKCONTENTION: %s\n", pszName);
23 LogPrintf(
"Locker: %s:%d\n", pszFile, nLine);
27 #ifdef DEBUG_LOCKORDER
39 struct CLockLocation {
45 const std::string& thread_name)
49 m_thread_name(thread_name),
52 std::string ToString()
const
55 "%s %s:%s%s (in thread %s)",
56 mutexName, sourceFile,
itostr(sourceLine), (fTry ?
" (TRY)" :
""), m_thread_name);
61 std::string mutexName;
62 std::string sourceFile;
63 const std::string& m_thread_name;
67 typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
68 typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
69 typedef std::set<std::pair<void*, void*> > InvLockOrders;
77 LockData() : available(true) {}
78 ~LockData() { available =
false; }
80 LockOrders lockorders;
81 InvLockOrders invlockorders;
84 LockData& GetLockData() {
85 static LockData lockdata;
89 static thread_local LockStack g_lockstack;
91 static void potential_deadlock_detected(
const std::pair<void*, void*>& mismatch,
const LockStack& s1,
const LockStack& s2)
93 LogPrintf(
"POTENTIAL DEADLOCK DETECTED\n");
95 for (
const std::pair<void*, CLockLocation> & i : s2) {
96 if (i.first == mismatch.first) {
99 if (i.first == mismatch.second) {
105 for (
const std::pair<void*, CLockLocation> & i : s1) {
106 if (i.first == mismatch.first) {
109 if (i.first == mismatch.second) {
114 if (g_debug_lockorder_abort) {
115 tfm::format(std::cerr,
"Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
118 throw std::logic_error(
"potential deadlock detected");
121 static void push_lock(
void* c,
const CLockLocation& locklocation)
123 LockData& lockdata = GetLockData();
124 std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
126 g_lockstack.push_back(std::make_pair(c, locklocation));
128 for (
const std::pair<void*, CLockLocation>& i : g_lockstack) {
132 std::pair<void*, void*> p1 = std::make_pair(i.first, c);
133 if (lockdata.lockorders.count(p1))
135 lockdata.lockorders.emplace(p1, g_lockstack);
137 std::pair<void*, void*> p2 = std::make_pair(c, i.first);
138 lockdata.invlockorders.insert(p2);
139 if (lockdata.lockorders.count(p2))
140 potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
144 static void pop_lock()
146 g_lockstack.pop_back();
149 void EnterCritical(
const char* pszName,
const char* pszFile,
int nLine,
void* cs,
bool fTry)
159 std::string LocksHeld()
162 for (
const std::pair<void*, CLockLocation>& i : g_lockstack)
163 result += i.second.ToString() + std::string(
"\n");
167 void AssertLockHeldInternal(
const char* pszName,
const char* pszFile,
int nLine,
void* cs)
169 for (
const std::pair<void*, CLockLocation>& i : g_lockstack)
172 fprintf(stderr,
"Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
176 void AssertLockNotHeldInternal(
const char* pszName,
const char* pszFile,
int nLine,
void* cs)
178 for (
const std::pair<void*, CLockLocation>& i : g_lockstack) {
180 tfm::format(std::cerr,
"Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld());
186 void DeleteLock(
void* cs)
188 LockData& lockdata = GetLockData();
189 if (!lockdata.available) {
193 std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
194 std::pair<void*, void*> item = std::make_pair(cs,
nullptr);
195 LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
196 while (it != lockdata.lockorders.end() && it->first.first == cs) {
197 std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
198 lockdata.invlockorders.erase(invitem);
199 lockdata.lockorders.erase(it++);
201 InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
202 while (invit != lockdata.invlockorders.end() && invit->first == cs) {
203 std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
204 lockdata.lockorders.erase(invinvitem);
205 lockdata.invlockorders.erase(invit++);
209 bool g_debug_lockorder_abort =
true;