Skip to content

Commit 42c784d

Browse files
OlegGirkoUdjinM6
authored andcommitted
Backport Bitcoin PR#9289: net: drop boost::thread_group (#1568)
* net: a few small cleanups before replacing boost threads - Drop the interruption point directly after the pnode allocation. This would be leaky if hit. - Rearrange thread creation so that the socket handler comes first * net: add CThreadInterrupt and InterruptibleSleep * net: make net interruptible Also now that net threads are interruptible, switch them to use std threads/binds/mutexes/condvars. * net: make net processing interruptible * net: remove thread_interrupted catch This is now a std::thread, so there's no hope of catching a boost interruption point. * net: make proxy receives interruptible * net: misc header cleanups
1 parent df6d458 commit 42c784d

File tree

11 files changed

+229
-82
lines changed

11 files changed

+229
-82
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ BITCOIN_CORE_H = \
171171
support/pagelocker.h \
172172
sync.h \
173173
threadsafety.h \
174+
threadinterrupt.h \
174175
timedata.h \
175176
tinyformat.h \
176177
torcontrol.h \
@@ -387,6 +388,7 @@ libbitcoin_util_a_SOURCES = \
387388
support/cleanse.cpp \
388389
sync.cpp \
389390
uint256.cpp \
391+
threadinterrupt.cpp \
390392
util.cpp \
391393
utilmoneystr.cpp \
392394
utilstrencodings.cpp \

src/init.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ void Interrupt(boost::thread_group& threadGroup)
200200
InterruptRPC();
201201
InterruptREST();
202202
InterruptTorControl();
203+
if (g_connman)
204+
g_connman->Interrupt();
203205
threadGroup.interrupt_all();
204206
}
205207

@@ -2025,7 +2027,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
20252027
connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
20262028
connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
20272029

2028-
if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions))
2030+
if (!connman.Start(scheduler, strNodeError, connOptions))
20292031
return InitError(strNodeError);
20302032

20312033
// Generate coins in the background

src/net.cpp

Lines changed: 85 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@
4040
#include <miniupnpc/upnperrors.h>
4141
#endif
4242

43-
#include <boost/filesystem.hpp>
44-
#include <boost/thread.hpp>
4543

4644
#include <math.h>
4745

@@ -1071,7 +1069,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
10711069
void CConnman::ThreadSocketHandler()
10721070
{
10731071
unsigned int nPrevNodeCount = 0;
1074-
while (true)
1072+
while (!interruptNet)
10751073
{
10761074
//
10771075
// Disconnect nodes
@@ -1211,7 +1209,8 @@ void CConnman::ThreadSocketHandler()
12111209

12121210
int nSelect = select(have_fds ? hSocketMax + 1 : 0,
12131211
&fdsetRecv, &fdsetSend, &fdsetError, &timeout);
1214-
boost::this_thread::interruption_point();
1212+
if (interruptNet)
1213+
return;
12151214

12161215
if (nSelect == SOCKET_ERROR)
12171216
{
@@ -1224,7 +1223,8 @@ void CConnman::ThreadSocketHandler()
12241223
}
12251224
FD_ZERO(&fdsetSend);
12261225
FD_ZERO(&fdsetError);
1227-
MilliSleep(timeout.tv_usec/1000);
1226+
if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000)))
1227+
return;
12281228
}
12291229

