changeset 2982:ab55014c4119 draft

Merge remote branch 'origin/0.6.2' into 0.6.x Conflicts: src/addrman.cpp
author Luke Dashjr <luke-jr+git@utopios.org>
date Tue, 15 May 2012 07:23:32 +0000
parents 73ad3a07a95a (current diff) 344164d72a38 (diff)
children 05cc429f7bf9
files bitcoin-qt.pro doc/README doc/README_windows.txt share/setup.nsi src/addrman.cpp src/addrman.h src/net.cpp src/net.h src/util.h
diffstat 9 files changed, 111 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -1,6 +1,6 @@
 TEMPLATE = app
 TARGET =
-VERSION = 0.6.1
+VERSION = 0.6.2.2
 INCLUDEPATH += src src/json src/qt
 DEFINES += QT_GUI BOOST_THREAD_USE_LIB
 CONFIG += no_include_pwd
--- a/doc/README
+++ b/doc/README
@@ -1,4 +1,4 @@
-Bitcoin 0.6.1 BETA
+Bitcoin 0.6.2 BETA
 
 Copyright (c) 2009-2012 Bitcoin Developers
 Distributed under the MIT/X11 software license, see the accompanying
--- a/doc/README_windows.txt
+++ b/doc/README_windows.txt
@@ -1,4 +1,4 @@
-Bitcoin 0.6.1 BETA
+Bitcoin 0.6.2 BETA
 
 Copyright (c) 2009-2012 Bitcoin Developers
 Distributed under the MIT/X11 software license, see the accompanying
--- a/share/setup.nsi
+++ b/share/setup.nsi
@@ -5,7 +5,7 @@
 
 # General Symbol Definitions
 !define REGKEY "SOFTWARE\$(^Name)"
-!define VERSION 0.6.1
+!define VERSION 0.6.2
 !define COMPANY "Bitcoin project"
 !define URL http://www.bitcoin.org/
 
@@ -45,13 +45,13 @@
 !insertmacro MUI_LANGUAGE English
 
 # Installer attributes
-OutFile bitcoin-0.6.1-win32-setup.exe
+OutFile bitcoin-0.6.2-win32-setup.exe
 InstallDir $PROGRAMFILES\Bitcoin
 CRCCheck on
 XPStyle on
 BrandingText " "
 ShowInstDetails show
-VIProductVersion 0.6.1.3
+VIProductVersion 0.6.2.0
 VIAddVersionKey ProductName Bitcoin
 VIAddVersionKey ProductVersion "${VERSION}"
 VIAddVersionKey CompanyName "${COMPANY}"
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -107,9 +107,15 @@
     if (nRndPos1 == nRndPos2)
         return;
 
+    assert(nRndPos1 >= 0 && nRndPos2 >= 0);
+    assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
+
     int nId1 = vRandom[nRndPos1];
     int nId2 = vRandom[nRndPos2];
 
+    assert(mapInfo.count(nId1) == 1);
+    assert(mapInfo.count(nId2) == 1);
+
     mapInfo[nId1].nRandomPos = nRndPos2;
     mapInfo[nId2].nRandomPos = nRndPos1;
 
@@ -131,6 +137,7 @@
         int nTemp = vTried[nPos];
         vTried[nPos] = vTried[i];
         vTried[i] = nTemp;
+        assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
         if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
            nOldest = nTemp;
            nOldestPos = nPos;
@@ -142,11 +149,13 @@
 
 int CAddrMan::ShrinkNew(int nUBucket)
 {
+    assert(nUBucket >= 0 && nUBucket < vvNew.size());
     std::set<int> &vNew = vvNew[nUBucket];
 
     // first look for deletable items
     for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
     {
+        assert(mapInfo.count(*it));
         CAddrInfo &info = mapInfo[*it];
         if (info.IsTerrible())
         {
@@ -171,11 +180,13 @@
     {
         if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3])
         {
+            assert(nOldest == -1 || mapInfo.count(*it) == 1);
             if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
                 nOldest = *it;
         }
         nI++;
     }
+    assert(mapInfo.count(nOldest) == 1);
     CAddrInfo &info = mapInfo[nOldest];
     if (--info.nRefCount == 0) 
     {
@@ -192,6 +203,8 @@
 
 void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
 {
+    assert(vvNew[nOrigin].count(nId) == 1);
+
     // remove the entry from all new buckets
     for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++)
     {
@@ -200,6 +213,8 @@
     }
     nNew--;
 
+    assert(info.nRefCount == 0);
+
     // what tried bucket to move the entry to
     int nKBucket = info.GetTriedBucket(nKey);
     std::vector<int> &vTried = vvTried[nKBucket];
@@ -217,6 +232,7 @@
     int nPos = SelectTried(nKBucket);
 
     // find which new bucket it belongs to
+    assert(mapInfo.count(vTried[nPos]) == 1);
     int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
     std::set<int> &vNew = vvNew[nUBucket];
 
@@ -388,6 +404,7 @@
             std::vector<int> &vTried = vvTried[nKBucket];
             if (vTried.size() == 0) continue;
             int nPos = GetRandInt(vTried.size());
+            assert(mapInfo.count(vTried[nPos]) == 1);
             CAddrInfo &info = mapInfo[vTried[nPos]];
             if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
                 return info;
@@ -405,6 +422,7 @@
             std::set<int>::iterator it = vNew.begin();
             while (nPos--)
                 it++;
+            assert(mapInfo.count(*it) == 1);
             CAddrInfo &info = mapInfo[*it];
             if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
                 return info;
@@ -484,6 +502,7 @@
     {
         int nRndPos = GetRandInt(vRandom.size() - n) + n;
         SwapRandom(n, nRndPos);
+        assert(mapInfo.count(vRandom[n]) == 1);
         vAddr.push_back(mapInfo[vRandom[n]]);
     }
 }
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -35,7 +35,7 @@
 void ThreadMapPort2(void* parg);
 #endif
 void ThreadDNSAddressSeed2(void* parg);
-bool OpenNetworkConnection(const CAddress& addrConnect);
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant = true);
 
 
 
