Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Epoll.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_IO_EPOLL_HPP
18#define TOOLBOX_IO_EPOLL_HPP
19
20#include <toolbox/io/Event.hpp>
22
23#include <sys/epoll.h>
24
25namespace toolbox {
26namespace os {
27
30inline FileHandle epoll_create(int size, std::error_code& ec) noexcept
31{
32 const auto ret = ::epoll_create(size);
33 if (ret < 0) {
35 }
36 return ret;
37}
38
42{
43 const auto fd = ::epoll_create(size);
44 if (fd < 0) {
45 throw std::system_error{make_error(errno), "epoll_create"};
46 }
47 return fd;
48}
49
51inline FileHandle epoll_create1(int flags, std::error_code& ec) noexcept
52{
53 const auto ret = ::epoll_create1(flags);
54 if (ret < 0) {
56 }
57 return ret;
58}
59
62{
63 const auto fd = ::epoll_create1(flags);
64 if (fd < 0) {
65 throw std::system_error{make_error(errno), "epoll_create1"};
66 }
67 return fd;
68}
69
71inline int epoll_ctl(int epfd, int op, int fd, epoll_event event, std::error_code& ec) noexcept
72{
73 const auto ret = ::epoll_ctl(epfd, op, fd, &event);
74 if (ret < 0) {
76 }
77 return ret;
78}
79
81inline void epoll_ctl(int epfd, int op, int fd, epoll_event event)
82{
83 const auto ret = ::epoll_ctl(epfd, op, fd, &event);
84 if (ret < 0) {
85 throw std::system_error{make_error(errno), "epoll_ctl"};
86 }
87}
88
90inline int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout,
91 std::error_code& ec) noexcept
92{
93 const auto ret = ::epoll_wait(epfd, events, maxevents, timeout);
94 if (ret < 0) {
96 }
97 return ret;
98}
99
101inline int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout)
102{
103 const auto ret = ::epoll_wait(epfd, events, maxevents, timeout);
104 if (ret < 0) {
105 throw std::system_error{make_error(errno), "epoll_wait"};
106 }
107 return ret;
108}
109
110} // namespace os
111inline namespace io {
112
113enum : unsigned {
116
119
124
128
133
142
147
153};
154
156
157class Epoll {
158 public:
160
161 static constexpr int fd(const Event& ev) noexcept
162 {
163 return static_cast<int>(ev.data.u64 & 0xffffffff);
164 }
165 static constexpr int sid(const Event& ev) noexcept
166 {
167 return static_cast<int>(ev.data.u64 >> 32);
168 }
169 explicit Epoll(int flags = 0)
170 : epfd_{os::epoll_create1(flags)}
171 , tfd_{TFD_NONBLOCK}
172 {
173 add(tfd_.fd(), 0, EpollIn);
174 }
175 ~Epoll() { del(tfd_.fd()); }
176
177 // Copy.
178 Epoll(const Epoll&) = delete;
179 Epoll& operator=(const Epoll&) = delete;
180
181 // Move.
184
188 int timer_fd() const noexcept { return tfd_.fd(); }
189
190 void swap(Epoll& rhs) noexcept { std::swap(epfd_, rhs.epfd_); }
191
193 int wait(Event buf[], std::size_t size, std::error_code& ec) noexcept
194 {
196 // Only set the timer if it has changed.
197 if (timeout != timeout_) {
198 // A zero timeout will disarm the timer.
199 tfd_.set_time(0, timeout, ec);
200 if (ec) {
201 return 0;
202 }
203 timeout_ = timeout;
204 }
205 return os::epoll_wait(*epfd_, buf, size, -1, ec);
206 }
211 int wait(Event buf[], std::size_t size, MonoTime timeout, std::error_code& ec) noexcept
212 {
213 // Only set the timer if it has changed.
214 if (timeout != timeout_) {
215 // A zero timeout will disarm the timer.
216 tfd_.set_time(0, timeout, ec);
217 if (ec) {
218 return 0;
219 }
220 timeout_ = timeout;
221 }
222 // Do not block if timer is zero.
223 return os::epoll_wait(*epfd_, buf, size, is_zero(timeout) ? 0 : -1, ec);
224 }
225 void add(int fd, int sid, unsigned events)
226 {
227 Event ev;
228 mod(ev, fd, sid, events);
229 os::epoll_ctl(*epfd_, EPOLL_CTL_ADD, fd, ev);
230 }
231 void del(int fd) noexcept
232 {
233 // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required a non-null pointer
234 // in event, even though this argument is ignored.
235 Event ev{};
236 std::error_code ec;
237 os::epoll_ctl(*epfd_, EPOLL_CTL_DEL, fd, ev, ec);
238 }
239 void mod(int fd, int sid, unsigned events, std::error_code& ec) noexcept
240 {
241 Event ev;
242 mod(ev, fd, sid, events);
243 os::epoll_ctl(*epfd_, EPOLL_CTL_MOD, fd, ev, ec);
244 }
245 void mod(int fd, int sid, unsigned events)
246 {
247 Event ev;
248 mod(ev, fd, sid, events);
249 os::epoll_ctl(*epfd_, EPOLL_CTL_MOD, fd, ev);
250 }
251
252 private:
253 static void mod(Event& ev, int fd, int sid, unsigned events) noexcept
254 {
255 ev.events = events;
256 ev.data.u64 = static_cast<std::uint64_t>(sid) << 32 | fd;
257 }
258 FileHandle epfd_;
260 MonoTime timeout_{};
261};
262
263} // namespace io
264} // namespace toolbox
265
266#endif // TOOLBOX_IO_EPOLL_HPP
static constexpr int sid(const Event &ev) noexcept
Definition Epoll.hpp:165
int timer_fd() const noexcept
Definition Epoll.hpp:188
void del(int fd) noexcept
Definition Epoll.hpp:231
void swap(Epoll &rhs) noexcept
Definition Epoll.hpp:190
int wait(Event buf[], std::size_t size, MonoTime timeout, std::error_code &ec) noexcept
Definition Epoll.hpp:211
void mod(int fd, int sid, unsigned events, std::error_code &ec) noexcept
Definition Epoll.hpp:239
static constexpr int fd(const Event &ev) noexcept
Definition Epoll.hpp:161
void add(int fd, int sid, unsigned events)
Definition Epoll.hpp:225
int wait(Event buf[], std::size_t size, std::error_code &ec) noexcept
Returns the number of file descriptors that are ready.
Definition Epoll.hpp:193
Epoll & operator=(const Epoll &)=delete
void mod(int fd, int sid, unsigned events)
Definition Epoll.hpp:245
Epoll(const Epoll &)=delete
Epoll(int flags=0)
Definition Epoll.hpp:169
Epoll(Epoll &&) noexcept=default
EpollEvent Event
Definition Epoll.hpp:159
@ EpollIn
The associated file is available for read(2) operations.
Definition Epoll.hpp:115
@ EpollOut
The associated file is available for write(2) operations.
Definition Epoll.hpp:118
epoll_event EpollEvent
Definition Epoll.hpp:155
int epoll_wait(int epfd, epoll_event *events, int maxevents, int timeout, std::error_code &ec) noexcept
Wait for an I/O event on an epoll file descriptor.
Definition Epoll.hpp:90
int epoll_ctl(int epfd, int op, int fd, epoll_event event, std::error_code &ec) noexcept
Control interface for an epoll file descriptor.
Definition Epoll.hpp:71
FileHandle epoll_create1(int flags, std::error_code &ec) noexcept
Open a new epoll instance. If flags is zero, then epoll_create1() is the same as epoll_create().
Definition Epoll.hpp:51
FileHandle epoll_create(int size, std::error_code &ec) noexcept
Definition Epoll.hpp:30
constexpr bool is_zero(std::chrono::duration< RepT, PeriodT > d) noexcept
Definition Time.hpp:156
MonoClock::time_point MonoTime
Definition Time.hpp:110
std::error_code make_error(int err) noexcept
Definition Error.hpp:25
constexpr std::size_t size(const detail::Struct< detail::Member< TagsT, ValuesT >... > &s)
Definition Struct.hpp:98
constexpr auto bind() noexcept
Definition Slot.hpp:92