This commit is contained in:
Wladimir J. van der Laan 2011-08-22 14:43:37 +02:00
commit adce862c27
5 changed files with 150 additions and 69 deletions

View file

@ -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) bool CheckDiskSpace(uint64 nAdditionalBytes)
{ {
uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available; uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;

View file

@ -10,7 +10,7 @@ WXLIBS=$(shell wx-config --libs)
USE_UPNP:=0 USE_UPNP:=0
DEFS=-DNOPCH -DFOURWAYSSE2 -DUSE_SSL DEFS=-DNOPCH -DUSE_SSL
# for boost 1.37, add -mt to the boost libraries # for boost 1.37, add -mt to the boost libraries
LIBS= \ LIBS= \

View file

@ -677,7 +677,7 @@ public:
void BeginMessage(const char* pszCommand) void BeginMessage(const char* pszCommand)
{ {
cs_vSend.Enter(); cs_vSend.Enter("cs_vSend", __FILE__, __LINE__);
if (nHeaderStart != -1) if (nHeaderStart != -1)
AbortMessage(); AbortMessage();
nHeaderStart = vSend.size(); nHeaderStart = vSend.size();

View file

@ -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 */

View file

@ -221,31 +221,17 @@ std::string FormatFullVersion();
// Wrapper to automatically initialize critical sections // Wrapper to automatically initialize mutex
class CCriticalSection 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: protected:
boost::interprocess::interprocess_recursive_mutex mutex; boost::interprocess::interprocess_recursive_mutex mutex;
public: public:
explicit CCriticalSection() { } explicit CCriticalSection() { }
~CCriticalSection() { } ~CCriticalSection() { }
void Enter() { mutex.lock(); } void Enter(const char* pszName, const char* pszFile, int nLine);
void Leave() { mutex.unlock(); } void Leave();
bool TryEnter() { return mutex.try_lock(); } bool TryEnter(const char* pszName, const char* pszFile, int nLine);
#endif
public:
const char* pszFile;
int nLine;
}; };
// Automatically leave critical section when leaving block, needed for exception safety // Automatically leave critical section when leaving block, needed for exception safety
@ -253,9 +239,17 @@ class CCriticalBlock
{ {
protected: protected:
CCriticalSection* pcs; CCriticalSection* pcs;
public: public:
CCriticalBlock(CCriticalSection& csIn) { pcs = &csIn; pcs->Enter(); } CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
~CCriticalBlock() { pcs->Leave(); } {
pcs = &csIn;
pcs->Enter(pszName, pszFile, nLine);
}
~CCriticalBlock()
{
pcs->Leave();
}
}; };
// WARNING: This will catch continue and break! // 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. // I'd rather be careful than suffer the other more error prone syntax.
// The compiler will optimise away all this loop junk. // The compiler will optimise away all this loop junk.
#define CRITICAL_BLOCK(cs) \ #define CRITICAL_BLOCK(cs) \
for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \ 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 (CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__); fcriticalblockonce; fcriticalblockonce=false)
class CTryCriticalBlock class CTryCriticalBlock
{ {
protected: protected:
CCriticalSection* pcs; CCriticalSection* pcs;
public: public:
CTryCriticalBlock(CCriticalSection& csIn) { pcs = (csIn.TryEnter() ? &csIn : NULL); } CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
~CTryCriticalBlock() { if (pcs) pcs->Leave(); } {
pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL);
}
~CTryCriticalBlock()
{
if (pcs)
{
pcs->Leave();
}
}
bool Entered() { return pcs != NULL; } bool Entered() { return pcs != NULL; }
}; };
#define TRY_CRITICAL_BLOCK(cs) \ #define TRY_CRITICAL_BLOCK(cs) \
for (bool fcriticalblockonce=true; fcriticalblockonce; assert("break caught by TRY_CRITICAL_BLOCK!" && !fcriticalblockonce), fcriticalblockonce=false) \ 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 (CTryCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()); fcriticalblockonce=false)