@@ -64,10 +64,7 @@
 set<CNetAddr> setservAddNodeAddresses;
 CCriticalSection cs_setservAddNodeAddresses;
 
-static CWaitableCriticalSection csOutbound;
-static int nOutbound = 0;
-static CConditionVariable condOutbound;
-
+static CSemaphore *semOutbound = NULL;
 
 unsigned short GetListenPort()
 {
@@ -368,10 +365,6 @@
             LOCK(cs_vNodes);
             vNodes.push_back(pnode);
         }
-        {
-            WAITABLE_LOCK(csOutbound);
-            nOutbound++;
-        }
 
         pnode->nTimeConnected = GetTime();
         return pnode;
@@ -517,14 +510,9 @@
                     // remove from vNodes
                     vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
 
-                    if (!pnode->fInbound)
-                        {
-                            WAITABLE_LOCK(csOutbound);
-                            nOutbound--;
-
-                            // Connection slot(s) were removed, notify connection creator(s)
-                            NOTIFY(condOutbound);
-                        }
+                    if (pnode->fHasGrant)
+                        semOutbound->post();
+                    pnode->fHasGrant = false;
 
                     // close socket and cleanup
                     pnode->CloseSocketDisconnect();
@@ -1201,7 +1189,7 @@
             {
                 CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
                 if (addr.IsValid())
-                    OpenNetworkConnection(addr);
+                    OpenNetworkConnection(addr, false);
                 for (int i = 0; i < 10 && i < nLoop; i++)
                 {
                     Sleep(500);
@@ -1222,13 +1210,9 @@
         if (fShutdown)
             return;
 
-        // Limit outbound connections
-        int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+
         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
-        {
-            WAITABLE_LOCK(csOutbound);
-            WAIT(condOutbound, fShutdown || nOutbound < nMaxOutbound);
-        }
+        semOutbound->wait();
         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
         if (fShutdown)
             return;
@@ -1261,11 +1245,15 @@
 
         // Only connect to one address per a.b.?.? range.
         // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
+        int nOutbound = 0;
         set<vector<unsigned char> > setConnected;
         {
             LOCK(cs_vNodes);
-            BOOST_FOREACH(CNode* pnode, vNodes)
+            BOOST_FOREACH(CNode* pnode, vNodes) {
                 setConnected.insert(pnode->addr.GetGroup());
+                if (!pnode->fInbound)
+                    nOutbound++;
+            }
         }
 
         int64 nANow = GetAdjustedTime();
@@ -1296,6 +1284,8 @@
 
         if (addrConnect.IsValid())
             OpenNetworkConnection(addrConnect);
+        else
+            semOutbound->post();
     }
 }
 
@@ -1358,6 +1348,7 @@
         }
         BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
         {
+            semOutbound->wait();
             OpenNetworkConnection(CAddress(*(vserv.begin())));
             Sleep(500);
             if (fShutdown)
@@ -1373,7 +1364,14 @@
     }
 }
 
