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