Raven Core  3.0.0
P2P Digital Currency
sync.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Copyright (c) 2017-2019 The Raven Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "sync.h"
7 
8 #include "util.h"
9 #include "utilstrencodings.h"
10 
11 #include <stdio.h>
12 
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\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 {
36  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 
44  std::string ToString() const
45  {
46  return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
47  }
48 
49  bool fTry;
50 private:
51  std::string mutexName;
52  std::string sourceFile;
53  int sourceLine;
54 };
55 
56 typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
57 typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
58 typedef std::set<std::pair<void*, void*> > InvLockOrders;
59 
60 struct LockData {
61  // Very ugly hack: as the global constructs and destructors run single
62  // threaded, we use this boolean to know whether LockData still exists,
63  // as DeleteLock can get called by global CCriticalSection destructors
64  // after LockData disappears.
65  bool available;
66  LockData() : available(true) {}
67  ~LockData() { available = false; }
68 
69  LockOrders lockorders;
70  InvLockOrders invlockorders;
71  boost::mutex dd_mutex;
72 } static lockdata;
73 
74 boost::thread_specific_ptr<LockStack> lockstack;
75 
76 static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
77 {
78  LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
79  LogPrintf("Previous lock order was:\n");
80  for (const std::pair<void*, CLockLocation> & i : s2) {
81  if (i.first == mismatch.first) {
82  LogPrintf(" (1)");
83  }
84  if (i.first == mismatch.second) {
85  LogPrintf(" (2)");
86  }
87  LogPrintf(" %s\n", i.second.ToString());
88  }
89  LogPrintf("Current lock order is:\n");
90  for (const std::pair<void*, CLockLocation> & i : s1) {
91  if (i.first == mismatch.first) {
92  LogPrintf(" (1)");
93  }
94  if (i.first == mismatch.second) {
95  LogPrintf(" (2)");
96  }
97  LogPrintf(" %s\n", i.second.ToString());
98  }
99  assert(false);
100 }
101 
102 static void push_lock(void* c, const CLockLocation& locklocation)
103 {
104  if (lockstack.get() == nullptr)
105  lockstack.reset(new LockStack);
106 
107  boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
108 
109  (*lockstack).push_back(std::make_pair(c, locklocation));
110 
111  for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
112  if (i.first == c)
113  break;
114 
115  std::pair<void*, void*> p1 = std::make_pair(i.first, c);
116  if (lockdata.lockorders.count(p1))
117  continue;
118  lockdata.lockorders[p1] = (*lockstack);
119 
120  std::pair<void*, void*> p2 = std::make_pair(c, i.first);
121  lockdata.invlockorders.insert(p2);
122  if (lockdata.lockorders.count(p2))
123  potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
124  }
125 }
126 
127 static void pop_lock()
128 {
129  (*lockstack).pop_back();
130 }
131 
132 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
133 {
134  push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry));
135 }
136 
137 void LeaveCritical()
138 {
139  pop_lock();
140 }
141 
142 std::string LocksHeld()
143 {
144  std::string result;
145  for (const std::pair<void*, CLockLocation> & i : *lockstack)
146  result += i.second.ToString() + std::string("\n");
147  return result;
148 }
149 
150 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
151 {
152  for (const std::pair<void*, CLockLocation> & i : *lockstack)
153  if (i.first == cs)
154  return;
155  fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
156  abort();
157 }
158 
159 void DeleteLock(void* cs)
160 {
161  if (!lockdata.available) {
162  // We're already shutting down.
163  return;
164  }
165  boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
166  std::pair<void*, void*> item = std::make_pair(cs, nullptr);
167  LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
168  while (it != lockdata.lockorders.end() && it->first.first == cs) {
169  std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
170  lockdata.invlockorders.erase(invitem);
171  lockdata.lockorders.erase(it++);
172  }
173  InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
174  while (invit != lockdata.invlockorders.end() && invit->first == cs) {
175  std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
176  lockdata.lockorders.erase(invinvitem);
177  lockdata.invlockorders.erase(invit++);
178  }
179 }
180 
181 #endif /* DEBUG_LOCKORDER */
#define s2
Definition: sph_hamsi.c:214
#define LogPrintf(...)
Definition: util.h:149
#define s1(x)
Definition: sha2.c:57
std::string itostr(int n)