Dash Core  0.12.2.1
P2P Digital Currency
sync.cpp
Go to the documentation of this file.
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
16 void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
17 {
18  LogPrintf("LOCKCONTENTION: %s Locker: %s:%d\n", pszName, pszFile, nLine);
19 }
20 #endif /* DEBUG_LOCKCONTENTION */
21 
22 #ifdef DEBUG_LOCKORDER
23 //
24 // Early deadlock detection.
25 // Problem being solved:
26 // Thread 1 locks A, then B, then C
27 // Thread 2 locks D, then C, then A
28 // --> may result in deadlock between the two threads, depending on when they run.
29 // Solution implemented here:
30 // Keep track of pairs of locks: (A before B), (A before C), etc.
31 // Complain if any thread tries to lock in a different order.
32 //
33 
34 struct CLockLocation {
35  CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
36  {
37  mutexName = pszName;
38  sourceFile = pszFile;
39  sourceLine = nLine;
40  fTry = fTryIn;
41  }
42 
43  std::string ToString() const
44  {
45  return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
46  }
47 
48  std::string MutexName() const { return mutexName; }
49 
50  bool fTry;
51 private:
52  std::string mutexName;
53  std::string sourceFile;
54  int sourceLine;
55 };
56 
57 typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
58 
59 static boost::mutex dd_mutex;
60 static std::map<std::pair<void*, void*>, LockStack> lockorders;
61 static boost::thread_specific_ptr<LockStack> lockstack;
62 
63 
64 static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
65 {
66  // We attempt to not assert on probably-not deadlocks by assuming that
67  // a try lock will immediately have otherwise bailed if it had
68  // failed to get the lock
69  // We do this by, for the locks which triggered the potential deadlock,
70  // in either lockorder, checking that the second of the two which is locked
71  // is only a TRY_LOCK, ignoring locks if they are reentrant.
72  bool firstLocked = false;
73  bool secondLocked = false;
74  bool onlyMaybeDeadlock = false;
75  std::string strOutput = "";
76 
77  strOutput += "POTENTIAL DEADLOCK DETECTED\n";
78  strOutput += "Previous lock order was:\n";
79  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
80  if (i.first == mismatch.first) {
81  strOutput += " (1)";
82  if (!firstLocked && secondLocked && i.second.fTry)
83  onlyMaybeDeadlock = true;
84  firstLocked = true;
85  }
86  if (i.first == mismatch.second) {
87  strOutput += " (2)";
88  if (!secondLocked && firstLocked && i.second.fTry)
89  onlyMaybeDeadlock = true;
90  secondLocked = true;
91  }
92  strOutput += strprintf(" %s\n", i.second.ToString().c_str());
93  }
94  firstLocked = false;
95  secondLocked = false;
96  strOutput += "Current lock order is:\n";
97  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
98  if (i.first == mismatch.first) {
99  strOutput += " (1)";
100  if (!firstLocked && secondLocked && i.second.fTry)
101  onlyMaybeDeadlock = true;
102  firstLocked = true;
103  }
104  if (i.first == mismatch.second) {
105  strOutput += " (2)";
106  if (!secondLocked && firstLocked && i.second.fTry)
107  onlyMaybeDeadlock = true;
108  secondLocked = true;
109  }
110  strOutput += strprintf(" %s\n", i.second.ToString().c_str());
111  }
112  if(!onlyMaybeDeadlock) {
113  printf("%s\n", strOutput.c_str());
114  LogPrintf("%s\n", strOutput.c_str());
115  }
116  assert(onlyMaybeDeadlock);
117 }
118 
119 static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
120 {
121  if (lockstack.get() == NULL)
122  lockstack.reset(new LockStack);
123 
124  dd_mutex.lock();
125 
126  (*lockstack).push_back(std::make_pair(c, locklocation));
127 
128  if (!fTry) {
129  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
130  if (i.first == c)
131  break;
132 
133  std::pair<void*, void*> p1 = std::make_pair(i.first, c);
134  if (lockorders.count(p1))
135  continue;
136  lockorders[p1] = (*lockstack);
137 
138  std::pair<void*, void*> p2 = std::make_pair(c, i.first);
139  if (lockorders.count(p2))
140  potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
141  }
142  }
143  dd_mutex.unlock();
144 }
145 
146 static void pop_lock()
147 {
148  dd_mutex.lock();
149  (*lockstack).pop_back();
150  dd_mutex.unlock();
151 }
152 
153 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
154 {
155  push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
156 }
157 
158 void LeaveCritical()
159 {
160  pop_lock();
161 }
162 
163 std::string LocksHeld()
164 {
165  std::string result;
166  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
167  result += i.second.ToString() + std::string("\n");
168  return result;
169 }
170 
171 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
172 {
173  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
174  if (i.first == cs)
175  return;
176  fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
177  abort();
178 }
179 
180 #endif /* DEBUG_LOCKORDER */
#define strprintf
Definition: tinyformat.h:1011
#define LogPrintf(...)
Definition: util.h:98
static void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs)
Definition: sync.h:94
static void EnterCritical(const char *pszName, const char *pszFile, int nLine, void *cs, bool fTry=false)
Definition: sync.h:92
static void LeaveCritical()
Definition: sync.h:93
#define PAIRTYPE(t1, t2)
std::string itostr(int n)
result
Definition: rpcuser.py:37