1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "sync.h"
6 
7 #include "util.h"
8 #include "utilstrencodings.h"
9 
10 #include <stdio.h>
11 
12 #include <boost/foreach.hpp>
13 #include <boost/thread.hpp>
14 
15 #ifdef DEBUG_LOCKCONTENTION
PrintLockContention(const char * pszName,const char * pszFile,int nLine)16 void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
17 {
18     LogPrintf("LOCKCONTENTION: %s\n", pszName);
19     LogPrintf("Locker: %s:%d\n", pszFile, nLine);
20 }
21 #endif /* DEBUG_LOCKCONTENTION */
22 
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.
32 // Complain if any thread tries to lock in a different order.
33 //
34 
35 struct CLockLocation {
CLockLocationCLockLocation36     CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
37     {
38         mutexName = pszName;
39         sourceFile = pszFile;
40         sourceLine = nLine;
41         fTry = fTryIn;
42     }
43 
ToStringCLockLocation44     std::string ToString() const
45     {
46         return mutexName + "  " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
47     }
48 
MutexNameCLockLocation49     std::string MutexName() const { return mutexName; }
50 
51     bool fTry;
52 private:
53     std::string mutexName;
54     std::string sourceFile;
55     int sourceLine;
56 };
57 
58 typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
59 typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
60 typedef std::set<std::pair<void*, void*> > InvLockOrders;
61 
62 struct LockData {
63     // Very ugly hack: as the global constructs and destructors run single
64     // threaded, we use this boolean to know whether LockData still exists,
65     // as DeleteLock can get called by global CCriticalSection destructors
66     // after LockData disappears.
67     bool available;
LockDataLockData68     LockData() : available(true) {}
~LockDataLockData69     ~LockData() { available = false; }
70 
71     LockOrders lockorders;
72     InvLockOrders invlockorders;
73     boost::mutex dd_mutex;
74 } static lockdata;
75 
76 boost::thread_specific_ptr<LockStack> lockstack;
77 
potential_deadlock_detected(const std::pair<void *,void * > & mismatch,const LockStack & s1,const LockStack & s2)78 static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
79 {
80     // We attempt to not assert on probably-not deadlocks by assuming that
81     // a try lock will immediately have otherwise bailed if it had
82     // failed to get the lock
83     // We do this by, for the locks which triggered the potential deadlock,
84     // in either lockorder, checking that the second of the two which is locked
85     // is only a TRY_LOCK, ignoring locks if they are reentrant.
86     bool firstLocked = false;
87     bool secondLocked = false;
88     bool onlyMaybeDeadlock = false;
89 
90     LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
91     LogPrintf("Previous lock order was:\n");
92     BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
93         if (i.first == mismatch.first) {
94             LogPrintf(" (1)");
95             if (!firstLocked && secondLocked && i.second.fTry)
96                 onlyMaybeDeadlock = true;
97             firstLocked = true;
98         }
99         if (i.first == mismatch.second) {
100             LogPrintf(" (2)");
101             if (!secondLocked && firstLocked && i.second.fTry)
102                 onlyMaybeDeadlock = true;
103             secondLocked = true;
104         }
105         LogPrintf(" %s\n", i.second.ToString());
106     }
107     firstLocked = false;
108     secondLocked = false;
109     LogPrintf("Current lock order is:\n");
110     BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
111         if (i.first == mismatch.first) {
112             LogPrintf(" (1)");
113             if (!firstLocked && secondLocked && i.second.fTry)
114                 onlyMaybeDeadlock = true;
115             firstLocked = true;
116         }
117         if (i.first == mismatch.second) {
118             LogPrintf(" (2)");
119             if (!secondLocked && firstLocked && i.second.fTry)
120                 onlyMaybeDeadlock = true;
121             secondLocked = true;
122         }
123         LogPrintf(" %s\n", i.second.ToString());
124     }
125     assert(onlyMaybeDeadlock);
126 }
127 
push_lock(void * c,const CLockLocation & locklocation,bool fTry)128 static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
129 {
130     if (lockstack.get() == NULL)
131         lockstack.reset(new LockStack);
132 
133     boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
134 
135     (*lockstack).push_back(std::make_pair(c, locklocation));
136 
137     if (!fTry) {
138         BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
139             if (i.first == c)
140                 break;
141 
142             std::pair<void*, void*> p1 = std::make_pair(i.first, c);
143             if (lockdata.lockorders.count(p1))
144                 continue;
145             lockdata.lockorders[p1] = (*lockstack);
146 
147             std::pair<void*, void*> p2 = std::make_pair(c, i.first);
148             lockdata.invlockorders.insert(p2);
149             if (lockdata.lockorders.count(p2))
150                 potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
151         }
152     }
153 }
154 
pop_lock()155 static void pop_lock()
156 {
157     (*lockstack).pop_back();
158 }
159 
EnterCritical(const char * pszName,const char * pszFile,int nLine,void * cs,bool fTry)160 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
161 {
162     push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
163 }
164 
LeaveCritical()165 void LeaveCritical()
166 {
167     pop_lock();
168 }
169 
LocksHeld()170 std::string LocksHeld()
171 {
172     std::string result;
173     BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
174         result += i.second.ToString() + std::string("\n");
175     return result;
176 }
177 
AssertLockHeldInternal(const char * pszName,const char * pszFile,int nLine,void * cs)178 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
179 {
180     BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
181         if (i.first == cs)
182             return;
183     fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
184     abort();
185 }
186 
DeleteLock(void * cs)187 void DeleteLock(void* cs)
188 {
189     if (!lockdata.available) {
190         // We're already shutting down.
191         return;
192     }
193     boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
194     std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
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++);
200     }
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++);
206     }
207 }
208 
209 #endif /* DEBUG_LOCKORDER */
210