Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

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 <memory>
8 #include <set>
9 #include <util.h>
10 #include <utilstrencodings.h>
11 
12 #include <stdio.h>
13 
14 #ifdef DEBUG_LOCKCONTENTION
15 #if !defined(HAVE_THREAD_LOCAL)
16 static_assert(false, "thread_local is not supported");
17 #endif
18 void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
19 {
20  LogPrintf("LOCKCONTENTION: %s Locker: %s:%d\n", pszName, pszFile, nLine);
21 }
22 #endif /* DEBUG_LOCKCONTENTION */
23 
24 #ifdef DEBUG_LOCKORDER
25 //
26 // Early deadlock detection.
27 // Problem being solved:
28 // Thread 1 locks A, then B, then C
29 // Thread 2 locks D, then C, then A
30 // --> may result in deadlock between the two threads, depending on when they run.
31 // Solution implemented here:
32 // Keep track of pairs of locks: (A before B), (A before C), etc.
33 // Complain if any thread tries to lock in a different order.
34 //
35 
36 struct CLockLocation {
37  CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
38  {
39  mutexName = pszName;
40  sourceFile = pszFile;
41  sourceLine = nLine;
42  fTry = fTryIn;
43  }
44 
45  std::string ToString() const
46  {
47  return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
48  }
49 
50 private:
51  bool fTry;
52  std::string mutexName;
53  std::string sourceFile;
54  int sourceLine;
55 };
56 
57 typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
58 typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
59 typedef std::set<std::pair<void*, void*> > InvLockOrders;
60 
61 struct LockData {
62  // Very ugly hack: as the global constructs and destructors run single
63  // threaded, we use this boolean to know whether LockData still exists,
64  // as DeleteLock can get called by global CCriticalSection destructors
65  // after LockData disappears.
66  bool available;
67  LockData() : available(true) {}
68  ~LockData() { available = false; }
69 
70  LockOrders lockorders;
71  InvLockOrders invlockorders;
72  std::mutex dd_mutex;
73 } static lockdata;
74 
75 static thread_local std::unique_ptr<LockStack> lockstack;
76 
77 static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
78 {
79  std::string strOutput = "";
80  strOutput += "POTENTIAL DEADLOCK DETECTED\n";
81  strOutput += "Previous lock order was:\n";
82  for (const std::pair<void*, CLockLocation> & i : s2) {
83  if (i.first == mismatch.first) {
84  strOutput += " (1)";
85  }
86  if (i.first == mismatch.second) {
87  strOutput += " (2)";
88  }
89  strOutput += strprintf(" %s\n", i.second.ToString().c_str());
90  }
91  strOutput += "Current lock order is:\n";
92  for (const std::pair<void*, CLockLocation> & i : s1) {
93  if (i.first == mismatch.first) {
94  strOutput += " (1)";
95  }
96  if (i.first == mismatch.second) {
97  strOutput += " (2)";
98  }
99  strOutput += strprintf(" %s\n", i.second.ToString().c_str());
100  }
101 
102  printf("%s\n", strOutput.c_str());
103  LogPrintf("%s\n", strOutput.c_str());
104 
105  assert(false);
106 }
107 
108 static void push_lock(void* c, const CLockLocation& locklocation)
109 {
110  if (!lockstack)
111  lockstack.reset(new LockStack);
112 
113  std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
114 
115  lockstack->push_back(std::make_pair(c, locklocation));
116 
117  for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
118  if (i.first == c)
119  break;
120 
121  std::pair<void*, void*> p1 = std::make_pair(i.first, c);
122  if (lockdata.lockorders.count(p1))
123  continue;
124  lockdata.lockorders[p1] = (*lockstack);
125 
126  std::pair<void*, void*> p2 = std::make_pair(c, i.first);
127  lockdata.invlockorders.insert(p2);
128  if (lockdata.lockorders.count(p2))
129  potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
130  }
131 }
132 
133 static void pop_lock()
134 {
135  (*lockstack).pop_back();
136 }
137 
138 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
139 {
140  push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry));
141 }
142 
143 void LeaveCritical()
144 {
145  pop_lock();
146 }
147 
148 std::string LocksHeld()
149 {
150  std::string result;
151  for (const std::pair<void*, CLockLocation> & i : *lockstack)
152  result += i.second.ToString() + std::string("\n");
153  return result;
154 }
155 
156 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
157 {
158  for (const std::pair<void*, CLockLocation> & i : *lockstack)
159  if (i.first == cs)
160  return;
161  fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
162  abort();
163 }
164 
165 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
166 {
167  for (const std::pair<void*, CLockLocation>& i : *lockstack) {
168  if (i.first == cs) {
169  fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
170  abort();
171  }
172  }
173 }
174 
175 void DeleteLock(void* cs)
176 {
177  if (!lockdata.available) {
178  // We're already shutting down.
179  return;
180  }
181  std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
182  std::pair<void*, void*> item = std::make_pair(cs, nullptr);
183  LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
184  while (it != lockdata.lockorders.end() && it->first.first == cs) {
185  std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
186  lockdata.invlockorders.erase(invitem);
187  lockdata.lockorders.erase(it++);
188  }
189  InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
190  while (invit != lockdata.invlockorders.end() && invit->first == cs) {
191  std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
192  lockdata.lockorders.erase(invinvitem);
193  lockdata.invlockorders.erase(invit++);
194  }
195 }
196 
197 #endif /* DEBUG_LOCKORDER */
static void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs)
Definition: sync.h:84
#define strprintf
Definition: tinyformat.h:1066
false true true true
Definition: bls_dkg.cpp:176
#define LogPrintf(...)
Definition: util.h:203
static void DeleteLock(void *cs)
Definition: sync.h:85
static void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs)
Definition: sync.h:83
static void EnterCritical(const char *pszName, const char *pszFile, int nLine, void *cs, bool fTry=false)
Definition: sync.h:81
static void LeaveCritical()
Definition: sync.h:82
void printf(const char *fmt, const Args &... args)
Format list of arguments to std::cout, according to the given format string.
Definition: tinyformat.h:984
std::string itostr(int n)
Released under the MIT license