Merge branch 'master' of https://github.com/bitcoin/bitcoin
authorWladimir J. van der Laan <laanwj@gmail.com>
Mon, 22 Aug 2011 12:43:37 +0000 (14:43 +0200)
committerWladimir J. van der Laan <laanwj@gmail.com>
Mon, 22 Aug 2011 12:43:37 +0000 (14:43 +0200)
1  2 
src/main.cpp
src/util.cpp
src/util.h

diff --combined src/main.cpp
@@@ -30,7 -30,7 +30,7 @@@ map<COutPoint, CInPoint> mapNextTx
  map<uint256, CBlockIndex*> mapBlockIndex;
  uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
  CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
 -const int nTotalBlocksEstimate = 134444; // Conservative estimate of total nr of blocks on main chain
 +int nTotalBlocksEstimate = 134444; // Conservative estimate of total nr of blocks on main chain
  const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
  CBlockIndex* pindexGenesisBlock = NULL;
  int nBestHeight = -1;
@@@ -1385,47 -1385,6 +1385,6 @@@ bool static ProcessBlock(CNode* pfrom, 
  
  
  
- 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;
@@@ -1876,10 -1835,6 +1835,10 @@@ bool static ProcessMessage(CNode* pfrom
          pfrom->fSuccessfullyConnected = true;
  
          printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
 +        if(pfrom->nStartingHeight > nTotalBlocksEstimate)
 +        {
 +            nTotalBlocksEstimate = pfrom->nStartingHeight;
 +        }
      }
  
  
diff --combined src/util.cpp
@@@ -264,7 -264,8 +264,7 @@@ int my_snprintf(char* buffer, size_t li
      return ret;
  }
  
 -
 -string strprintf(const char* format, ...)
 +string strprintf(const std::string &format, ...)
  {
      char buffer[50000];
      char* p = buffer;
      {
          va_list arg_ptr;
          va_start(arg_ptr, format);
 -        ret = _vsnprintf(p, limit, format, arg_ptr);
 +        ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
          va_end(arg_ptr);
          if (ret >= 0 && ret < limit)
              break;
      return str;
  }
  
 -
 -bool error(const char* format, ...)
 +bool error(const std::string &format, ...)
  {
      char buffer[50000];
      int limit = sizeof(buffer);
      va_list arg_ptr;
      va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
 +    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
@@@ -907,4 -909,122 +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 --combined src/util.h
@@@ -65,7 -65,7 +65,7 @@@ typedef unsigned long long  uint64
  #endif
  
  // This is needed because the foreach macro can't get over the comma in pair<t1, t2>
 -#define PAIRTYPE(t1, t2)    pair<t1, t2>
 +#define PAIRTYPE(t1, t2)    std::pair<t1, t2>
  
  // Used to bypass the rule against non-const reference to temporary
  // where it makes sense with wrappers such as CFlatData or CTxDB
@@@ -140,7 -140,8 +140,7 @@@ inline int myclosesocket(SOCKET& hSocke
      return ret;
  }
  #define closesocket(s)      myclosesocket(s)
 -
 -#ifndef GUI
 +#if !defined(QT_GUI) && !defined(GUI)
  inline const char* _(const char* psz)
  {
      return psz;
  
  
  
 -
  extern std::map<std::string, std::string> mapArgs;
  extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
  extern bool fDebug;
@@@ -175,8 -177,8 +175,8 @@@ void RandAddSeed()
  void RandAddSeedPerfmon();
  int OutputDebugStringF(const char* pszFormat, ...);
  int my_snprintf(char* buffer, size_t limit, const char* format, ...);
 -std::string strprintf(const char* format, ...);
 -bool error(const char* format, ...);
 +std::string strprintf(const std::string &format, ...);
 +bool error(const std::string &format, ...);
  void LogException(std::exception* pex, const char* pszThread);
  void PrintException(std::exception* pex, const char* pszThread);
  void PrintExceptionContinue(std::exception* pex, const char* pszThread);
@@@ -221,31 -223,17 +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 -241,17 +239,17 @@@ class CCriticalBloc
  {
  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!
  // 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)