]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2011-2012 The Bitcoin Core developers |
78253fcb | 2 | // Distributed under the MIT software license, see the accompanying |
3a25a2b9 | 3 | // file COPYING or http://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 { |
7f3ccb59 PW |
36 | CLockLocation(const char* pszName, const char* pszFile, int nLine) |
37 | { | |
38 | mutexName = pszName; | |
39 | sourceFile = pszFile; | |
40 | sourceLine = nLine; | |
41 | } | |
42 | ||
43 | std::string ToString() const | |
44 | { | |
20e01b1a | 45 | return mutexName + " " + sourceFile + ":" + itostr(sourceLine); |
7f3ccb59 PW |
46 | } |
47 | ||
c649637b GA |
48 | std::string MutexName() const { return mutexName; } |
49 | ||
7f3ccb59 PW |
50 | private: |
51 | std::string mutexName; | |
52 | std::string sourceFile; | |
53 | int sourceLine; | |
54 | }; | |
55 | ||
20e01b1a | 56 | typedef std::vector<std::pair<void*, CLockLocation> > LockStack; |
7f3ccb59 | 57 | |
660ff174 | 58 | static boost::mutex dd_mutex; |
7f3ccb59 PW |
59 | static std::map<std::pair<void*, void*>, LockStack> lockorders; |
60 | static boost::thread_specific_ptr<LockStack> lockstack; | |
61 | ||
62 | ||
63 | static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) | |
64 | { | |
881a85a2 GA |
65 | LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); |
66 | LogPrintf("Previous lock order was:\n"); | |
20e01b1a PW |
67 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) { |
68 | if (i.first == mismatch.first) | |
69 | LogPrintf(" (1)"); | |
70 | if (i.first == mismatch.second) | |
71 | LogPrintf(" (2)"); | |
7d9d134b | 72 | LogPrintf(" %s\n", i.second.ToString()); |
7f3ccb59 | 73 | } |
881a85a2 | 74 | LogPrintf("Current lock order is:\n"); |
20e01b1a PW |
75 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) { |
76 | if (i.first == mismatch.first) | |
77 | LogPrintf(" (1)"); | |
78 | if (i.first == mismatch.second) | |
79 | LogPrintf(" (2)"); | |
7d9d134b | 80 | LogPrintf(" %s\n", i.second.ToString()); |
7f3ccb59 PW |
81 | } |
82 | } | |
83 | ||
84 | static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) | |
85 | { | |
7f3ccb59 PW |
86 | if (lockstack.get() == NULL) |
87 | lockstack.reset(new LockStack); | |
88 | ||
7f3ccb59 PW |
89 | dd_mutex.lock(); |
90 | ||
91 | (*lockstack).push_back(std::make_pair(c, locklocation)); | |
92 | ||
660ff174 | 93 | if (!fTry) { |
20e01b1a PW |
94 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) { |
95 | if (i.first == c) | |
96 | break; | |
660ff174 PW |
97 | |
98 | std::pair<void*, void*> p1 = std::make_pair(i.first, c); | |
99 | if (lockorders.count(p1)) | |
100 | continue; | |
101 | lockorders[p1] = (*lockstack); | |
102 | ||
103 | std::pair<void*, void*> p2 = std::make_pair(c, i.first); | |
20e01b1a | 104 | if (lockorders.count(p2)) { |
660ff174 PW |
105 | potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); |
106 | break; | |
107 | } | |
7f3ccb59 PW |
108 | } |
109 | } | |
110 | dd_mutex.unlock(); | |
111 | } | |
112 | ||
113 | static void pop_lock() | |
114 | { | |
7f3ccb59 PW |
115 | dd_mutex.lock(); |
116 | (*lockstack).pop_back(); | |
117 | dd_mutex.unlock(); | |
118 | } | |
119 | ||
120 | void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) | |
121 | { | |
122 | push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); | |
123 | } | |
124 | ||
125 | void LeaveCritical() | |
126 | { | |
127 | pop_lock(); | |
128 | } | |
129 | ||
c649637b GA |
130 | std::string LocksHeld() |
131 | { | |
132 | std::string result; | |
20e01b1a | 133 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack) |
c649637b GA |
134 | result += i.second.ToString() + std::string("\n"); |
135 | return result; | |
136 | } | |
137 | ||
20e01b1a | 138 | void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) |
c649637b | 139 | { |
20e01b1a PW |
140 | BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack) |
141 | if (i.first == cs) | |
142 | return; | |
143 | fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str()); | |
ca4cf5cf | 144 | abort(); |
c649637b GA |
145 | } |
146 | ||
7f3ccb59 | 147 | #endif /* DEBUG_LOCKORDER */ |