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