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 <errno.h>
17 #include <stdio.h>
18 #include "le_epoll.h"
19 #include "le_idle.h"
20 #include "le_timer.h"
21 
IsValid_(const EventEpoll * loop)22 static int IsValid_(const EventEpoll *loop)
23 {
24     return loop->epollFd >= 0;
25 }
26 
GetEpollEvent_(int fd,int op,struct epoll_event * event)27 static void GetEpollEvent_(int fd, int op, struct epoll_event *event)
28 {
29     event->data.fd = fd;
30     if (LE_TEST_FLAGS(op, EVENT_READ)) {
31         event->events |= EPOLLIN;
32     }
33     if (LE_TEST_FLAGS(op, EVENT_WRITE)) {
34         event->events |= EPOLLOUT;
35     }
36 }
37 
Close_(const EventLoop * loop)38 static LE_STATUS Close_(const EventLoop *loop)
39 {
40     LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
41     EventEpoll *epoll = (EventEpoll *)loop;
42     LE_LOGV("Close_ epollFd %d", epoll->epollFd);
43     close(epoll->epollFd);
44     free(epoll);
45     return LE_SUCCESS;
46 }
47 
AddEvent_(const EventLoop * loop,const BaseTask * task,int op)48 static LE_STATUS AddEvent_(const EventLoop *loop, const BaseTask *task, int op)
49 {
50     LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
51     EventEpoll *epoll = (EventEpoll *)loop;
52 
53     int ret = LE_FAILURE;
54     struct epoll_event event = {};
55     int fd = GetSocketFd((const TaskHandle)task);
56     GetEpollEvent_(fd, op, &event);
57     if (IsValid_(epoll) && fd >= 0) {
58         ret = epoll_ctl(epoll->epollFd, EPOLL_CTL_ADD, fd, &event);
59     }
60     LE_CHECK(ret == 0, return LE_FAILURE, "Failed to add epoll_ctl %d ret %d", fd, errno);
61     return LE_SUCCESS;
62 }
63 
ModEvent_(const EventLoop * loop,const BaseTask * task,int op)64 static LE_STATUS ModEvent_(const EventLoop *loop, const BaseTask *task, int op)
65 {
66     LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
67     EventEpoll *epoll = (EventEpoll *)loop;
68 
69     int ret = LE_FAILURE;
70     struct epoll_event event = {};
71     int fd = GetSocketFd((const TaskHandle)task);
72     GetEpollEvent_(fd, op, &event);
73     if (IsValid_(epoll) && fd >= 0) {
74         ret = epoll_ctl(epoll->epollFd, EPOLL_CTL_MOD, fd, &event);
75     }
76     LE_CHECK(ret == 0, return LE_FAILURE, "Failed to mod epoll_ctl %d ret %d", fd, errno);
77     return LE_SUCCESS;
78 }
79 
DelEvent_(const EventLoop * loop,int fd,int op)80 static LE_STATUS DelEvent_(const EventLoop *loop, int fd, int op)
81 {
82     LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
83     EventEpoll *epoll = (EventEpoll *)loop;
84 
85     int ret = LE_FAILURE;
86     struct epoll_event event = {};
87     GetEpollEvent_(fd, op, &event);
88     if (IsValid_(epoll) && fd >= 0) {
89         ret = epoll_ctl(epoll->epollFd, EPOLL_CTL_DEL, fd, &event);
90     }
91     LE_CHECK(ret == 0, return LE_FAILURE, "Failed to del epoll_ctl %d ret %d", fd, errno);
92     return LE_SUCCESS;
93 }
94 
RunLoop_(const EventLoop * loop)95 static LE_STATUS RunLoop_(const EventLoop *loop)
96 {
97     LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
98 
99     EventEpoll *epoll = (EventEpoll *)loop;
100     if (!IsValid_(epoll)) {
101         return LE_FAILURE;
102     }
103 
104     while (1) {
105         LE_RunIdle((LoopHandle)&(epoll->loop));
106 
107         uint64_t minTimePeriod = GetMinTimeoutPeriod(loop);
108         int timeout = 0;
109         if (minTimePeriod == 0) {
110             timeout = -1;
111         } else if (GetCurrentTimespec(0) >= minTimePeriod) {
112             timeout = 0;
113         } else {
114             timeout = (int)(minTimePeriod - GetCurrentTimespec(0));
115         }
116 
117         int number = epoll_wait(epoll->epollFd, epoll->waitEvents, loop->maxevents, timeout);
118         for (int index = 0; index < number; index++) {
119             if ((epoll->waitEvents[index].events & EPOLLIN) == EPOLLIN) {
120                 ProcessEvent(loop, epoll->waitEvents[index].data.fd, EVENT_READ);
121             }
122             if ((epoll->waitEvents[index].events & EPOLLOUT) == EPOLLOUT) {
123                 ProcessEvent(loop, epoll->waitEvents[index].data.fd, EVENT_WRITE);
124             }
125             if (epoll->waitEvents[index].events & (EPOLLERR | EPOLLHUP)) {
126                 LE_LOGV("RunLoop_ fd:%d, error:%d", epoll->waitEvents[index].data.fd, errno);
127                 ProcessEvent(loop, epoll->waitEvents[index].data.fd, EVENT_ERROR);
128             }
129         }
130 
131         if (number == 0) {
132             CheckTimeoutOfTimer((EventLoop *)loop, GetCurrentTimespec(0));
133         }
134 
135         if (loop->stop) {
136             break;
137         }
138     }
139     return LE_SUCCESS;
140 }
141 
CreateEpollLoop(EventLoop ** loop,uint32_t maxevents,uint32_t timeout)142 LE_STATUS CreateEpollLoop(EventLoop **loop, uint32_t maxevents, uint32_t timeout)
143 {
144     LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
145     EventEpoll *epoll = (EventEpoll *)malloc(sizeof(EventEpoll) + sizeof(struct epoll_event) * (maxevents));
146     LE_CHECK(epoll != NULL, return LE_FAILURE, "Failed to alloc memory for epoll");
147     epoll->epollFd = epoll_create(maxevents);
148     LE_CHECK(epoll->epollFd >= 0, free(epoll);
149         return LE_FAILURE, "Failed to create epoll");
150 
151     *loop = (EventLoop *)epoll;
152     epoll->loop.maxevents = maxevents;
153     epoll->loop.timeout = timeout;
154     epoll->loop.close = Close_;
155     epoll->loop.runLoop = RunLoop_;
156     epoll->loop.delEvent = DelEvent_;
157     epoll->loop.addEvent = AddEvent_;
158     epoll->loop.modEvent = ModEvent_;
159     return LE_SUCCESS;
160 }
161