diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2012-05-10 16:39:49 -0400 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2012-05-10 16:39:49 -0400 |
commit | aaff04791d35087ba66a2a0e814620b30fbf9b96 (patch) | |
tree | 7b2fd009f09ea2a685556362bf1f7bed47f8f326 | |
parent | 91b13a0dff056b444d8fd0c2a5baae75e9d6208b (diff) | |
parent | f0f1b3775e5e0c7939c1131f831ce0334348ac72 (diff) |
Merge branch 'semaphores-v0.6.2' of https://github.com/sipa/bitcoin into 0.6.2
-rw-r--r-- | src/net.cpp | 69 | ||||
-rw-r--r-- | src/net.h | 2 | ||||
-rw-r--r-- | src/util.h | 57 |
3 files changed, 84 insertions, 44 deletions
diff --git a/src/net.cpp b/src/net.cpp index 92b4a3173f..88a3b436c7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -35,7 +35,7 @@ void ThreadOpenAddedConnections2(void* parg); 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 @@ map<CInv, int64> mapAlreadyAskedFor; 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 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) LOCK(cs_vNodes); vNodes.push_back(pnode); } - { - WAITABLE_LOCK(csOutbound); - nOutbound++; - } pnode->nTimeConnected = GetTime(); return pnode; @@ -517,14 +510,9 @@ void ThreadSocketHandler2(void* parg) // 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 @@ void ThreadOpenConnections2(void* parg) { 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 @@ void ThreadOpenConnections2(void* parg) 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 @@ void ThreadOpenConnections2(void* parg) // 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 @@ void ThreadOpenConnections2(void* parg) if (addrConnect.IsValid()) OpenNetworkConnection(addrConnect); + else + semOutbound->post(); } } @@ -1358,6 +1348,7 @@ void ThreadOpenAddedConnections2(void* parg) } BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses) { + semOutbound->wait(); OpenNetworkConnection(CAddress(*(vserv.begin()))); Sleep(500); if (fShutdown) @@ -1373,7 +1364,14 @@ void ThreadOpenAddedConnections2(void* parg) } } -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 @@ bool OpenNetworkConnection(const CAddress& addrConnect) 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 @@ bool OpenNetworkConnection(const CAddress& addrConnect) 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 @@ bool BindListenPort(string& strError) 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 @@ bool StopNode() fShutdown = true; nTransactionsUpdated++; int64 nStart = GetTime(); - NOTIFY_ALL(condOutbound); + for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) + semOutbound->post(); do { int nThreadsRunning = 0; @@ -127,6 +127,7 @@ public: bool fNetworkNode; bool fSuccessfullyConnected; bool fDisconnect; + bool fHasGrant; // whether to call semOutbound.post() at disconnect protected: int nRefCount; @@ -171,6 +172,7 @@ public: nVersion = 0; strSubVer = ""; fClient = false; // set by version message + fHasGrant = false; fInbound = fInboundIn; fNetworkNode = false; fSuccessfullyConnected = false; diff --git a/src/util.h b/src/util.h index 5f8d0375da..15ccf82f9a 100644 --- a/src/util.h +++ b/src/util.h @@ -23,7 +23,7 @@ typedef int pid_t; /* define for windows compatiblity */ #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 @@ public: }; 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 @@ typedef boost::interprocess::interprocess_condition CConditionVariable; 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) { |