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_demultiplexer.h"
17#include "event_reactor.h"
18#include "event_handler.h"
19#include "common_timer_errors.h"
20#include "utils_log.h"
21
22#include <vector>
23#include <cstdio>
24#include <strings.h>
25#include <unistd.h>
26#include <sys/epoll.h>
27
28namespace OHOS {
29namespace Utils {
30
31static const int EPOLL_MAX_EVENS_INIT = 8;
32static const int HALF_OF_MAX_EVENT = 2;
33static const int EPOLL_INVALID_FD = -1;
34static const int INTERRUPTED_SYS_CALL = 4;
35static const int EPOLL_ERROR_BADF = 9;
36static const int EPOLL_ERROR_EINVAL = 22;
37
38EventDemultiplexer::EventDemultiplexer()
39    : epollFd_(epoll_create1(EPOLL_CLOEXEC)), maxEvents_(EPOLL_MAX_EVENS_INIT), mutex_(), eventHandlers_()
40{
41}
42
43EventDemultiplexer::~EventDemultiplexer()
44{
45    CleanUp();
46}
47
48uint32_t EventDemultiplexer::StartUp()
49{
50    if (epollFd_ < 0) {
51        epollFd_ = epoll_create1(EPOLL_CLOEXEC);
52        if (epollFd_ < 0) {
53            return TIMER_ERR_BADF;
54        }
55    }
56    return TIMER_ERR_OK;
57}
58
59void EventDemultiplexer::CleanUp()
60{
61    if (epollFd_ != EPOLL_INVALID_FD) {
62        close(epollFd_);
63        epollFd_ = EPOLL_INVALID_FD;
64    }
65}
66
67uint32_t EventDemultiplexer::UpdateEventHandler(EventHandler* handler)
68{
69    if (handler == nullptr) {
70        return TIMER_ERR_INVALID_VALUE;
71    }
72
73    std::lock_guard<std::recursive_mutex> lock(mutex_);
74    auto itor = eventHandlers_.find(handler->GetHandle());
75    if (itor == eventHandlers_.end()) {
76        eventHandlers_.insert(std::make_pair(handler->GetHandle(), handler->shared_from_this()));
77        return Update(EPOLL_CTL_ADD, handler);
78    }
79
80    if (handler->Events() == EventReactor::NONE_EVENT) {
81        eventHandlers_.erase(itor);
82        return Update(EPOLL_CTL_DEL, handler);
83    }
84
85    if (handler != itor->second.get()) {
86        return TIMER_ERR_DEAL_FAILED;
87    }
88    return Update(EPOLL_CTL_MOD, handler);
89}
90
91uint32_t EventDemultiplexer::Update(int operation, EventHandler* handler)
92{
93    struct epoll_event event;
94    bzero(&event, sizeof(event));
95    event.events   = Reactor2Epoll(handler->Events());
96    event.data.fd = handler->GetHandle();
97
98    if (epoll_ctl(epollFd_, operation, handler->GetHandle(), &event) != 0) {
99        UTILS_LOGD("epoll_ctl %{public}d  operation %{public}d on handle %{public}d failed",
100            epollFd_, operation, handler->GetHandle());
101        return TIMER_ERR_DEAL_FAILED;
102    }
103    return TIMER_ERR_OK;
104}
105
106int EventDemultiplexer::Polling(int timeout /* ms */)
107{
108    std::vector<struct epoll_event> epollEvents(maxEvents_);
109    std::vector<std::shared_ptr<EventHandler>> taskQue;
110    std::vector<uint32_t> eventQue;
111
112    int nfds = epoll_wait(epollFd_, &epollEvents[0], static_cast<int>(epollEvents.size()), timeout);
113    if (nfds == 0) {
114        return nfds;
115    }
116    if (nfds == -1) {
117        if (errno != INTERRUPTED_SYS_CALL) {
118            UTILS_LOGE("epoll_wait failed, errno %{public}d, epollFd_: %{public}d, pollEvents.size: %{public}zu",
119                errno, epollFd_, epollEvents.size());
120        }
121        if (errno == EPOLL_ERROR_BADF || errno == EPOLL_ERROR_EINVAL) {
122            UTILS_LOGE("epoll_wait critical error, thread exit");
123            return EPOLL_CRITICAL_ERROR;
124        }
125        return nfds;
126    }
127
128    {
129        std::lock_guard<std::recursive_mutex> lock(mutex_);
130        for (int idx = 0; idx < nfds; ++idx) {
131            int targetFd = epollEvents[idx].data.fd;
132            uint32_t events = epollEvents[idx].events;
133
134            auto itor = eventHandlers_.find(targetFd);
135            if (itor != eventHandlers_.end()) {
136                taskQue.emplace_back(itor->second);
137                eventQue.emplace_back(events);
138            } else {
139                UTILS_LOGE("fd not found in eventHandlers_, fd=%{public}d", targetFd);
140            }
141        }
142    }
143
144    for (size_t idx = 0u; idx < taskQue.size() && idx < eventQue.size(); idx++) {
145        taskQue[idx]->HandleEvents(eventQue[idx]);
146    }
147
148    if (nfds == maxEvents_) {
149        maxEvents_ *= HALF_OF_MAX_EVENT;
150    }
151    return nfds;
152}
153
154uint32_t EventDemultiplexer::Epoll2Reactor(uint32_t epollEvents)
155{
156    if (epollEvents & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) {
157        return EventReactor::READ_EVENT;
158    }
159
160    return EventReactor::NONE_EVENT;
161}
162
163uint32_t EventDemultiplexer::Reactor2Epoll(uint32_t reactorEvent)
164{
165    switch (reactorEvent) {
166        case EventReactor::NONE_EVENT:
167            return TIMER_ERR_OK;
168        case EventReactor::READ_EVENT:
169            return EPOLLIN | EPOLLPRI;
170        default:
171            UTILS_LOGD("invalid event %{public}u.", reactorEvent);
172            return TIMER_ERR_DEAL_FAILED;
173    }
174}
175
176}
177}
178