]>
Commit | Line | Data |
---|---|---|
7f3ccb59 PW |
1 | // Copyright (c) 2011-2012 The Bitcoin developers |
2 | // Distributed under the MIT/X11 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" |
7f3ccb59 | 8 | |
660ff174 | 9 | #include <boost/foreach.hpp> |
7f3ccb59 | 10 | |
4d009243 MC |
11 | #ifdef DEBUG_LOCKCONTENTION |
12 | void PrintLockContention(const char* pszName, const char* pszFile, int nLine) | |
13 | { | |
881a85a2 GA |
14 | LogPrintf("LOCKCONTENTION: %s\n", pszName); |
15 | LogPrintf("Locker: %s:%d\n", pszFile, nLine); | |
4d009243 MC |
16 | } |
17 | #endif /* DEBUG_LOCKCONTENTION */ | |
18 | ||
7f3ccb59 PW |
19 | #ifdef DEBUG_LOCKORDER |
20 | // | |
21 | // Early deadlock detection. | |
22 | // Problem being solved: | |
23 | // Thread 1 locks A, then B, then C | |
24 | // Thread 2 locks D, then C, then A | |
25 | // --> may result in deadlock between the two threads, depending on when they run. | |
26 | // Solution implemented here: | |
27 | // Keep track of pairs of locks: (A before B), (A before C), etc. | |
e7494052 | 28 | // Complain if any thread tries to lock in a different order. |
7f3ccb59 PW |
29 | // |
30 | ||
31 | struct CLockLocation | |
32 | { | |
33 | CLockLocation(const char* pszName, const char* pszFile, int nLine) | |
34 | { | |
35 | mutexName = pszName; | |
36 | sourceFile = pszFile; | |
37 | sourceLine = nLine; | |
38 | } | |
39 | ||
40 | std::string ToString() const | |
41 | { | |
42 | return mutexName+" "+sourceFile+":"+itostr(sourceLine); | |
43 | } | |
44 | ||
c649637b GA |
45 | std::string MutexName() const { return mutexName; } |
46 | ||
7f3ccb59 PW |
47 | private: |
48 | std::string mutexName; | |
49 | std::string sourceFile; | |
50 | int sourceLine; | |
51 | }; | |
52 | ||
53 | typedef std::vector< std::pair<void*, CLockLocation> > LockStack; | |
54 | ||
660ff174 | 55 | static boost::mutex dd_mutex; |
7f3ccb59 PW |
56 | static std::map<std::pair<void*, void*>, LockStack> lockorders; |
57 | static boost::thread_specific_ptr<LockStack> lockstack; | |
58 | ||
59 | ||
60 | static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) | |
61 | { | |
881a85a2 GA |
62 | LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); |
63 | LogPrintf("Previous lock order was:\n"); | |
7f3ccb59 PW |
64 | BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2) |
65 | { | |
881a85a2 GA |
66 | if (i.first == mismatch.first) LogPrintf(" (1)"); |
67 | if (i.first == mismatch.second) LogPrintf(" (2)"); | |
7d9d134b | 68 | LogPrintf(" %s\n", i.second.ToString()); |
7f3ccb59 | 69 | } |
881a85a2 | 70 | LogPrintf("Current lock order is:\n"); |
7f3ccb59 PW |
71 | BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1) |
72 | { | |
881a85a2 GA |
73 | if (i.first == mismatch.first) LogPrintf(" (1)"); |
74 | if (i.first == mismatch.second) LogPrintf(" (2)"); | |
7d9d134b | 75 | LogPrintf(" %s\n", i.second.ToString()); |
7f3ccb59 PW |
76 | } |
77 | } | |
78 | ||
79 | static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) | |
80 | { | |
7f3ccb59 PW |
81 | if (lockstack.get() == NULL) |
82 | lockstack.reset(new LockStack); | |
83 | ||
7d9d134b | 84 | LogPrint("lock", "Locking: %s\n", locklocation.ToString()); |
7f3ccb59 PW |
85 | dd_mutex.lock(); |
86 | ||
87 | (*lockstack).push_back(std::make_pair(c, locklocation)); | |
88 | ||
660ff174 PW |
89 | if (!fTry) { |
90 | BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) { | |
91 | if (i.first == c) break; | |
92 | ||
93 | std::pair<void*, void*> p1 = std::make_pair(i.first, c); | |
94 | if (lockorders.count(p1)) | |
95 | continue; | |
96 | lockorders[p1] = (*lockstack); | |
97 | ||
98 | std::pair<void*, void*> p2 = std::make_pair(c, i.first); | |
99 | if (lockorders.count(p2)) | |
100 | { | |
101 | potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); | |
102 | break; | |
103 | } | |
7f3ccb59 PW |
104 | } |
105 | } | |
106 | dd_mutex.unlock(); | |
107 | } | |
108 | ||
109 | static void pop_lock() | |
110 | { | |
ea0796bd | 111 | if (fDebug) |
7f3ccb59 PW |
112 | { |
113 | const CLockLocation& locklocation = (*lockstack).rbegin()->second; | |
7d9d134b | 114 | LogPrint("lock", "Unlocked: %s\n", locklocation.ToString()); |
7f3ccb59 PW |
115 | } |
116 | dd_mutex.lock(); | |
117 | (*lockstack).pop_back(); | |
118 | dd_mutex.unlock(); | |
119 | } | |
120 | ||
121 | void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) | |
122 | { | |
123 | push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); | |
124 | } | |
125 | ||
126 | void LeaveCritical() | |
127 | { | |
128 | pop_lock(); | |
129 | } | |
130 | ||
c649637b GA |
131 | std::string LocksHeld() |
132 | { | |
133 | std::string result; | |
134 | BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack) | |
135 | result += i.second.ToString() + std::string("\n"); | |
136 | return result; | |
137 | } | |
138 | ||
19a56762 | 139 | void AssertLockHeldInternal(const char *pszName, const char* pszFile, int nLine, void *cs) |
c649637b GA |
140 | { |
141 | BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack) | |
19a56762 | 142 | if (i.first == cs) return; |
ca4cf5cf GA |
143 | fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", |
144 | pszName, pszFile, nLine, LocksHeld().c_str()); | |
145 | abort(); | |
c649637b GA |
146 | } |
147 | ||
7f3ccb59 | 148 | #endif /* DEBUG_LOCKORDER */ |