mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 11:32: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
|
||||
# Let's switch socketevents mode to some random mode
|
||||
R=$(($RANDOM%2))
|
||||
R=$(($RANDOM%3))
|
||||
if [ "$R" == "0" ]; then
|
||||
SOCKETEVENTS="select"
|
||||
else
|
||||
elif [ "$R" == "1" ]; then
|
||||
SOCKETEVENTS="poll"
|
||||
else
|
||||
SOCKETEVENTS="epoll"
|
||||
fi
|
||||
fi
|
||||
echo "Using socketevents mode: $SOCKETEVENTS"
|
||||
|
@ -109,6 +109,10 @@ typedef char* sockopt_arg_type;
|
||||
#define USE_POLL
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#define USE_EPOLL
|
||||
#endif
|
||||
|
||||
bool static inline IsSelectableSocket(const SOCKET& s) {
|
||||
#if defined(USE_POLL) || defined(WIN32)
|
||||
return true;
|
||||
|
@ -414,6 +414,9 @@ std::string GetSupportedSocketEventsStr()
|
||||
std::string strSupportedModes = "'select'";
|
||||
#ifdef USE_POLL
|
||||
strSupportedModes += ", 'poll'";
|
||||
#endif
|
||||
#ifdef USE_EPOLL
|
||||
strSupportedModes += ", 'epoll'";
|
||||
#endif
|
||||
return strSupportedModes;
|
||||
}
|
||||
@ -2244,6 +2247,10 @@ bool AppInitMain()
|
||||
#ifdef USE_POLL
|
||||
} else if (strSocketEventsMode == "poll") {
|
||||
connOptions.socketEventsMode = CConnman::SOCKETEVENTS_POLL;
|
||||
#endif
|
||||
#ifdef USE_EPOLL
|
||||
} else if (strSocketEventsMode == "epoll") {
|
||||
connOptions.socketEventsMode = CConnman::SOCKETEVENTS_EPOLL;
|
||||
#endif
|
||||
} else {
|
||||
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>
|
||||
#endif
|
||||
|
||||
#ifdef USE_EPOLL
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#include <miniupnpc/miniupnpc.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);
|
||||
CloseSocket(hSocket);
|
||||
}
|
||||
@ -1256,6 +1262,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
LOCK(cs_vNodes);
|
||||
vNodes.push_back(pnode);
|
||||
mapSocketToNode.emplace(pnode->hSocket, pnode);
|
||||
RegisterEvents(pnode);
|
||||
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();
|
||||
}
|
||||
|
||||
#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
|
||||
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)
|
||||
{
|
||||
switch (socketEventsMode) {
|
||||
#ifdef USE_EPOLL
|
||||
case SOCKETEVENTS_EPOLL:
|
||||
SocketEventsEpoll(recv_set, send_set, error_set, fOnlyPoll);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_POLL
|
||||
case SOCKETEVENTS_POLL:
|
||||
SocketEventsPoll(recv_set, send_set, error_set, fOnlyPoll);
|
||||
@ -2623,6 +2662,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
vNodes.push_back(pnode);
|
||||
RegisterEvents(pnode);
|
||||
WakeSelect();
|
||||
}
|
||||
}
|
||||
@ -2745,6 +2785,20 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
|
||||
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));
|
||||
|
||||
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
|
||||
@ -2886,6 +2940,16 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||
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 (clientInterface) {
|
||||
clientInterface->ThreadSafeMessageBox(
|
||||
@ -2972,6 +3036,19 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||
if (fcntl(wakeupPipe[1], F_SETFL, fFlags | O_NONBLOCK) == -1) {
|
||||
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
|
||||
|
||||
@ -3085,9 +3162,15 @@ void CConnman::Stop()
|
||||
pnode->CloseSocketDisconnect(this);
|
||||
}
|
||||
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))
|
||||
LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
|
||||
}
|
||||
|
||||
// clean up some globals (to help leak detection)
|
||||
for (CNode *pnode : vNodes) {
|
||||
@ -3108,6 +3191,16 @@ void CConnman::Stop()
|
||||
semOutbound.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
|
||||
if (wakeupPipe[0] != -1) close(wakeupPipe[0]);
|
||||
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();
|
||||
}
|
||||
|
||||
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 {
|
||||
SOCKETEVENTS_SELECT = 0,
|
||||
SOCKETEVENTS_POLL = 1,
|
||||
SOCKETEVENTS_EPOLL = 2,
|
||||
};
|
||||
|
||||
struct Options
|
||||
@ -485,6 +486,9 @@ private:
|
||||
void NotifyNumConnectionsChanged();
|
||||
void InactivityCheck(CNode *pnode);
|
||||
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
|
||||
void SocketEventsPoll(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set, bool fOnlyPoll);
|
||||
#endif
|
||||
@ -529,6 +533,9 @@ private:
|
||||
// Whether the node should be passed out in ForEach* callbacks
|
||||
static bool NodeFullyConnected(const CNode* pnode);
|
||||
|
||||
void RegisterEvents(CNode* pnode);
|
||||
void UnregisterEvents(CNode* pnode);
|
||||
|
||||
// Network usage totals
|
||||
CCriticalSection cs_totalBytesRecv;
|
||||
CCriticalSection cs_totalBytesSent;
|
||||
@ -603,6 +610,9 @@ private:
|
||||
std::atomic<bool> wakeupSelectNeeded{false};
|
||||
|
||||
SocketEventsMode socketEventsMode;
|
||||
#ifdef USE_EPOLL
|
||||
int epollfd{-1};
|
||||
#endif
|
||||
|
||||
/** Protected 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:
|
||||
strSocketEvents = "poll";
|
||||
break;
|
||||
case CConnman::SOCKETEVENTS_EPOLL:
|
||||
strSocketEvents = "epoll";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user