Remove boost foreach macro
[novacoin.git] / src / sync.cpp
1 // Copyright (c) 2011-2012 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "sync.h"
6 #include "util.h"
7
8
9 #ifdef DEBUG_LOCKCONTENTION
10 void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
11 {
12     printf("LOCKCONTENTION: %s\n", pszName);
13     printf("Locker: %s:%d\n", pszFile, nLine);
14 }
15 #endif /* DEBUG_LOCKCONTENTION */
16
17 #ifdef DEBUG_LOCKORDER
18 //
19 // Early deadlock detection.
20 // Problem being solved:
21 //    Thread 1 locks  A, then B, then C
22 //    Thread 2 locks  D, then C, then A
23 //     --> may result in deadlock between the two threads, depending on when they run.
24 // Solution implemented here:
25 // Keep track of pairs of locks: (A before B), (A before C), etc.
26 // Complain if any thread tries to lock in a different order.
27 //
28
29 struct CLockLocation
30 {
31     CLockLocation(const char* pszName, const char* pszFile, int nLine)
32     {
33         mutexName = pszName;
34         sourceFile = pszFile;
35         sourceLine = nLine;
36     }
37
38     std::string ToString() const
39     {
40         return mutexName+"  "+sourceFile+":"+itostr(sourceLine);
41     }
42
43 private:
44     std::string mutexName;
45     std::string sourceFile;
46     int sourceLine;
47 };
48
49 typedef std::vector< std::pair<void*, CLockLocation> > LockStack;
50
51 static boost::mutex dd_mutex;
52 static std::map<std::pair<void*, void*>, LockStack> lockorders;
53 static boost::thread_specific_ptr<LockStack> lockstack;
54
55
56 static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
57 {
58     printf("POTENTIAL DEADLOCK DETECTED\n");
59     printf("Previous lock order was:\n");
60     for (const auto& i : s2)
61     {
62         if (i.first == mismatch.first) printf(" (1)");
63         if (i.first == mismatch.second) printf(" (2)");
64         printf(" %s\n", i.second.ToString().c_str());
65     }
66     printf("Current lock order is:\n");
67     for (const auto& i : s1)
68     {
69         if (i.first == mismatch.first) printf(" (1)");
70         if (i.first == mismatch.second) printf(" (2)");
71         printf(" %s\n", i.second.ToString().c_str());
72     }
73 }
74
75 static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
76 {
77     if (lockstack.get() == NULL)
78         lockstack.reset(new LockStack);
79
80     if (fDebug) printf("Locking: %s\n", locklocation.ToString().c_str());
81     dd_mutex.lock();
82
83     (*lockstack).push_back(std::make_pair(c, locklocation));
84
85     if (!fTry) {
86         for (const auto& i : (*lockstack)) {
87             if (i.first == c) break;
88
89             std::pair<void*, void*> p1 = std::make_pair(i.first, c);
90             if (lockorders.count(p1))
91                 continue;
92             lockorders[p1] = (*lockstack);
93
94             std::pair<void*, void*> p2 = std::make_pair(c, i.first);
95             if (lockorders.count(p2))
96             {
97                 potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
98                 break;
99             }
100         }
101     }
102     dd_mutex.unlock();
103 }
104
105 static void pop_lock()
106 {
107     if (fDebug)
108     {
109         const CLockLocation& locklocation = (*lockstack).rbegin()->second;
110         printf("Unlocked: %s\n", locklocation.ToString().c_str());
111     }
112     dd_mutex.lock();
113     (*lockstack).pop_back();
114     dd_mutex.unlock();
115 }
116
117 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
118 {
119     push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
120 }
121
122 void LeaveCritical()
123 {
124     pop_lock();
125 }
126
127 #endif /* DEBUG_LOCKORDER */