-bool OpenNetworkConnection(const CAddress& addrConnect)
+bool static ReleaseGrant(bool fUseGrant) {
+    if (fUseGrant)
+        semOutbound->post();
+    return false;
+}
+
+// only call this function when semOutbound has been waited for
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant)
 {
     //
     // Initiate outbound network connection
@@ -1382,7 +1380,7 @@
         return false;
     if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
         FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
-        return false;
+        return ReleaseGrant(fUseGrant);
 
     vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
     CNode* pnode = ConnectNode(addrConnect);
@@ -1390,7 +1388,13 @@
     if (fShutdown)
         return false;
     if (!pnode)
-        return false;
+        return ReleaseGrant(fUseGrant);
+    if (pnode->fHasGrant) {
+        // node already has connection grant, release the one that was passed to us
+        ReleaseGrant(fUseGrant);
+    } else {
+        pnode->fHasGrant = fUseGrant;
+    }
     pnode->fNetworkNode = true;
 
     return true;
@@ -1567,6 +1571,12 @@
 
 void StartNode(void* parg)
 {
+    if (semOutbound == NULL) {
+        // initialize semaphore
+        int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+        semOutbound = new CSemaphore(nMaxOutbound);
+    }
+
 #ifdef USE_UPNP
 #if USE_UPNP
     fUseUPnP = GetBoolArg("-upnp", true);
@@ -1693,7 +1703,8 @@
     fShutdown = true;
     nTransactionsUpdated++;
     int64 nStart = GetTime();
-    NOTIFY_ALL(condOutbound);
+    for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
+         semOutbound->post();
     do
     {
         int nThreadsRunning = 0;
--- a/src/net.h
+++ b/src/net.h
@@ -127,6 +127,7 @@
     bool fNetworkNode;
     bool fSuccessfullyConnected;
     bool fDisconnect;
+    bool fHasGrant; // whether to call semOutbound.post() at disconnect
 protected:
     int nRefCount;
 
@@ -171,6 +172,7 @@
         nVersion = 0;
         strSubVer = "";
         fClient = false; // set by version message
+        fHasGrant = false;
         fInbound = fInboundIn;
         fNetworkNode = false;
         fSuccessfullyConnected = false;
--- a/src/util.h
+++ b/src/util.h
@@ -23,7 +23,7 @@
 #include <boost/filesystem/path.hpp>
 #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
 #include <boost/interprocess/sync/scoped_lock.hpp>
-#include <boost/interprocess/sync/interprocess_condition.hpp>
+#include <boost/interprocess/sync/interprocess_semaphore.hpp>
 #include <boost/interprocess/sync/lock_options.hpp>
 #include <boost/date_time/gregorian/gregorian_types.hpp>
 #include <boost/date_time/posix_time/posix_time_types.hpp>
@@ -270,24 +270,10 @@
 };
 
 typedef CMutexLock<CCriticalSection> CCriticalBlock;
-typedef CMutexLock<CWaitableCriticalSection> CWaitableCriticalBlock;
-typedef boost::interprocess::interprocess_condition CConditionVariable;
-
-/** Wait for a given condition inside a WAITABLE_CRITICAL_BLOCK */
-#define WAIT(name,condition) \
-   do { while(!(condition)) { (name).wait(waitablecriticalblock.GetLock()); } } while(0)
-
-/** Notify waiting threads that a condition may hold now */
-#define NOTIFY(name) \
-   do { (name).notify_one(); } while(0)
-
-#define NOTIFY_ALL(name) \
-   do { (name).notify_all(); } while(0)
 
 #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
 #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
 #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
-#define WAITABLE_LOCK(cs) CWaitableCriticalBlock waitablecriticalblock(cs, #cs, __FILE__, __LINE__)
 
 #define ENTER_CRITICAL_SECTION(cs) \
     { \
@@ -301,6 +287,47 @@
         LeaveCritical(); \
     }
 
+#ifdef MAC_OSX
+// boost::interprocess::interprocess_semaphore seems to spinlock on OSX; prefer polling instead
+class CSemaphore
+{
+private:
+    CCriticalSection cs;
+    int val;
+
+public:
+    CSemaphore(int init) : val(init) {}
+
+    void wait() {
+        do {
+            {
+                LOCK(cs);
+                if (val>0) {
+                    val--;
+                    return;
+                }
+            }
+            Sleep(100);
+        } while(1);
+    }
+
+    bool try_wait() {
+        LOCK(cs);
+        if (val>0) {
+            val--;
+            return true;
+        }
+        return false;
+    }
+
+    void post() {
+        LOCK(cs);
+        val++;
+    }
+};
+#else
+typedef boost::interprocess::interprocess_semaphore CSemaphore;
+#endif
 
 inline std::string i64tostr(int64 n)
 {
--- a/src/version.h
+++ b/src/version.h
@@ -12,8 +12,8 @@
 
 static const int CLIENT_VERSION_MAJOR       =  0;
 static const int CLIENT_VERSION_MINOR       =  6;
-static const int CLIENT_VERSION_REVISION    =  1;
-static const int CLIENT_VERSION_BUILD       = 3;
+static const int CLIENT_VERSION_REVISION    =  2;
+static const int CLIENT_VERSION_BUILD       = 2;
 
 static const int CLIENT_VERSION =
                            1000000 * CLIENT_VERSION_MAJOR