1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "event_loop_epoll.h"
17
18 #ifdef EVENT_LOOP_USE_EPOLL
19 #include <sys/eventfd.h>
20 #include "event_impl.h"
21 #include "log_print.h"
22 #include "db_errno.h"
23
24 namespace DistributedDB {
EventLoopEpoll()25 EventLoopEpoll::EventLoopEpoll()
26 : pollFdCount_(0)
27 {
28 }
29
~EventLoopEpoll()30 EventLoopEpoll::~EventLoopEpoll()
31 {
32 if (wakeUpFd_.IsValid()) {
33 wakeUpFd_.Close();
34 }
35 if (epollFd_.IsValid()) {
36 epollFd_.Close();
37 }
38 }
39
Initialize()40 int EventLoopEpoll::Initialize()
41 {
42 if (epollFd_.IsValid()) {
43 return -E_INVALID_ARGS;
44 }
45
46 int errCode;
47 wakeUpFd_ = EventFd(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
48 if (!wakeUpFd_.IsValid()) {
49 errCode = -errno;
50 LOGE("Create event fd failed, err:'%d'", errCode);
51 return errCode;
52 }
53
54 epollFd_ = EventFd(epoll_create(EPOLL_INIT_REVENTS));
55 if (!epollFd_.IsValid()) {
56 errCode = -errno;
57 wakeUpFd_.Close();
58 LOGE("Create epoll fd failed, err:'%d'", errCode);
59 return errCode;
60 }
61
62 struct epoll_event event;
63 event.events = EPOLLIN;
64 event.data.ptr = this;
65 errCode = epoll_ctl(epollFd_, EPOLL_CTL_ADD, wakeUpFd_, &event);
66 if (errCode < 0) {
67 errCode = -errno;
68 epollFd_.Close();
69 wakeUpFd_.Close();
70 LOGE("Add wake up fd to epoll failed, err:'%d'", errCode);
71 return errCode;
72 }
73
74 ++pollFdCount_;
75 return E_OK;
76 }
77
Prepare(const std::set<EventImpl * > & polling)78 int EventLoopEpoll::Prepare(const std::set<EventImpl *> &polling)
79 {
80 if (pollFdCount_ > 0) {
81 revents_.resize(pollFdCount_);
82 return E_OK;
83 }
84 LOGE("Prepared epoll loop failed, fd count:'%d'", pollFdCount_);
85 return -E_INTERNAL_ERROR;
86 }
87
Poll(EventTime sleepTime)88 int EventLoopEpoll::Poll(EventTime sleepTime)
89 {
90 if (sleepTime > INT_MAX) {
91 LOGE("[EventLoopEpoll][Poll] sleepTime is too large!");
92 return -E_INVALID_ARGS;
93 }
94 int nReady = epoll_wait(epollFd_, &revents_[0], revents_.size(), sleepTime);
95 if (nReady < 0) {
96 int errCode = -errno;
97 if (errCode != -EINTR) {
98 LOGE("Call epoll wait failed, err:'%d'", errCode);
99 return errCode;
100 }
101 nReady = 0;
102 }
103
104 for (int index = 0; index < nReady; ++index) {
105 struct epoll_event *revent = &revents_[index];
106 if (revent->data.ptr == this) {
107 EpollWokenUp();
108 continue;
109 }
110 auto event = static_cast<EventImpl *>(revent->data.ptr);
111 EventsMask revents = CalEventsMask(revent->events);
112 event->SetRevents(revents);
113 }
114 return E_OK;
115 }
116
WakeUp()117 int EventLoopEpoll::WakeUp()
118 {
119 int64_t incValue = 1;
120
121 while (true) {
122 int nWrite = write(wakeUpFd_, &incValue, sizeof(incValue));
123 if (nWrite == static_cast<int>(sizeof(incValue))) {
124 break;
125 }
126
127 int errCode = -errno;
128 if (errCode == -EINTR) {
129 continue;
130 }
131 if (errCode == -EAGAIN) {
132 // We have already signalled the loop.
133 break;
134 }
135 LOGE("Write loop wake up data failed, err:'%d'", errCode);
136 return errCode;
137 }
138 return E_OK;
139 }
140
Exit(const std::set<EventImpl * > & polling)141 int EventLoopEpoll::Exit(const std::set<EventImpl *> &polling)
142 {
143 if (revents_.capacity() > 0) {
144 std::vector<epoll_event> revents;
145 revents.swap(revents_);
146 }
147 wakeUpFd_.Close();
148 epollFd_.Close();
149 pollFdCount_ = 0;
150 return E_OK;
151 }
152
EpollWokenUp()153 void EventLoopEpoll::EpollWokenUp()
154 {
155 while (true) {
156 int64_t intValue;
157 int nRead = read(wakeUpFd_, &intValue, sizeof(intValue));
158 if (nRead < 0) {
159 int errCode = -errno;
160 if (errCode == -EINTR) {
161 continue;
162 }
163 if (errCode != -EAGAIN) {
164 LOGE("Clear loop wake up data failed, err:'%d'", errCode);
165 }
166 }
167 break;
168 }
169 }
170
CalEpollEvents(EventsMask events) const171 uint32_t EventLoopEpoll::CalEpollEvents(EventsMask events) const
172 {
173 uint32_t epollEvents = 0;
174 if (events & IEvent::ET_READ) { // LCOV_EXCL_BR_LINE
175 epollEvents |= EPOLLIN;
176 }
177 if (events & IEvent::ET_WRITE) { // LCOV_EXCL_BR_LINE
178 epollEvents |= EPOLLOUT;
179 }
180 if (events & IEvent::ET_ERROR) { // LCOV_EXCL_BR_LINE
181 epollEvents |= EPOLLERR;
182 }
183 return epollEvents;
184 }
185
CalEventsMask(uint32_t epollEvents)186 EventsMask EventLoopEpoll::CalEventsMask(uint32_t epollEvents)
187 {
188 EventsMask events = 0;
189 if (epollEvents & EPOLLIN) { // LCOV_EXCL_BR_LINE
190 events |= IEvent::ET_READ;
191 }
192 if (epollEvents & EPOLLOUT) { // LCOV_EXCL_BR_LINE
193 events |= IEvent::ET_WRITE;
194 }
195 if (epollEvents & EPOLLERR) { // LCOV_EXCL_BR_LINE
196 events |= IEvent::ET_ERROR;
197 }
198 return events;
199 }
200
EpollCtl(int operation,EventImpl * event,EventsMask events)201 int EventLoopEpoll::EpollCtl(int operation, EventImpl *event, EventsMask events)
202 {
203 if (operation != EPOLL_CTL_ADD &&
204 operation != EPOLL_CTL_MOD &&
205 operation != EPOLL_CTL_DEL) { // LCOV_EXCL_BR_LINE
206 return -E_INVALID_ARGS;
207 }
208 if (event == nullptr) { // LCOV_EXCL_BR_LINE
209 return -E_INVALID_ARGS;
210 }
211
212 EventFd fd = event->GetEventFd();
213 if (fd.IsValid()) { // LCOV_EXCL_BR_LINE
214 return -E_INVALID_ARGS;
215 }
216
217 uint32_t epollEvents = CalEpollEvents(events);
218 struct epoll_event epollEvent;
219 epollEvent.events = epollEvents;
220 epollEvent.data.ptr = event;
221
222 int errCode = epoll_ctl(epollFd_, operation, fd, &epollEvent);
223 if (errCode < 0) { // LCOV_EXCL_BR_LINE
224 errCode = -errno;
225 return errCode;
226 }
227 return E_OK;
228 }
229
AddEvent(EventImpl * event)230 int EventLoopEpoll::AddEvent(EventImpl *event)
231 {
232 if (event == nullptr) { // LCOV_EXCL_BR_LINE
233 return -E_INVALID_ARGS;
234 }
235
236 EventsMask events = event->GetEvents();
237 int errCode = EpollCtl(EPOLL_CTL_ADD, event, events);
238 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
239 LOGE("Add fd to epoll set failed, err:'%d'", errCode);
240 return errCode;
241 }
242
243 ++pollFdCount_;
244 return E_OK;
245 }
246
RemoveEvent(EventImpl * event)247 int EventLoopEpoll::RemoveEvent(EventImpl *event)
248 {
249 if (event == nullptr) { // LCOV_EXCL_BR_LINE
250 return -E_INVALID_ARGS;
251 }
252
253 EventsMask events = event->GetEvents();
254 int errCode = EpollCtl(EPOLL_CTL_DEL, event, events);
255 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
256 LOGE("Remove fd from epoll set failed, err:'%d'", errCode);
257 return errCode;
258 }
259
260 --pollFdCount_;
261 return E_OK;
262 }
263
ModifyEvent(EventImpl * event,bool isAdd,EventsMask events)264 int EventLoopEpoll::ModifyEvent(EventImpl *event, bool isAdd, EventsMask events)
265 {
266 if (event == nullptr) { // LCOV_EXCL_BR_LINE
267 return -E_INVALID_ARGS;
268 }
269
270 EventsMask newEvents = event->GetEvents();
271 if (isAdd) { // LCOV_EXCL_BR_LINE
272 newEvents |= events;
273 } else {
274 newEvents &= ~events;
275 }
276
277 int errCode = EpollCtl(EPOLL_CTL_MOD, event, newEvents);
278 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
279 LOGE("Modify fd in epoll set failed, err:'%d'", errCode);
280 return errCode;
281 }
282 return E_OK;
283 }
284
285 DEFINE_OBJECT_TAG_FACILITIES(EventLoopEpoll)
286 }
287 #endif // EVENT_LOOP_USE_EPOLL
288