]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/epollmplexer.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <sys/epoll.h>
34 #include "namespaces.hh"
36 class EpollFDMultiplexer
: public FDMultiplexer
39 EpollFDMultiplexer(unsigned int maxEventsHint
);
40 ~EpollFDMultiplexer() override
47 int run(struct timeval
* tv
, int timeout
= 500) override
;
48 void getAvailableFDs(std::vector
<int>& fds
, int timeout
) override
;
50 void addFD(int fd
, FDMultiplexer::EventKind kind
) override
;
51 void removeFD(int fd
, FDMultiplexer::EventKind kind
) override
;
52 void alterFD(int fd
, FDMultiplexer::EventKind from
, FDMultiplexer::EventKind to
) override
;
54 string
getName() const override
61 std::vector
<epoll_event
> d_eevents
;
64 static FDMultiplexer
* makeEpoll(unsigned int maxEventsHint
)
66 return new EpollFDMultiplexer(maxEventsHint
);
69 static struct EpollRegisterOurselves
71 EpollRegisterOurselves()
73 FDMultiplexer::getMultiplexerMap().emplace(0, &makeEpoll
); // priority 0!
77 EpollFDMultiplexer::EpollFDMultiplexer(unsigned int maxEventsHint
) :
78 d_eevents(maxEventsHint
)
80 d_epollfd
= epoll_create(static_cast<int>(maxEventsHint
)); // not hard max, just a hint that is actually ignored since Linux 2.6.8
82 throw FDMultiplexerException("Setting up epoll: " + stringerror());
84 int fd
= socket(AF_INET
, SOCK_DGRAM
, 0); // for self-test
96 catch (const FDMultiplexerException
& fe
) {
99 throw FDMultiplexerException("epoll multiplexer failed self-test: " + string(fe
.what()));
103 static uint32_t convertEventKind(FDMultiplexer::EventKind kind
)
106 case FDMultiplexer::EventKind::Read
:
108 case FDMultiplexer::EventKind::Write
:
110 case FDMultiplexer::EventKind::Both
:
111 return EPOLLIN
| EPOLLOUT
;
114 throw std::runtime_error("Unhandled event kind in the epoll multiplexer");
117 void EpollFDMultiplexer::addFD(int fd
, FDMultiplexer::EventKind kind
)
119 struct epoll_event eevent
;
121 eevent
.events
= convertEventKind(kind
);
123 eevent
.data
.u64
= 0; // placate valgrind (I love it so much)
126 if (epoll_ctl(d_epollfd
, EPOLL_CTL_ADD
, fd
, &eevent
) < 0) {
127 throw FDMultiplexerException("Adding fd to epoll set: " + stringerror());
131 void EpollFDMultiplexer::removeFD(int fd
, FDMultiplexer::EventKind
)
133 struct epoll_event dummy
;
137 if (epoll_ctl(d_epollfd
, EPOLL_CTL_DEL
, fd
, &dummy
) < 0) {
138 throw FDMultiplexerException("Removing fd from epoll set: " + stringerror());
142 void EpollFDMultiplexer::alterFD(int fd
, FDMultiplexer::EventKind
, FDMultiplexer::EventKind to
)
144 struct epoll_event eevent
;
145 eevent
.events
= convertEventKind(to
);
146 eevent
.data
.u64
= 0; // placate valgrind (I love it so much)
149 if (epoll_ctl(d_epollfd
, EPOLL_CTL_MOD
, fd
, &eevent
) < 0) {
150 throw FDMultiplexerException("Altering fd in epoll set: " + stringerror());
154 void EpollFDMultiplexer::getAvailableFDs(std::vector
<int>& fds
, int timeout
)
156 int ret
= epoll_wait(d_epollfd
, d_eevents
.data(), d_eevents
.size(), timeout
);
158 if (ret
< 0 && errno
!= EINTR
) {
159 throw FDMultiplexerException("epoll returned error: " + stringerror());
162 for (int n
= 0; n
< ret
; ++n
) {
163 fds
.push_back(d_eevents
[n
].data
.fd
);
167 int EpollFDMultiplexer::run(struct timeval
* now
, int timeout
)
170 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
173 int ret
= epoll_wait(d_epollfd
, d_eevents
.data(), d_eevents
.size(), timeout
);
174 gettimeofday(now
, nullptr); // MANDATORY
176 if (ret
< 0 && errno
!= EINTR
) {
177 throw FDMultiplexerException("epoll returned error: " + stringerror());
180 if (ret
< 1) { // thanks AB!
186 for (int n
= 0; n
< ret
; ++n
) {
187 if ((d_eevents
[n
].events
& EPOLLIN
) || (d_eevents
[n
].events
& EPOLLERR
) || (d_eevents
[n
].events
& EPOLLHUP
)) {
188 const auto& iter
= d_readCallbacks
.find(d_eevents
[n
].data
.fd
);
189 if (iter
!= d_readCallbacks
.end()) {
190 iter
->d_callback(iter
->d_fd
, iter
->d_parameter
);
195 if ((d_eevents
[n
].events
& EPOLLOUT
) || (d_eevents
[n
].events
& EPOLLERR
) || (d_eevents
[n
].events
& EPOLLHUP
)) {
196 const auto& iter
= d_writeCallbacks
.find(d_eevents
[n
].data
.fd
);
197 if (iter
!= d_writeCallbacks
.end()) {
198 iter
->d_callback(iter
->d_fd
, iter
->d_parameter
);
209 void acceptData(int fd
, funcparam_t
& parameter
)
211 cout
<<"Have data on fd "<<fd
<<endl
;
212 Socket
* sock
=funcparam_t_cast
<Socket
*>(parameter
);
215 sock
->recvFrom(packet
, rem
);
216 cout
<<"Received "<<packet
.size()<<" bytes!\n";
222 Socket
s(AF_INET
, SOCK_DGRAM
);
224 IPEndpoint
loc("0.0.0.0", 2000);
227 EpollFDMultiplexer sfm
;
229 sfm
.addReadFD(s
.getHandle(), &acceptData
, &s
);
231 for(int n
=0; n
< 100 ; ++n
) {
234 sfm
.removeReadFD(s
.getHandle());
235 sfm
.removeReadFD(s
.getHandle());