]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/epollmplexer.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / epollmplexer.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
a1dfcec8
BH
25#include "mplexer.hh"
26#include "sstuff.hh"
27#include <iostream>
28#include <unistd.h>
29#include "misc.hh"
3c19a35f 30#ifdef __linux__
a1dfcec8 31#include <sys/epoll.h>
3c19a35f 32#endif
a1dfcec8 33
10f4eea8 34#include "namespaces.hh"
a1dfcec8 35
a1dfcec8
BH
36class EpollFDMultiplexer : public FDMultiplexer
37{
38public:
39 EpollFDMultiplexer();
40 virtual ~EpollFDMultiplexer()
41 {
42 close(d_epollfd);
43 }
44
5bdbb83d
RG
45 virtual int run(struct timeval* tv, int timeout=500) override;
46 virtual void getAvailableFDs(std::vector<int>& fds, int timeout) override;
a1dfcec8 47
27ae2e3c 48 virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd=nullptr) override;
5bdbb83d
RG
49 virtual void removeFD(callbackmap_t& cbmap, int fd) override;
50 string getName() const override
1f4abb20
BH
51 {
52 return "epoll";
53 }
a1dfcec8
BH
54private:
55 int d_epollfd;
56 boost::shared_array<epoll_event> d_eevents;
57 static int s_maxevents; // not a hard maximum
58};
59
1f4abb20 60
aa136564 61static FDMultiplexer* makeEpoll()
a1dfcec8
BH
62{
63 return new EpollFDMultiplexer();
64}
65
aa136564 66static struct EpollRegisterOurselves
1f4abb20 67{
aa136564
BH
68 EpollRegisterOurselves() {
69 FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeEpoll)); // priority 0!
1f4abb20 70 }
aa136564 71} doItEpoll;
1f4abb20 72
a1dfcec8 73int EpollFDMultiplexer::s_maxevents=1024;
5bdbb83d 74
a1dfcec8
BH
75EpollFDMultiplexer::EpollFDMultiplexer() : d_eevents(new epoll_event[s_maxevents])
76{
77 d_epollfd=epoll_create(s_maxevents); // not hard max
78 if(d_epollfd < 0)
79 throw FDMultiplexerException("Setting up epoll: "+stringerror());
98d0ee4a
BH
80 int fd=socket(AF_INET, SOCK_DGRAM, 0); // for self-test
81 if(fd < 0)
82 return;
83 try {
84 addReadFD(fd, 0);
85 removeReadFD(fd);
86 close(fd);
87 return;
88 }
89 catch(FDMultiplexerException &fe) {
90 close(fd);
0a7f24cb 91 close(d_epollfd);
98d0ee4a
BH
92 throw FDMultiplexerException("epoll multiplexer failed self-test: "+string(fe.what()));
93 }
94
a1dfcec8
BH
95}
96
27ae2e3c 97void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter, const struct timeval* ttd)
a1dfcec8 98{
27ae2e3c 99 accountingAddFD(cbmap, fd, toDo, parameter, ttd);
a1dfcec8 100
a1dfcec8
BH
101 struct epoll_event eevent;
102
103 eevent.events = (&cbmap == &d_readCallbacks) ? EPOLLIN : EPOLLOUT;
104
105 eevent.data.u64=0; // placate valgrind (I love it so much)
106 eevent.data.fd=fd;
107
c454d11b
BH
108 if(epoll_ctl(d_epollfd, EPOLL_CTL_ADD, fd, &eevent) < 0) {
109 cbmap.erase(fd);
a1dfcec8 110 throw FDMultiplexerException("Adding fd to epoll set: "+stringerror());
c454d11b 111 }
a1dfcec8
BH
112}
113
114void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
115{
a1dfcec8 116 if(!cbmap.erase(fd))
335da0ba 117 throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
a1dfcec8 118
3368984f
BH
119 struct epoll_event dummy;
120 dummy.events = 0;
121 dummy.data.u64 = 0;
122
123 if(epoll_ctl(d_epollfd, EPOLL_CTL_DEL, fd, &dummy) < 0)
a1dfcec8
BH
124 throw FDMultiplexerException("Removing fd from epoll set: "+stringerror());
125}
126
5bdbb83d
RG
127void EpollFDMultiplexer::getAvailableFDs(std::vector<int>& fds, int timeout)
128{
129 int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, timeout);
130
131 if(ret < 0 && errno!=EINTR)
132 throw FDMultiplexerException("epoll returned error: "+stringerror());
133
134 for(int n=0; n < ret; ++n) {
135 fds.push_back(d_eevents[n].data.fd);
136 }
137}
138
0e663c3b 139int EpollFDMultiplexer::run(struct timeval* now, int timeout)
a1dfcec8
BH
140{
141 if(d_inrun) {
142 throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
143 }
144
0e663c3b 145 int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, timeout);
55df795b 146 gettimeofday(now,0); // MANDATORY
5bdbb83d 147
a1dfcec8 148 if(ret < 0 && errno!=EINTR)
abbd6830 149 throw FDMultiplexerException("epoll returned error: "+stringerror());
a1dfcec8 150
f3c5773b 151 if(ret < 1) // thanks AB!
a1dfcec8
BH
152 return 0;
153
154 d_inrun=true;
a1dfcec8
BH
155 for(int n=0; n < ret; ++n) {
156 d_iter=d_readCallbacks.find(d_eevents[n].data.fd);
157
0bff046b 158 if(d_iter != d_readCallbacks.end()) {
ac3da0c2 159 d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
abbd6830 160 continue; // so we don't refind ourselves as writable!
0bff046b 161 }
a1dfcec8
BH
162 d_iter=d_writeCallbacks.find(d_eevents[n].data.fd);
163
0bff046b 164 if(d_iter != d_writeCallbacks.end()) {
ac3da0c2 165 d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter);
0bff046b 166 }
a1dfcec8 167 }
a1dfcec8 168 d_inrun=false;
0e663c3b 169 return ret;
a1dfcec8
BH
170}
171
172#if 0
d8f6d49f 173void acceptData(int fd, funcparam_t& parameter)
a1dfcec8
BH
174{
175 cout<<"Have data on fd "<<fd<<endl;
d8f6d49f 176 Socket* sock=funcparam_t_cast<Socket*>(parameter);
a1dfcec8
BH
177 string packet;
178 IPEndpoint rem;
179 sock->recvFrom(packet, rem);
180 cout<<"Received "<<packet.size()<<" bytes!\n";
181}
182
183
184int main()
185{
a5794017 186 Socket s(AF_INET, SOCK_DGRAM);
a1dfcec8
BH
187
188 IPEndpoint loc("0.0.0.0", 2000);
189 s.bind(loc);
190
191 EpollFDMultiplexer sfm;
192
193 sfm.addReadFD(s.getHandle(), &acceptData, &s);
194
195 for(int n=0; n < 100 ; ++n) {
196 sfm.run();
197 }
198 sfm.removeReadFD(s.getHandle());
199 sfm.removeReadFD(s.getHandle());
200}
201#endif
202
203