aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2011-08-22 14:43:37 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2011-08-22 14:43:37 +0200
commitadce862c2795142a5f56933584abffdbe3599472 (patch)
treed181162faf9da3ed5c480983aab3a363784e7589 /src
parent872b1f3e4c15de16fd821ab0adde9697a9e8d925 (diff)
parent865ed8a1e5c587468a40756d46bcbc1c5a12bb06 (diff)
Merge branch 'master' of https://github.com/bitcoin/bitcoin
Diffstat (limited to 'src')
-rw-r--r--src/main.cpp41
-rw-r--r--src/makefile.unix2
-rw-r--r--src/net.h2
-rw-r--r--src/util.cpp118
-rw-r--r--src/util.h56
5 files changed, 150 insertions, 69 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 3647f90fe3..4d668b6ffb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1385,47 +1385,6 @@ bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
-template<typename Stream>
-bool static ScanMessageStart(Stream& s)
-{
- // Scan ahead to the next pchMessageStart, which should normally be immediately
- // at the file pointer. Leaves file pointer at end of pchMessageStart.
- s.clear(0);
- short prevmask = s.exceptions(0);
- const char* p = BEGIN(pchMessageStart);
- try
- {
- loop
- {
- char c;
- s.read(&c, 1);
- if (s.fail())
- {
- s.clear(0);
- s.exceptions(prevmask);
- return false;
- }
- if (*p != c)
- p = BEGIN(pchMessageStart);
- if (*p == c)
- {
- if (++p == END(pchMessageStart))
- {
- s.clear(0);
- s.exceptions(prevmask);
- return true;
- }
- }
- }
- }
- catch (...)
- {
- s.clear(0);
- s.exceptions(prevmask);
- return false;
- }
-}
-
bool CheckDiskSpace(uint64 nAdditionalBytes)
{
uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
diff --git a/src/makefile.unix b/src/makefile.unix
index ba9d0ca11d..4c92797292 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -10,7 +10,7 @@ WXLIBS=$(shell wx-config --libs)
USE_UPNP:=0
-DEFS=-DNOPCH -DFOURWAYSSE2 -DUSE_SSL
+DEFS=-DNOPCH -DUSE_SSL
# for boost 1.37, add -mt to the boost libraries
LIBS= \
diff --git a/src/net.h b/src/net.h
index 37fab7f8b0..3b098e1a82 100644
--- a/src/net.h
+++ b/src/net.h
@@ -677,7 +677,7 @@ public:
void BeginMessage(const char* pszCommand)
{
- cs_vSend.Enter();
+ cs_vSend.Enter("cs_vSend", __FILE__, __LINE__);
if (nHeaderStart != -1)
AbortMessage();
nHeaderStart = vSend.size();
diff --git a/src/util.cpp b/src/util.cpp
index 8a8ccabee8..974e54c391 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -907,4 +907,122 @@ string FormatFullVersion()
+#ifdef DEBUG_LOCKORDER
+//
+// Early deadlock detection.
+// Problem being solved:
+// Thread 1 locks A, then B, then C
+// Thread 2 locks D, then C, then A
+// --> may result in deadlock between the two threads, depending on when they run.
+// Solution implemented here:
+// Keep track of pairs of locks: (A before B), (A before C), etc.
+// Complain if any thread trys to lock in a different order.
+//
+
+struct CLockLocation
+{
+ std::string mutexName;
+ std::string sourceFile;
+ int sourceLine;
+
+ CLockLocation(const char* pszName, const char* pszFile, int nLine)
+ {
+ mutexName = pszName;
+ sourceFile = pszFile;
+ sourceLine = nLine;
+ }
+};
+
+typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack;
+
+static boost::interprocess::interprocess_mutex dd_mutex;
+static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders;
+static boost::thread_specific_ptr<LockStack> lockstack;
+
+
+static void potential_deadlock_detected(const LockStack& s1, const LockStack& s2)
+{
+ printf("POTENTIAL DEADLOCK DETECTED\n");
+ printf("Previous lock order was:\n");
+ BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2)
+ {
+ printf(" %s %s:%d\n", i.second.mutexName.c_str(), i.second.sourceFile.c_str(), i.second.sourceLine);
+ }
+ printf("Current lock order is:\n");
+ BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1)
+ {
+ printf(" %s %s:%d\n", i.second.mutexName.c_str(), i.second.sourceFile.c_str(), i.second.sourceLine);
+ }
+}
+
+static void push_lock(CCriticalSection* c, const CLockLocation& locklocation)
+{
+ bool fOrderOK = true;
+ if (lockstack.get() == NULL)
+ lockstack.reset(new LockStack);
+
+ dd_mutex.lock();
+
+ (*lockstack).push_back(std::make_pair(c, locklocation));
+
+ BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack))
+ {
+ if (i.first == c) break;
+
+ std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c);
+ if (lockorders.count(p1))
+ continue;
+ lockorders[p1] = (*lockstack);
+
+ std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first);
+ if (lockorders.count(p2))
+ {
+ potential_deadlock_detected(lockorders[p2], lockorders[p1]);
+ break;
+ }
+ }
+ dd_mutex.unlock();
+}
+
+static void pop_lock()
+{
+ (*lockstack).pop_back();
+}
+
+void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
+{
+ push_lock(this, CLockLocation(pszName, pszFile, nLine));
+ mutex.lock();
+}
+void CCriticalSection::Leave()
+{
+ mutex.unlock();
+ pop_lock();
+}
+bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine)
+{
+ push_lock(this, CLockLocation(pszName, pszFile, nLine));
+ bool result = mutex.try_lock();
+ if (!result) pop_lock();
+ return result;
+}
+
+#else
+
+void CCriticalSection::Enter(const char*, const char*, int)
+{
+ mutex.lock();
+}
+
+void CCriticalSection::Leave()
+{
+ mutex.unlock();
+}
+
+bool CCriticalSection::TryEnter(const char*, const char*, int)
+{
+ bool result = mutex.try_lock();
+ return result;
+}
+#endif /* DEBUG_LOCKORDER */
diff --git a/src/util.h b/src/util.h
index 028538e9ae..7fd224cbe7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -221,31 +221,17 @@ std::string FormatFullVersion();
-// Wrapper to automatically initialize critical sections
+// Wrapper to automatically initialize mutex
class CCriticalSection
{
-#ifdef __WXMSW__
-protected:
- CRITICAL_SECTION cs;
-public:
- explicit CCriticalSection() { InitializeCriticalSection(&cs); }
- ~CCriticalSection() { DeleteCriticalSection(&cs); }
- void Enter() { EnterCriticalSection(&cs); }
- void Leave() { LeaveCriticalSection(&cs); }
- bool TryEnter() { return TryEnterCriticalSection(&cs); }
-#else
protected:
boost::interprocess::interprocess_recursive_mutex mutex;
public:
explicit CCriticalSection() { }
~CCriticalSection() { }
- void Enter() { mutex.lock(); }
- void Leave() { mutex.unlock(); }
- bool TryEnter() { return mutex.try_lock(); }
-#endif
-public:
- const char* pszFile;
- int nLine;
+ void Enter(const char* pszName, const char* pszFile, int nLine);
+ void Leave();
+ bool TryEnter(const char* pszName, const char* pszFile, int nLine);
};
// Automatically leave critical section when leaving block, needed for exception safety
@@ -253,9 +239,17 @@ class CCriticalBlock
{
protected:
CCriticalSection* pcs;
+
public:
- CCriticalBlock(CCriticalSection& csIn) { pcs = &csIn; pcs->Enter(); }
- ~CCriticalBlock() { pcs->Leave(); }
+ CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
+ {
+ pcs = &csIn;
+ pcs->Enter(pszName, pszFile, nLine);
+ }
+ ~CCriticalBlock()
+ {
+ pcs->Leave();
+ }
};
// WARNING: This will catch continue and break!
@@ -263,22 +257,32 @@ public:
// I'd rather be careful than suffer the other more error prone syntax.
// The compiler will optimise away all this loop junk.
#define CRITICAL_BLOCK(cs) \
- for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \
- for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
+ for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!" && !fcriticalblockonce)), fcriticalblockonce=false) \
+ for (CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__); fcriticalblockonce; fcriticalblockonce=false)
class CTryCriticalBlock
{
protected:
CCriticalSection* pcs;
+
public:
- CTryCriticalBlock(CCriticalSection& csIn) { pcs = (csIn.TryEnter() ? &csIn : NULL); }
- ~CTryCriticalBlock() { if (pcs) pcs->Leave(); }
+ CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
+ {
+ pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL);
+ }
+ ~CTryCriticalBlock()
+ {
+ if (pcs)
+ {
+ pcs->Leave();
+ }
+ }
bool Entered() { return pcs != NULL; }
};
#define TRY_CRITICAL_BLOCK(cs) \
- for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by TRY_CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \
- for (CTryCriticalBlock criticalblock(cs); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()) && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
+ for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!" && !fcriticalblockonce)), fcriticalblockonce=false) \
+ for (CTryCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()); fcriticalblockonce=false)