12301230
//
@@ -1244,7 +1244,8 @@ void CConnman::ThreadSocketHandler()
12441244
std::vector<CNode*> vNodesCopy = CopyNodeVector();
12451245
BOOST_FOREACH(CNode* pnode, vNodesCopy)
12461246
{
1247-
boost::this_thread::interruption_point();
1247+
if (interruptNet)
1248+
return;
12481249

12491250
//
12501251
// Receive
@@ -1266,7 +1267,7 @@ void CConnman::ThreadSocketHandler()
12661267
if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
12671268
pnode->CloseSocketDisconnect();
12681269
if(notify)
1269-
messageHandlerCondition.notify_one();
1270+
condMsgProc.notify_one();
12701271
pnode->nLastRecv = GetTime();
12711272
pnode->nRecvBytes += nBytes;
12721273
RecordBytesRecv(nBytes);
@@ -1471,7 +1472,8 @@ void CConnman::ThreadDNSAddressSeed()
14711472
// goal: only query DNS seeds if address need is acute
14721473
if ((addrman.size() > 0) &&
14731474
(!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
1474-
MilliSleep(11 * 1000);
1475+
if (!interruptNet.sleep_for(std::chrono::seconds(11)))
1476+
return;
14751477

14761478
LOCK(cs_vNodes);
14771479
if (vNodes.size() >= 2) {
@@ -1569,10 +1571,12 @@ void CConnman::ThreadOpenConnections()
15691571
OpenNetworkConnection(addr, NULL, strAddr.c_str());
15701572
for (int i = 0; i < 10 && i < nLoop; i++)
15711573
{
1572-
MilliSleep(500);
1574+
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
1575+
return;
15731576
}
15741577
}
1575-
MilliSleep(500);
1578+
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
1579+
return;
15761580
}
15771581
}
15781582

@@ -1581,14 +1585,16 @@ void CConnman::ThreadOpenConnections()
15811585

15821586
// Minimum time before next feeler connection (in microseconds).
15831587
int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
1584-
while (true)
1588+
while (!interruptNet)
15851589
{
15861590
ProcessOneShot();
15871591

1588-
MilliSleep(500);
1592+
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
1593+
return;
15891594

15901595
CSemaphoreGrant grant(*semOutbound);
1591-
boost::this_thread::interruption_point();
1596+
if (interruptNet)
1597+
return;
15921598

15931599
// Add seed nodes if DNS seeds are all down (an infrastructure attack?).
15941600
if (addrman.size() == 0 && (GetTime() - nStart > 60)) {
@@ -1645,7 +1651,7 @@ void CConnman::ThreadOpenConnections()
16451651

16461652
int64_t nANow = GetAdjustedTime();
16471653
int nTries = 0;
1648-
while (true)
1654+
while (!interruptNet)
16491655
{
16501656
CAddrInfo addr = addrman.Select(fFeeler);
16511657

@@ -1684,7 +1690,8 @@ void CConnman::ThreadOpenConnections()
16841690
if (fFeeler) {
16851691
// Add small amount of random noise before connection to avoid synchronization.
16861692
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
1687-
MilliSleep(randsleep);
1693+
if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
1694+
return;
16881695
LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString());
16891696
}
16901697

@@ -1762,11 +1769,12 @@ void CConnman::ThreadOpenAddedConnections()
17621769
// OpenNetworkConnection can detect existing connections to that IP/port.
17631770
CService service(info.strAddedNode, Params().GetDefaultPort());
17641771
OpenNetworkConnection(CAddress(service, NODE_NONE), &grant, info.strAddedNode.c_str(), false);
1765-
MilliSleep(500);
1772+
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
1773+
return;
17661774
}
17671775
}
1768-
1769-
MilliSleep(120000); // Retry every 2 minutes
1776+
if (!interruptNet.sleep_for(std::chrono::minutes(2)))
1777+
return;
17701778
}
17711779
}
17721780

@@ -1776,12 +1784,14 @@ void CConnman::ThreadMnbRequestConnections()
17761784
if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
17771785
return;
17781786

1779-
while (true)
1787+
while (!interruptNet)
17801788
{
1781-
MilliSleep(1000);
1789+
if (!interruptNet.sleep_for(std::chrono::milliseconds(1000)))
1790+
return;
17821791

17831792
CSemaphoreGrant grant(*semMasternodeOutbound);
1784-
boost::this_thread::interruption_point();
1793+
if (interruptNet)
1794+
return;
17851795

17861796
std::pair<CService, std::set<uint256> > p = mnodeman.PopScheduledMnbRequestConnection();
17871797
if(p.first == CService() || p.second.empty()) continue;
@@ -1820,7 +1830,9 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGran
18201830
//
18211831
// Initiate outbound network connection
18221832
//
1823-
boost::this_thread::interruption_point();
1833+
if (interruptNet) {
1834+
return false;
1835+
}
18241836
if (!pszDest) {
18251837
if (IsLocal(addrConnect) ||
18261838
FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) ||
@@ -1830,7 +1842,6 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGran
18301842
return false;
18311843

18321844
CNode* pnode = ConnectNode(addrConnect, pszDest);
1833-
boost::this_thread::interruption_point();
18341845

18351846
if (!pnode)
18361847
return false;
@@ -1844,14 +1855,10 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGran
18441855
return true;
18451856
}
18461857

1847-
18481858
void CConnman::ThreadMessageHandler()
18491859
{
1850-
boost::mutex condition_mutex;
1851-
boost::unique_lock<boost::mutex> lock(condition_mutex);
1852-
18531860
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1854-
while (true)
1861+
while (!flagInterruptMsgProc)
18551862
{
18561863
std::vector<CNode*> vNodesCopy = CopyNodeVector();
18571864

@@ -1867,7 +1874,7 @@ void CConnman::ThreadMessageHandler()
18671874
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
18681875
if (lockRecv)
18691876
{
1870-
if (!GetNodeSignals().ProcessMessages(pnode, *this))
1877+
if (!GetNodeSignals().ProcessMessages(pnode, *this, flagInterruptMsgProc))
18711878
pnode->fDisconnect = true;
18721879

18731880
if (pnode->nSendSize < GetSendBufferSize())
@@ -1879,21 +1886,25 @@ void CConnman::ThreadMessageHandler()
18791886
}
18801887
}
18811888
}
1882-
boost::this_thread::interruption_point();
1889+
if (flagInterruptMsgProc)
1890+
return;
18831891

18841892
// Send messages
18851893
{
18861894
TRY_LOCK(pnode->cs_vSend, lockSend);
18871895
if (lockSend)
1888-
GetNodeSignals().SendMessages(pnode, *this);
1896+
GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);
18891897
}
1890-
boost::this_thread::interruption_point();
1898+
if (flagInterruptMsgProc)
1899+
return;
18911900
}
18921901

