Dogecoin Core  1.14.2
P2P Digital Currency
sync.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 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\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  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;
68  LockData() : available(true) {}
69  ~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 
78 static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
79 {
80  LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
81  LogPrintf("Previous lock order was:\n");
82  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
83  if (i.first == mismatch.first) {
84  LogPrintf(" (1)");
85  }
86  if (i.first == mismatch.second) {
87  LogPrintf(" (2)");
88  }
89  LogPrintf(" %s\n", i.second.ToString());
90  }
91  LogPrintf("Current lock order is:\n");
92  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
93  if (i.first == mismatch.first) {
94  LogPrintf(" (1)");
95  }
96  if (i.first == mismatch.second) {
97  LogPrintf(" (2)");
98  }
99  LogPrintf(" %s\n", i.second.ToString());
100  }
101  assert(false);
102 }
103 
104 static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
105 {
106  if (lockstack.get() == NULL)
107  lockstack.reset(new LockStack);
108 
109  boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
110 
111  (*lockstack).push_back(std::make_pair(c, locklocation));
112 
113  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, (*lockstack)) {
114  if (i.first == c)
115  break;
116 
117  std::pair<void*, void*> p1 = std::make_pair(i.first, c);
118  if (lockdata.lockorders.count(p1))
119  continue;
120  lockdata.lockorders[p1] = (*lockstack);
121 
122  std::pair<void*, void*> p2 = std::make_pair(c, i.first);
123  lockdata.invlockorders.insert(p2);
124  if (lockdata.lockorders.count(p2))
125  potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
126  }
127 }
128 
129 static void pop_lock()
130 {
131  (*lockstack).pop_back();
132 }
133 
134 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
135 {
136  push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
137 }
138 
139 void LeaveCritical()
140 {
141  pop_lock();
142 }
143 
144 std::string LocksHeld()
145 {
146  std::string result;
147  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
148  result += i.second.ToString() + std::string("\n");
149  return result;
150 }
151 
152 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
153 {
154  BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, *lockstack)
155  if (i.first == cs)
156  return;
157  fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
158  abort();
159 }
160 
161 void DeleteLock(void* cs)
162 {
163  if (!lockdata.available) {
164  // We're already shutting down.
165  return;
166  }
167  boost::unique_lock<boost::mutex> lock(lockdata.dd_mutex);
168  std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
169  LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
170  while (it != lockdata.lockorders.end() && it->first.first == cs) {
171  std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
172  lockdata.invlockorders.erase(invitem);
173  lockdata.lockorders.erase(it++);
174  }
175  InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
176  while (invit != lockdata.invlockorders.end() && invit->first == cs) {
177  std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
178  lockdata.lockorders.erase(invinvitem);
179  lockdata.invlockorders.erase(invit++);
180  }
181 }
182 
183 #endif /* DEBUG_LOCKORDER */
#define LogPrintf(...)
Definition: util.h:82
std::string itostr(int n)
#define PAIRTYPE(t1, t2)
This is needed because the foreach macro can't get over the comma in pair<t1, t2>