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
22static int IsValid_(const EventEpoll *loop)
23{
24    return loop->epollFd >= 0;
25}
26
27static 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
38static 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
48static 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
64static 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
80static 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
95static 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        if (timeout < 0 || timeout > 1000) { //1000ms
117            LE_LOGW("timeout:%d", timeout);
118        }
119
120        int number = epoll_wait(epoll->epollFd, epoll->waitEvents, loop->maxevents, timeout);
121        for (int index = 0; index < number; index++) {
122            if ((epoll->waitEvents[index].events & EPOLLIN) == EPOLLIN) {
123                ProcessEvent(loop, epoll->waitEvents[index].data.fd, EVENT_READ);
124            }
125            if ((epoll->waitEvents[index].events & EPOLLOUT) == EPOLLOUT) {
126                ProcessEvent(loop, epoll->waitEvents[index].data.fd, EVENT_WRITE);
127            }
128            if (epoll->waitEvents[index].events & (EPOLLERR | EPOLLHUP)) {
129                LE_LOGV("RunLoop_ fd:%d, error:%d", epoll->waitEvents[index].data.fd, errno);
130                ProcessEvent(loop, epoll->waitEvents[index].data.fd, EVENT_ERROR);
131            }
132        }
133
134        if (number == 0) {
135            CheckTimeoutOfTimer((EventLoop *)loop, GetCurrentTimespec(0));
136        }
137
138        if (loop->stop) {
139            break;
140        }
141    }
142    return LE_SUCCESS;
143}
144
145LE_STATUS CreateEpollLoop(EventLoop **loop, uint32_t maxevents, uint32_t timeout)
146{
147    LE_CHECK(loop != NULL, return LE_FAILURE, "Invalid loop");
148    EventEpoll *epoll = (EventEpoll *)malloc(sizeof(EventEpoll) + sizeof(struct epoll_event) * (maxevents));
149    LE_CHECK(epoll != NULL, return LE_FAILURE, "Failed to alloc memory for epoll");
150    epoll->epollFd = epoll_create(maxevents);
151    LE_CHECK(epoll->epollFd >= 0, free(epoll);
152        return LE_FAILURE, "Failed to create epoll");
153
154    *loop = (EventLoop *)epoll;
155    epoll->loop.maxevents = maxevents;
156    epoll->loop.timeout = timeout;
157    epoll->loop.close = Close_;
158    epoll->loop.runLoop = RunLoop_;
159    epoll->loop.delEvent = DelEvent_;
160    epoll->loop.addEvent = AddEvent_;
161    epoll->loop.modEvent = ModEvent_;
162    return LE_SUCCESS;
163}
164