mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Implement epoll support
This commit is contained in:
parent
087d98477b
commit
3fa94aac56
@ -19,11 +19,13 @@ cd build-ci/dashcore-$BUILD_TARGET
|
|||||||
|
|
||||||
if [ "$SOCKETEVENTS" = "" ]; then
|
if [ "$SOCKETEVENTS" = "" ]; then
|
||||||
# Let's switch socketevents mode to some random mode
|
# Let's switch socketevents mode to some random mode
|
||||||
R=$(($RANDOM%2))
|
R=$(($RANDOM%3))
|
||||||
if [ "$R" == "0" ]; then
|
if [ "$R" == "0" ]; then
|
||||||
SOCKETEVENTS="select"
|
SOCKETEVENTS="select"
|
||||||
else
|
elif [ "$R" == "1" ]; then
|
||||||
SOCKETEVENTS="poll"
|
SOCKETEVENTS="poll"
|
||||||
|
else
|
||||||
|
SOCKETEVENTS="epoll"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo "Using socketevents mode: $SOCKETEVENTS"
|
echo "Using socketevents mode: $SOCKETEVENTS"
|
||||||
|
@ -109,6 +109,10 @@ typedef char* sockopt_arg_type;
|
|||||||
#define USE_POLL
|
#define USE_POLL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define USE_EPOLL
|
||||||
|
#endif
|
||||||
|
|
||||||
bool static inline IsSelectableSocket(const SOCKET& s) {
|
bool static inline IsSelectableSocket(const SOCKET& s) {
|
||||||
#if defined(USE_POLL) || defined(WIN32)
|
#if defined(USE_POLL) || defined(WIN32)
|
||||||
return true;
|
return true;
|
||||||
|
@ -414,6 +414,9 @@ std::string GetSupportedSocketEventsStr()
|
|||||||
std::string strSupportedModes = "'select'";
|
std::string strSupportedModes = "'select'";
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
strSupportedModes += ", 'poll'";
|
strSupportedModes += ", 'poll'";
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
strSupportedModes += ", 'epoll'";
|
||||||
#endif
|
#endif
|
||||||
return strSupportedModes;
|
return strSupportedModes;
|
||||||
}
|
}
|
||||||
@ -2244,6 +2247,10 @@ bool AppInitMain()
|
|||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
} else if (strSocketEventsMode == "poll") {
|
} else if (strSocketEventsMode == "poll") {
|
||||||
connOptions.socketEventsMode = CConnman::SOCKETEVENTS_POLL;
|
connOptions.socketEventsMode = CConnman::SOCKETEVENTS_POLL;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
} else if (strSocketEventsMode == "epoll") {
|
||||||
|
connOptions.socketEventsMode = CConnman::SOCKETEVENTS_EPOLL;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return InitError(strprintf(_("Invalid -socketevents ('%s') specified. Only these modes are supported: %s"), strSocketEventsMode, GetSupportedSocketEventsStr()));
|
return InitError(strprintf(_("Invalid -socketevents ('%s') specified. Only these modes are supported: %s"), strSocketEventsMode, GetSupportedSocketEventsStr()));
|
||||||
|
138
src/net.cpp
138
src/net.cpp
@ -39,6 +39,10 @@
|
|||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
#include <miniupnpc/miniupnpc.h>
|
#include <miniupnpc/miniupnpc.h>
|
||||||
#include <miniupnpc/miniwget.h>
|
#include <miniupnpc/miniwget.h>
|
||||||
@ -540,6 +544,8 @@ void CNode::CloseSocketDisconnect(CConnman* connman)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connman->UnregisterEvents(this);
|
||||||
|
|
||||||
LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
|
LogPrint(BCLog::NET, "disconnecting peer=%d\n", id);
|
||||||
CloseSocket(hSocket);
|
CloseSocket(hSocket);
|
||||||
}
|
}
|
||||||
@ -1256,6 +1262,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
|||||||
LOCK(cs_vNodes);
|
LOCK(cs_vNodes);
|
||||||
vNodes.push_back(pnode);
|
vNodes.push_back(pnode);
|
||||||
mapSocketToNode.emplace(pnode->hSocket, pnode);
|
mapSocketToNode.emplace(pnode->hSocket, pnode);
|
||||||
|
RegisterEvents(pnode);
|
||||||
WakeSelect();
|
WakeSelect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1443,6 +1450,33 @@ bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &s
|
|||||||
return !recv_set.empty() || !send_set.empty() || !error_set.empty();
|
return !recv_set.empty() || !send_set.empty() || !error_set.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
void CConnman::SocketEventsEpoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll)
|
||||||
|
{
|
||||||
|
const size_t maxEvents = 64;
|
||||||
|
epoll_event events[maxEvents];
|
||||||
|
|
||||||
|
wakeupSelectNeeded = true;
|
||||||
|
int n = epoll_wait(epollfd, events, maxEvents, fOnlyPoll ? 0 : SELECT_TIMEOUT_MILLISECONDS);
|
||||||
|
wakeupSelectNeeded = false;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
auto& e = events[i];
|
||||||
|
if((e.events & EPOLLERR) || (e.events & EPOLLHUP)) {
|
||||||
|
error_set.insert((SOCKET)e.data.fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.events & EPOLLIN) {
|
||||||
|
recv_set.insert((SOCKET)e.data.fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.events & EPOLLOUT) {
|
||||||
|
send_set.insert((SOCKET)e.data.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
void CConnman::SocketEventsPoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll)
|
void CConnman::SocketEventsPoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll)
|
||||||
{
|
{
|
||||||
@ -1570,6 +1604,11 @@ void CConnman::SocketEventsSelect(std::set<SOCKET> &recv_set, std::set<SOCKET> &
|
|||||||
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll)
|
void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll)
|
||||||
{
|
{
|
||||||
switch (socketEventsMode) {
|
switch (socketEventsMode) {
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
case SOCKETEVENTS_EPOLL:
|
||||||
|
SocketEventsEpoll(recv_set, send_set, error_set, fOnlyPoll);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
case SOCKETEVENTS_POLL:
|
case SOCKETEVENTS_POLL:
|
||||||
SocketEventsPoll(recv_set, send_set, error_set, fOnlyPoll);
|
SocketEventsPoll(recv_set, send_set, error_set, fOnlyPoll);
|
||||||
@ -2623,6 +2662,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
|||||||
{
|
{
|
||||||
LOCK(cs_vNodes);
|
LOCK(cs_vNodes);
|
||||||
vNodes.push_back(pnode);
|
vNodes.push_back(pnode);
|
||||||
|
RegisterEvents(pnode);
|
||||||
WakeSelect();
|
WakeSelect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2745,6 +2785,20 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode == SOCKETEVENTS_EPOLL) {
|
||||||
|
epoll_event event;
|
||||||
|
event.data.fd = hListenSocket;
|
||||||
|
event.events = EPOLLIN;
|
||||||
|
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, hListenSocket, &event) != 0) {
|
||||||
|
strError = strprintf(_("Error: failed to add socket to epollfd (epoll_ctl returned error %s)"), NetworkErrorString(WSAGetLastError()));
|
||||||
|
LogPrintf("%s\n", strError);
|
||||||
|
CloseSocket(hListenSocket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
|
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
|
||||||
|
|
||||||
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
|
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
|
||||||
@ -2886,6 +2940,16 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
|||||||
nMaxOutboundCycleStartTime = 0;
|
nMaxOutboundCycleStartTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode == SOCKETEVENTS_EPOLL) {
|
||||||
|
epollfd = epoll_create1(0);
|
||||||
|
if (epollfd == -1) {
|
||||||
|
LogPrintf("epoll_create1 failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
|
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
|
||||||
if (clientInterface) {
|
if (clientInterface) {
|
||||||
clientInterface->ThreadSafeMessageBox(
|
clientInterface->ThreadSafeMessageBox(
|
||||||
@ -2972,6 +3036,19 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
|||||||
if (fcntl(wakeupPipe[1], F_SETFL, fFlags | O_NONBLOCK) == -1) {
|
if (fcntl(wakeupPipe[1], F_SETFL, fFlags | O_NONBLOCK) == -1) {
|
||||||
LogPrint(BCLog::NET, "fcntl for O_NONBLOCK on wakeupPipe failed\n");
|
LogPrint(BCLog::NET, "fcntl for O_NONBLOCK on wakeupPipe failed\n");
|
||||||
}
|
}
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode == SOCKETEVENTS_EPOLL) {
|
||||||
|
epoll_event event;
|
||||||
|
event.events = EPOLLIN;
|
||||||
|
event.data.fd = wakeupPipe[0];
|
||||||
|
int r = epoll_ctl(epollfd, EPOLL_CTL_ADD, wakeupPipe[0], &event);
|
||||||
|
if (r != 0) {
|
||||||
|
LogPrint(BCLog::NET, "%s -- epoll_ctl(%d, %d, %d, ...) failed. error: %s\n", __func__,
|
||||||
|
epollfd, EPOLL_CTL_DEL, wakeupPipe[0], NetworkErrorString(WSAGetLastError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -3085,9 +3162,15 @@ void CConnman::Stop()
|
|||||||
pnode->CloseSocketDisconnect(this);
|
pnode->CloseSocketDisconnect(this);
|
||||||
}
|
}
|
||||||
for (ListenSocket& hListenSocket : vhListenSocket)
|
for (ListenSocket& hListenSocket : vhListenSocket)
|
||||||
if (hListenSocket.socket != INVALID_SOCKET)
|
if (hListenSocket.socket != INVALID_SOCKET) {
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode == SOCKETEVENTS_EPOLL) {
|
||||||
|
epoll_ctl(epollfd, EPOLL_CTL_DEL, hListenSocket.socket, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (!CloseSocket(hListenSocket.socket))
|
if (!CloseSocket(hListenSocket.socket))
|
||||||
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
|
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
|
||||||
// clean up some globals (to help leak detection)
|
// clean up some globals (to help leak detection)
|
||||||
for (CNode *pnode : vNodes) {
|
for (CNode *pnode : vNodes) {
|
||||||
@ -3108,6 +3191,16 @@ void CConnman::Stop()
|
|||||||
semOutbound.reset();
|
semOutbound.reset();
|
||||||
semAddnode.reset();
|
semAddnode.reset();
|
||||||
|
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode == SOCKETEVENTS_EPOLL && epollfd != -1) {
|
||||||
|
#ifdef USE_WAKEUP_PIPE
|
||||||
|
epoll_ctl(epollfd, EPOLL_CTL_DEL, wakeupPipe[0], nullptr);
|
||||||
|
#endif
|
||||||
|
close(epollfd);
|
||||||
|
}
|
||||||
|
epollfd = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WAKEUP_PIPE
|
#ifdef USE_WAKEUP_PIPE
|
||||||
if (wakeupPipe[0] != -1) close(wakeupPipe[0]);
|
if (wakeupPipe[0] != -1) close(wakeupPipe[0]);
|
||||||
if (wakeupPipe[1] != -1) close(wakeupPipe[1]);
|
if (wakeupPipe[1] != -1) close(wakeupPipe[1]);
|
||||||
@ -3740,3 +3833,46 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
|
|||||||
|
|
||||||
return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
|
return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CConnman::RegisterEvents(CNode *pnode)
|
||||||
|
{
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode != SOCKETEVENTS_EPOLL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK(pnode->cs_hSocket);
|
||||||
|
assert(pnode->hSocket != INVALID_SOCKET);
|
||||||
|
|
||||||
|
epoll_event e;
|
||||||
|
// We're using edge-triggered mode, so it's important that we drain sockets even if no signals come in
|
||||||
|
e.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLERR | EPOLLHUP;
|
||||||
|
e.data.fd = pnode->hSocket;
|
||||||
|
|
||||||
|
int r = epoll_ctl(epollfd, EPOLL_CTL_ADD, pnode->hSocket, &e);
|
||||||
|
if (r != 0) {
|
||||||
|
LogPrint(BCLog::NET, "%s -- epoll_ctl(%d, %d, %d, ...) failed. error: %s\n", __func__,
|
||||||
|
epollfd, EPOLL_CTL_ADD, pnode->hSocket, NetworkErrorString(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CConnman::UnregisterEvents(CNode *pnode)
|
||||||
|
{
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
if (socketEventsMode != SOCKETEVENTS_EPOLL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK(pnode->cs_hSocket);
|
||||||
|
if (pnode->hSocket == INVALID_SOCKET) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = epoll_ctl(epollfd, EPOLL_CTL_DEL, pnode->hSocket, nullptr);
|
||||||
|
if (r != 0) {
|
||||||
|
LogPrint(BCLog::NET, "%s -- epoll_ctl(%d, %d, %d, ...) failed. error: %s\n", __func__,
|
||||||
|
epollfd, EPOLL_CTL_DEL, pnode->hSocket, NetworkErrorString(WSAGetLastError()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
10
src/net.h
10
src/net.h
@ -146,6 +146,7 @@ public:
|
|||||||
enum SocketEventsMode {
|
enum SocketEventsMode {
|
||||||
SOCKETEVENTS_SELECT = 0,
|
SOCKETEVENTS_SELECT = 0,
|
||||||
SOCKETEVENTS_POLL = 1,
|
SOCKETEVENTS_POLL = 1,
|
||||||
|
SOCKETEVENTS_EPOLL = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Options
|
struct Options
|
||||||
@ -485,6 +486,9 @@ private:
|
|||||||
void NotifyNumConnectionsChanged();
|
void NotifyNumConnectionsChanged();
|
||||||
void InactivityCheck(CNode *pnode);
|
void InactivityCheck(CNode *pnode);
|
||||||
bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
|
bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
void SocketEventsEpoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll);
|
||||||
|
#endif
|
||||||
#ifdef USE_POLL
|
#ifdef USE_POLL
|
||||||
void SocketEventsPoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll);
|
void SocketEventsPoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll);
|
||||||
#endif
|
#endif
|
||||||
@ -529,6 +533,9 @@ private:
|
|||||||
// Whether the node should be passed out in ForEach* callbacks
|
// Whether the node should be passed out in ForEach* callbacks
|
||||||
static bool NodeFullyConnected(const CNode* pnode);
|
static bool NodeFullyConnected(const CNode* pnode);
|
||||||
|
|
||||||
|
void RegisterEvents(CNode* pnode);
|
||||||
|
void UnregisterEvents(CNode* pnode);
|
||||||
|
|
||||||
// Network usage totals
|
// Network usage totals
|
||||||
CCriticalSection cs_totalBytesRecv;
|
CCriticalSection cs_totalBytesRecv;
|
||||||
CCriticalSection cs_totalBytesSent;
|
CCriticalSection cs_totalBytesSent;
|
||||||
@ -603,6 +610,9 @@ private:
|
|||||||
std::atomic<bool> wakeupSelectNeeded{false};
|
std::atomic<bool> wakeupSelectNeeded{false};
|
||||||
|
|
||||||
SocketEventsMode socketEventsMode;
|
SocketEventsMode socketEventsMode;
|
||||||
|
#ifdef USE_EPOLL
|
||||||
|
int epollfd{-1};
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Protected by cs_vNodes */
|
/** Protected by cs_vNodes */
|
||||||
std::unordered_map<NodeId, CNode*> mapReceivableNodes GUARDED_BY(cs_vNodes);
|
std::unordered_map<NodeId, CNode*> mapReceivableNodes GUARDED_BY(cs_vNodes);
|
||||||
|
@ -494,6 +494,9 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
|
|||||||
case CConnman::SOCKETEVENTS_POLL:
|
case CConnman::SOCKETEVENTS_POLL:
|
||||||
strSocketEvents = "poll";
|
strSocketEvents = "poll";
|
||||||
break;
|
break;
|
||||||
|
case CConnman::SOCKETEVENTS_EPOLL:
|
||||||
|
strSocketEvents = "epoll";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user