29
29
#include < util/thread.h>
30
30
#include < util/time.h>
31
31
#include < util/translation.h>
32
+ #include < util/wpipe.h>
32
33
#include < validation.h> // for fDIP0001ActiveAtTip
33
34
34
35
#include < masternode/meta.h>
@@ -119,7 +120,7 @@ static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 50;
119
120
// We are however still somewhat limited in how long we can sleep as there is periodic work (cleanup) to be done in
120
121
// the socket handler thread
121
122
static const uint64_t SELECT_TIMEOUT_MILLISECONDS = 500 ;
122
- #endif
123
+ #endif /* USE_WAKEUP_PIPE */
123
124
124
125
const std::string NET_MESSAGE_COMMAND_OTHER = " *other*" ;
125
126
@@ -1284,7 +1285,9 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
1284
1285
LogPrint (BCLog::NET, " EdgeTriggeredEvents::RegisterEvents() failed\n " );
1285
1286
}
1286
1287
}
1287
- WakeSelect ();
1288
+ if (m_wakeup_pipe) {
1289
+ m_wakeup_pipe->Write ();
1290
+ }
1288
1291
}
1289
1292
1290
1293
// We received a new connection, harvest entropy from the time (and our peer count)
@@ -1569,14 +1572,14 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
1569
1572
}
1570
1573
}
1571
1574
1572
- # ifdef USE_WAKEUP_PIPE
1573
- // We add a pipe to the read set so that the select() call can be woken up from the outside
1574
- // This is done when data is added to send buffers (vSendMsg) or when new peers are added
1575
- // This is currently only implemented for POSIX compliant systems. This means that Windows will fall back to
1576
- // timing out after 50ms and then trying to send. This is ok as we assume that heavy-load daemons are usually
1577
- // run on Linux and friends.
1578
- recv_set.insert (wakeupPipe [0 ]);
1579
- # endif
1575
+ if (m_wakeup_pipe) {
1576
+ // We add a pipe to the read set so that the select() call can be woken up from the outside
1577
+ // This is done when data is added to send buffers (vSendMsg) or when new peers are added
1578
+ // This is currently only implemented for POSIX compliant systems. This means that Windows will fall back to
1579
+ // timing out after 50ms and then trying to send. This is ok as we assume that heavy-load daemons are usually
1580
+ // run on Linux and friends.
1581
+ recv_set.insert (m_wakeup_pipe-> m_pipe [0 ]);
1582
+ }
1580
1583
1581
1584
return !recv_set.empty () || !send_set.empty () || !error_set.empty ();
1582
1585
}
@@ -1594,9 +1597,8 @@ void CConnman::SocketEventsKqueue(std::set<SOCKET>& recv_set,
1594
1597
timeout.tv_sec = only_poll ? 0 : SELECT_TIMEOUT_MILLISECONDS / 1000 ;
1595
1598
timeout.tv_nsec = (only_poll ? 0 : SELECT_TIMEOUT_MILLISECONDS % 1000 ) * 1000 * 1000 ;
1596
1599
1597
- wakeupSelectNeeded = true ;
1598
- int n = kevent (Assert (m_edge_trig_events)->m_fd , nullptr , 0 , events, maxEvents, &timeout);
1599
- wakeupSelectNeeded = false ;
1600
+ int n{-1 };
1601
+ ToggleWakeupPipe ([&](){n = kevent (Assert (m_edge_trig_events)->m_fd , nullptr , 0 , events, maxEvents, &timeout);});
1600
1602
if (n == -1 ) {
1601
1603
LogPrintf (" kevent wait error\n " );
1602
1604
} else if (n > 0 ) {
@@ -1628,9 +1630,8 @@ void CConnman::SocketEventsEpoll(std::set<SOCKET>& recv_set,
1628
1630
const size_t maxEvents = 64 ;
1629
1631
epoll_event events[maxEvents];
1630
1632
1631
- wakeupSelectNeeded = true ;
1632
- int n = epoll_wait (Assert (m_edge_trig_events)->m_fd , events, maxEvents, only_poll ? 0 : SELECT_TIMEOUT_MILLISECONDS);
1633
- wakeupSelectNeeded = false ;
1633
+ int n{-1 };
1634
+ ToggleWakeupPipe ([&](){n = epoll_wait (Assert (m_edge_trig_events)->m_fd , events, maxEvents, only_poll ? 0 : SELECT_TIMEOUT_MILLISECONDS);});
1634
1635
for (int i = 0 ; i < n; i++) {
1635
1636
auto & e = events[i];
1636
1637
if ((e.events & EPOLLERR) || (e.events & EPOLLHUP)) {
@@ -1685,9 +1686,8 @@ void CConnman::SocketEventsPoll(const std::vector<CNode*>& nodes,
1685
1686
vpollfds.push_back (std::move (it.second ));
1686
1687
}
1687
1688
1688
- wakeupSelectNeeded = true ;
1689
- int r = poll (vpollfds.data (), vpollfds.size (), only_poll ? 0 : SELECT_TIMEOUT_MILLISECONDS);
1690
- wakeupSelectNeeded = false ;
1689
+ int r{-1 };
1690
+ ToggleWakeupPipe ([&](){r = poll (vpollfds.data (), vpollfds.size (), only_poll ? 0 : SELECT_TIMEOUT_MILLISECONDS);});
1691
1691
if (r < 0 ) {
1692
1692
return ;
1693
1693
}
@@ -1744,9 +1744,8 @@ void CConnman::SocketEventsSelect(const std::vector<CNode*>& nodes,
1744
1744
hSocketMax = std::max (hSocketMax, hSocket);
1745
1745
}
1746
1746
1747
- wakeupSelectNeeded = true ;
1748
- int nSelect = select (hSocketMax + 1 , &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
1749
- wakeupSelectNeeded = false ;
1747
+ int nSelect{-1 };
1748
+ ToggleWakeupPipe ([&](){nSelect = select (hSocketMax + 1 , &fdsetRecv, &fdsetSend, &fdsetError, &timeout);});
1750
1749
if (interruptNet)
1751
1750
return ;
1752
1751
@@ -1849,18 +1848,10 @@ void CConnman::SocketHandler(CMasternodeSync& mn_sync)
1849
1848
// empty sets.
1850
1849
SocketEvents (snap.Nodes (), recv_set, send_set, error_set, only_poll);
1851
1850
1852
- #ifdef USE_WAKEUP_PIPE
1853
- // drain the wakeup pipe
1854
- if (recv_set.count (wakeupPipe[0 ])) {
1855
- char buf[128 ];
1856
- while (true ) {
1857
- int r = read (wakeupPipe[0 ], buf, sizeof (buf));
1858
- if (r <= 0 ) {
1859
- break ;
1860
- }
1861
- }
1851
+ // Drain the wakeup pipe
1852
+ if (m_wakeup_pipe && recv_set.count (m_wakeup_pipe->m_pipe [0 ])) {
1853
+ m_wakeup_pipe->Drain ();
1862
1854
}
1863
- #endif
1864
1855
1865
1856
// Service (send/receive) each of the already connected nodes.
1866
1857
SocketHandlerConnected (recv_set, send_set, error_set);
@@ -2138,22 +2129,6 @@ void CConnman::WakeMessageHandler()
2138
2129
condMsgProc.notify_one ();
2139
2130
}
2140
2131
2141
- void CConnman::WakeSelect ()
2142
- {
2143
- #ifdef USE_WAKEUP_PIPE
2144
- if (wakeupPipe[1 ] == -1 ) {
2145
- return ;
2146
- }
2147
-
2148
- char buf{0 };
2149
- if (write (wakeupPipe[1 ], &buf, sizeof (buf)) != 1 ) {
2150
- LogPrint (BCLog::NET, " write to wakeupPipe failed\n " );
2151
- }
2152
- #endif
2153
-
2154
- wakeupSelectNeeded = false ;
2155
- }
2156
-
2157
2132
void CConnman::ThreadDNSAddressSeed ()
2158
2133
{
2159
2134
FastRandomContext rng;
@@ -2993,7 +2968,9 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
2993
2968
LogPrint (BCLog::NET, " EdgeTriggeredEvents::RegisterEvents() failed\n " );
2994
2969
}
2995
2970
}
2996
- WakeSelect ();
2971
+ if (m_wakeup_pipe) {
2972
+ m_wakeup_pipe->Write ();
2973
+ }
2997
2974
}
2998
2975
}
2999
2976
@@ -3373,23 +3350,13 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met
3373
3350
}
3374
3351
3375
3352
#ifdef USE_WAKEUP_PIPE
3376
- if (pipe (wakeupPipe) != 0 ) {
3377
- wakeupPipe[0 ] = wakeupPipe[1 ] = -1 ;
3378
- LogPrint (BCLog::NET, " pipe() for wakeupPipe failed\n " );
3379
- } else {
3380
- int fFlags = fcntl (wakeupPipe[0 ], F_GETFL, 0 );
3381
- if (fcntl (wakeupPipe[0 ], F_SETFL, fFlags | O_NONBLOCK) == -1 ) {
3382
- LogPrint (BCLog::NET, " fcntl for O_NONBLOCK on wakeupPipe failed\n " );
3383
- }
3384
- fFlags = fcntl (wakeupPipe[1 ], F_GETFL, 0 );
3385
- if (fcntl (wakeupPipe[1 ], F_SETFL, fFlags | O_NONBLOCK) == -1 ) {
3386
- LogPrint (BCLog::NET, " fcntl for O_NONBLOCK on wakeupPipe failed\n " );
3387
- }
3388
- if (m_edge_trig_events && !m_edge_trig_events->RegisterPipe (wakeupPipe[0 ])) {
3389
- LogPrint (BCLog::NET, " EdgeTriggeredEvents::RegisterPipe() failed\n " );
3390
- }
3353
+ m_wakeup_pipe = std::make_unique<WakeupPipe>(m_edge_trig_events.get ());
3354
+ if (!m_wakeup_pipe->IsValid ()) {
3355
+ /* We log the error but do not halt initialization */
3356
+ LogPrintf (" Unable to initialize WakeupPipe instance\n " );
3357
+ m_wakeup_pipe.reset ();
3391
3358
}
3392
- #endif
3359
+ #endif /* USE_WAKEUP_PIPE */
3393
3360
3394
3361
// Send and receive from sockets, accept connections
3395
3362
threadSocketHandler = std::thread (&util::TraceThread, " net" , [this , &mn_sync] { ThreadSocketHandler (mn_sync); });
@@ -3555,21 +3522,12 @@ void CConnman::StopNodes()
3555
3522
vhListenSocket.clear ();
3556
3523
semOutbound.reset ();
3557
3524
semAddnode.reset ();
3558
-
3559
- if (m_edge_trig_events) {
3560
- #ifdef USE_WAKEUP_PIPE
3561
- if (!m_edge_trig_events->UnregisterPipe (wakeupPipe[0 ])) {
3562
- LogPrintf (" EdgeTriggeredEvents::UnregisterPipe() failed\n " );
3563
- }
3564
- #endif
3565
- m_edge_trig_events.reset ();
3566
- }
3567
-
3568
- #ifdef USE_WAKEUP_PIPE
3569
- if (wakeupPipe[0 ] != -1 ) close (wakeupPipe[0 ]);
3570
- if (wakeupPipe[1 ] != -1 ) close (wakeupPipe[1 ]);
3571
- wakeupPipe[0 ] = wakeupPipe[1 ] = -1 ;
3572
- #endif
3525
+ /* *
3526
+ * m_wakeup_pipe must be reset *before* m_edge_trig_events as it may
3527
+ * attempt to call EdgeTriggeredEvents::UnregisterPipe() in its destructor
3528
+ */
3529
+ m_wakeup_pipe.reset ();
3530
+ m_edge_trig_events.reset ();
3573
3531
}
3574
3532
3575
3533
void CConnman::DeleteNode (CNode* pnode)
@@ -4082,8 +4040,8 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
4082
4040
}
4083
4041
4084
4042
// wake up select() call in case there was no pending data before (so it was not selecting this socket for sending)
4085
- if (!hasPendingData && wakeupSelectNeeded )
4086
- WakeSelect ();
4043
+ if (!hasPendingData && (m_wakeup_pipe && m_wakeup_pipe-> m_need_wakeup . load ()) )
4044
+ m_wakeup_pipe-> Write ();
4087
4045
}
4088
4046
}
4089
4047
0 commit comments