18931902
ReleaseNodeVector(vNodesCopy);
18941903

1895-
if (fSleep)
1896-
messageHandlerCondition.timed_wait(lock, boost::posix_time::microsec_clock::universal_time() + boost::posix_time::milliseconds(100));
1904+
if (fSleep) {
1905+
std::unique_lock<std::mutex> lock(mutexMsgProc);
1906+
condMsgProc.wait_until(lock, std::chrono::steady_clock::now() + std::chrono::milliseconds(100));
1907+
}
18971908
}
18981909
}
18991910

@@ -2064,14 +2075,15 @@ CConnman::CConnman()
20642075
nMaxOutbound = 0;
20652076
nBestHeight = 0;
20662077
clientInterface = NULL;
2078+
flagInterruptMsgProc = false;
20672079
}
20682080

20692081
NodeId CConnman::GetNewNodeId()
20702082
{
20712083
return nLastNodeId.fetch_add(1, std::memory_order_relaxed);
20722084
}
20732085

2074-
bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options connOptions)
2086+
bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options connOptions)
20752087
{
20762088
nTotalBytesRecv = 0;
20772089
nTotalBytesSent = 0;
@@ -2145,26 +2157,29 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st
21452157
//
21462158
// Start threads
21472159
//
2160+
InterruptSocks5(false);
2161+
interruptNet.reset();
2162+
flagInterruptMsgProc = false;
2163+
2164+
// Send and receive from sockets, accept connections
2165+
threadSocketHandler = std::thread(&TraceThread<std::function<void()> >, "net", std::function<void()>(std::bind(&CConnman::ThreadSocketHandler, this)));
21482166

21492167
if (!GetBoolArg("-dnsseed", true))
21502168
LogPrintf("DNS seeding disabled\n");
21512169
else
2152-
threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "dnsseed", boost::function<void()>(boost::bind(&CConnman::ThreadDNSAddressSeed, this))));
2153-
2154-
// Send and receive from sockets, accept connections
2155-
threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "net", boost::function<void()>(boost::bind(&CConnman::ThreadSocketHandler, this))));
2170+
threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));
21562171

21572172
// Initiate outbound connections from -addnode
2158-
threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "addcon", boost::function<void()>(boost::bind(&CConnman::ThreadOpenAddedConnections, this))));
2173+
threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
21592174

21602175
// Initiate outbound connections
2161-
threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "opencon", boost::function<void()>(boost::bind(&CConnman::ThreadOpenConnections, this))));
2176+
threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this)));
21622177

21632178
// Initiate masternode connections
2164-
threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "mnbcon", boost::function<void()>(boost::bind(&CConnman::ThreadMnbRequestConnections, this))));
2179+
threadMnbRequestConnections = std::thread(&TraceThread<std::function<void()> >, "mnbcon", std::function<void()>(std::bind(&CConnman::ThreadMnbRequestConnections, this)));
21652180

21662181
// Process messages
2167-
threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "msghand", boost::function<void()>(boost::bind(&CConnman::ThreadMessageHandler, this))));
2182+
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
21682183

21692184
// Dump network addresses
21702185
scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL);
@@ -2195,12 +2210,36 @@ void CExplicitNetCleanup::callCleanup()
21952210
delete tmp; // Stroustrup's gonna kill me for that
21962211
}
21972212

2198-
void CConnman::Stop()
2213+
void CConnman::Interrupt()
21992214
{
2200-
LogPrintf("%s\n",__func__);
2215+
{
2216+
std::lock_guard<std::mutex> lock(mutexMsgProc);
2217+
flagInterruptMsgProc = true;
2218+
}
2219+
condMsgProc.notify_all();
2220+
2221+
interruptNet();
2222+
InterruptSocks5(true);
2223+
22012224
if (semOutbound)
22022225
for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++)
22032226
semOutbound->post();
2227+
}
2228+
2229+
void CConnman::Stop()
2230+
{
2231+
if (threadMessageHandler.joinable())
2232+
threadMessageHandler.join();
2233+
if (threadMnbRequestConnections.joinable())
2234+
threadMnbRequestConnections.join();
2235+
if (threadOpenConnections.joinable())
2236+
threadOpenConnections.join();
2237+
if (threadOpenAddedConnections.joinable())
2238+
threadOpenAddedConnections.join();
2239+
if (threadDNSAddressSeed.joinable())
2240+
threadDNSAddressSeed.join();
2241+
if (threadSocketHandler.joinable())
2242+
threadSocketHandler.join();
22042243

22052244
if (semMasternodeOutbound)
22062245
for (int i=0; i<MAX_OUTBOUND_MASTERNODE_CONNECTIONS; i++)
@@ -2252,6 +2291,7 @@ void CConnman::DeleteNode(CNode* pnode)
22522291

22532292
CConnman::~CConnman()
22542293
{
2294+
Interrupt();
22552295
Stop();
22562296
}
22572297

0 commit comments

Comments
 (0)