From: Remi Gacogne Date: Tue, 15 Sep 2020 13:36:55 +0000 (+0200) Subject: Directly switch between read/write epoll states X-Git-Tag: auth-4.5.0-alpha0~14^2~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9232952699b2b8d650803b478cd2260af1c5a575;p=thirdparty%2Fpdns.git Directly switch between read/write epoll states Altering an existing state instead of removing then adding it back saves a call to `epoll_ctl()`. --- diff --git a/pdns/epollmplexer.cc b/pdns/epollmplexer.cc index 433687d214..1a4b2a3b50 100644 --- a/pdns/epollmplexer.cc +++ b/pdns/epollmplexer.cc @@ -47,6 +47,8 @@ public: virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd=nullptr) override; virtual void removeFD(callbackmap_t& cbmap, int fd) override; + virtual void alterFD(callbackmap_t& from, callbackmap_t& to, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd) override; + string getName() const override { return "epoll"; @@ -91,7 +93,7 @@ EpollFDMultiplexer::EpollFDMultiplexer() : d_eevents(new epoll_event[s_maxevents close(d_epollfd); throw FDMultiplexerException("epoll multiplexer failed self-test: "+string(fe.what())); } - + } void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd) @@ -99,11 +101,11 @@ void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo accountingAddFD(cbmap, fd, toDo, parameter, ttd); struct epoll_event eevent; - + eevent.events = (&cbmap == &d_readCallbacks) ? EPOLLIN : EPOLLOUT; - + eevent.data.u64=0; // placate valgrind (I love it so much) - eevent.data.fd=fd; + eevent.data.fd=fd; if(epoll_ctl(d_epollfd, EPOLL_CTL_ADD, fd, &eevent) < 0) { cbmap.erase(fd); @@ -113,8 +115,7 @@ void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) { - if(!cbmap.erase(fd)) - throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); + accountingRemoveFD(cbmap, fd); struct epoll_event dummy; dummy.events = 0; @@ -124,6 +125,22 @@ void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) throw FDMultiplexerException("Removing fd from epoll set: "+stringerror()); } +void EpollFDMultiplexer::alterFD(callbackmap_t& from, callbackmap_t& to, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd) +{ + accountingRemoveFD(from, fd); + accountingAddFD(to, fd, toDo, parameter, ttd); + + struct epoll_event eevent; + eevent.events = (&to == &d_readCallbacks) ? EPOLLIN : EPOLLOUT; + eevent.data.u64 = 0; // placate valgrind (I love it so much) + eevent.data.fd = fd; + + if (epoll_ctl(d_epollfd, EPOLL_CTL_MOD, fd, &eevent) < 0) { + to.erase(fd); + throw FDMultiplexerException("Altering fd in epoll set: "+stringerror()); + } +} + void EpollFDMultiplexer::getAvailableFDs(std::vector& fds, int timeout) { int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, timeout); @@ -141,7 +158,7 @@ int EpollFDMultiplexer::run(struct timeval* now, int timeout) if(d_inrun) { throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); } - + int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, timeout); gettimeofday(now,0); // MANDATORY @@ -154,13 +171,13 @@ int EpollFDMultiplexer::run(struct timeval* now, int timeout) d_inrun=true; for(int n=0; n < ret; ++n) { d_iter=d_readCallbacks.find(d_eevents[n].data.fd); - + if(d_iter != d_readCallbacks.end()) { d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter); continue; // so we don't refind ourselves as writable! } d_iter=d_writeCallbacks.find(d_eevents[n].data.fd); - + if(d_iter != d_writeCallbacks.end()) { d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter); } @@ -184,7 +201,7 @@ void acceptData(int fd, funcparam_t& parameter) int main() { Socket s(AF_INET, SOCK_DGRAM); - + IPEndpoint loc("0.0.0.0", 2000); s.bind(loc); @@ -199,5 +216,3 @@ int main() sfm.removeReadFD(s.getHandle()); } #endif - - diff --git a/pdns/mplexer.hh b/pdns/mplexer.hh index a2cd0b7507..a948c9f075 100644 --- a/pdns/mplexer.hh +++ b/pdns/mplexer.hh @@ -136,6 +136,16 @@ public: d_writeCallbacks.replace(it, newEntry); } + virtual void alterFDToRead(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t(), const struct timeval* ttd=nullptr) + { + this->alterFD(d_writeCallbacks, d_readCallbacks, fd, toDo, parameter, ttd); + } + + virtual void alterFDToWrite(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t(), const struct timeval* ttd=nullptr) + { + this->alterFD(d_readCallbacks, d_writeCallbacks, fd, toDo, parameter, ttd); + } + virtual std::vector > getTimeouts(const struct timeval& tv, bool writes=false) { std::vector > ret; @@ -209,6 +219,7 @@ protected: virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd=nullptr)=0; virtual void removeFD(callbackmap_t& cbmap, int fd)=0; + bool d_inrun; callbackmap_t::iterator d_iter; @@ -223,7 +234,7 @@ protected: cb.d_ttd = *ttd; } - auto pair = cbmap.insert(cb); + auto pair = cbmap.insert(std::move(cb)); if (!pair.second) { throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice"); } @@ -235,4 +246,12 @@ protected: throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); } } + + virtual void alterFD(callbackmap_t& from, callbackmap_t& to, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd) + { + /* naive implementation */ + removeFD(from, fd); + addFD(to, fd, toDo, parameter, ttd); + } + }; diff --git a/pdns/pollmplexer.cc b/pdns/pollmplexer.cc index 399ad132ae..665b4b823c 100644 --- a/pdns/pollmplexer.cc +++ b/pdns/pollmplexer.cc @@ -70,8 +70,7 @@ void PollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) if(d_inrun && d_iter->d_fd==fd) // trying to remove us! ++d_iter; - if(!cbmap.erase(fd)) - throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); + accountingRemoveFD(cbmap, fd); } vector PollFDMultiplexer::preparePollFD() const