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