]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2011-2012 The Bitcoin Core developers |
78253fcb | 2 | // Distributed under the MIT software license, see the accompanying |
bc909a7a | 3 | // file COPYING or https://www.opensource.org/licenses/mit-license.php . |
7f3ccb59 PW |
4 | |
5 | #include "sync.h" | |
51ed9ec9 | 6 | |
660ff174 | 7 | #include "util.h" |
d2d6f708 | 8 | #include "utilstrencodings.h" |
7f3ccb59 | 9 | |
611116d4 PK |
10 | #include <stdio.h> |
11 | ||
660ff174 | 12 | #include <boost/foreach.hpp> |
d2d6f708 | 13 | #include <boost/thread.hpp> |
7f3ccb59 | 14 | |
4d009243 MC |
15 | #ifdef DEBUG_LOCKCONTENTION |
16 | void PrintLockContention(const char* pszName, const char* pszFile, int nLine) | |
17 | { | |
881a85a2 GA |
18 | LogPrintf("LOCKCONTENTION: %s\n", pszName); |
19 | LogPrintf("Locker: %s:%d\n", pszFile, nLine); | |
4d009243 MC |
20 | } |
21 | #endif /* DEBUG_LOCKCONTENTION */ | |
22 | ||
7f3ccb59 PW |
23 | #ifdef DEBUG_LOCKORDER |
24 | // | |
25 | // Early deadlock detection. | |
26 | // Problem being solved: | |
27 | // Thread 1 locks A, then B, then C | |
28 | // Thread 2 locks D, then C, then A | |
29 | // --> may result in deadlock between the two threads, depending on when they run. | |
30 | // Solution implemented here: | |
31 | // Keep track of pairs of locks: (A before B), (A before C), etc. | |
e7494052 | 32 | // Complain if any thread tries to lock in a different order. |
7f3ccb59 PW |
33 | // |
34 | ||
20e01b1a | 35 | struct CLockLocation { |
8e4bc69d | 36 | CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn) |
7f3ccb59 PW |
37 | { |
38 | mutexName = pszName; | |
39 | sourceFile = pszFile; | |
40 | sourceLine = nLine; | |
8e4bc69d | 41 | fTry = fTryIn; |
7f3ccb59 PW |
42 | } |
43 | ||
44 | std::string ToString() const | |
45 | { | |
8e4bc69d | 46 | return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); |
7f3ccb59 PW |
47 | } |
48 | ||
c649637b GA |
49 | std::string MutexName() const { return mutexName; } |
50 | ||
8e4bc69d | 51 | bool fTry; |
7f3ccb59 PW |
52 | private: |
53 | std::string mutexName; | |
54 | std::string sourceFile; | |
55 | int sourceLine; | |
56 | }; | |
57 | ||
20e01b1a | 58 | typedef std::vector<std::pair<void*, CLockLocation> > LockStack; |
7f3ccb59 | 59 | |
660ff174 | 60 | static boost::mutex dd_mutex; |
7f3ccb59 PW |
61 | static std::map<std::pair<void*, void*>, LockStack> lockorders; |
62 | static boost::thread_specific_ptr<LockStack> lockstack; | |
63 | ||
64 | ||
65 | static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) | |
66 | { | |
8e4bc69d MC |
67 | // We attempt to not assert on probably-not deadlocks by assuming that |
68 | // a try lock will immediately have otherwise bailed if it had | |
69 | // failed to get the lock | |
70 | // We do this by, for the locks which triggered the potential deadlock, | |
71 | // in either lockorder, checking that the second of the two which is locked | |
72 | // is only a TRY_LOCK, ignoring locks if they are reentrant. | |
73 | bool firstLocked = false; | |
74 | bool secondLocked = false; | |
75 | bool onlyMaybeDeadlock = false; | |
76 | ||
881a85a2 GA |
77 | LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); |
78 | LogPrintf("Previous lock order was:\n"); | |
20e01b1a | 79 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) { |
8e4bc69d | 80 | if (i.first == mismatch.first) { |
20e01b1a | 81 | LogPrintf(" (1)"); |
8e4bc69d MC |
82 | if (!firstLocked && secondLocked && i.second.fTry) |
83 | onlyMaybeDeadlock = true; | |
84 | firstLocked = true; | |
85 | } | |
86 | if (i.first == mismatch.second) { | |
20e01b1a | 87 | LogPrintf(" (2)"); |
8e4bc69d MC |
88 | if (!secondLocked && firstLocked && i.second.fTry) |
89 | onlyMaybeDeadlock = true; | |
90 | secondLocked = true; | |
91 | } | |
7d9d134b | 92 | LogPrintf(" %s\n", i.second.ToString()); |
7f3ccb59 | 93 | } |
8e4bc69d MC |
94 | firstLocked = false; |
95 | secondLocked = false; | |
881a85a2 | 96 | LogPrintf("Current lock order is:\n"); |
20e01b1a | 97 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) { |
8e4bc69d | 98 | if (i.first == mismatch.first) { |
20e01b1a | 99 | LogPrintf(" (1)"); |
8e4bc69d MC |
100 | if (!firstLocked && secondLocked && i.second.fTry) |
101 | onlyMaybeDeadlock = true; | |
102 | firstLocked = true; | |
103 | } | |
104 | if (i.first == mismatch.second) { | |
20e01b1a | 105 | LogPrintf(" (2)"); |
8e4bc69d MC |
106 | if (!secondLocked && firstLocked && i.second.fTry) |
107 | onlyMaybeDeadlock = true; | |
108 | secondLocked = true; | |
109 | } | |
7d9d134b | 110 | LogPrintf(" %s\n", i.second.ToString()); |
7f3ccb59 | 111 | } |
8e4bc69d | 112 | assert(onlyMaybeDeadlock); |
7f3ccb59 PW |
113 | } |
114 | ||
115 | static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) | |
116 | { | |
7f3ccb59 PW |
117 | if (lockstack.get() == NULL) |
118 | lockstack.reset(new LockStack); | |
119 | ||
7f3ccb59 PW |
120 | dd_mutex.lock(); |
121 | ||
122 | (*lockstack).push_back(std::make_pair(c, locklocation)); | |
123 | ||
660ff174 | 124 | if (!fTry) { |
20e01b1a PW |
125 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) { |
126 | if (i.first == c) | |
127 | break; | |
660ff174 PW |
128 | |
129 | std::pair<void*, void*> p1 = std::make_pair(i.first, c); | |
130 | if (lockorders.count(p1)) | |
131 | continue; | |
132 | lockorders[p1] = (*lockstack); | |
133 | ||
134 | std::pair<void*, void*> p2 = std::make_pair(c, i.first); | |
8e4bc69d | 135 | if (lockorders.count(p2)) |
660ff174 | 136 | potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); |
7f3ccb59 PW |
137 | } |
138 | } | |
139 | dd_mutex.unlock(); | |
140 | } | |
141 | ||
142 | static void pop_lock() | |
143 | { | |
7f3ccb59 PW |
144 | dd_mutex.lock(); |
145 | (*lockstack).pop_back(); | |
146 | dd_mutex.unlock(); | |
147 | } | |
148 | ||
149 | void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) | |
150 | { | |
8e4bc69d | 151 | push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry); |
7f3ccb59 PW |
152 | } |
153 | ||
154 | void LeaveCritical() | |
155 | { | |
156 | pop_lock(); | |
157 | } | |
158 | ||
c649637b GA |
159 | std::string LocksHeld() |
160 | { | |
161 | std::string result; | |
20e01b1a | 162 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack) |
c649637b GA |
163 | result += i.second.ToString() + std::string("\n"); |
164 | return result; | |
165 | } | |
166 | ||
20e01b1a | 167 | void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) |
c649637b | 168 | { |
20e01b1a PW |
169 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack) |
170 | if (i.first == cs) | |
171 | return; | |
172 | fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str()); | |
ca4cf5cf | 173 | abort(); |
c649637b GA |
174 | } |
175 | ||
7f3ccb59 | 176 | #endif /* DEBUG_LOCKORDER */ |