13f4cbf05Sopenharmony_ci/*
23f4cbf05Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
33f4cbf05Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43f4cbf05Sopenharmony_ci * you may not use this file except in compliance with the License.
53f4cbf05Sopenharmony_ci * You may obtain a copy of the License at
63f4cbf05Sopenharmony_ci *
73f4cbf05Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
83f4cbf05Sopenharmony_ci *
93f4cbf05Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103f4cbf05Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113f4cbf05Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123f4cbf05Sopenharmony_ci * See the License for the specific language governing permissions and
133f4cbf05Sopenharmony_ci * limitations under the License.
143f4cbf05Sopenharmony_ci */
153f4cbf05Sopenharmony_ci#include <cstdio>
163f4cbf05Sopenharmony_ci#include <cstring>
173f4cbf05Sopenharmony_ci#include <queue>
183f4cbf05Sopenharmony_ci#include <vector>
193f4cbf05Sopenharmony_ci#include <sys/epoll.h>
203f4cbf05Sopenharmony_ci#include <unistd.h>
213f4cbf05Sopenharmony_ci#include "utils_log.h"
223f4cbf05Sopenharmony_ci#include "io_event_common.h"
233f4cbf05Sopenharmony_ci#include "common_event_sys_errors.h"
243f4cbf05Sopenharmony_ci#include "io_event_epoll.h"
253f4cbf05Sopenharmony_ci
263f4cbf05Sopenharmony_cinamespace OHOS {
273f4cbf05Sopenharmony_cinamespace Utils {
283f4cbf05Sopenharmony_ciIOEventEpoll::IOEventEpoll()
293f4cbf05Sopenharmony_ci    : epollFd_(epoll_create1(EPOLL_CLOEXEC)), maxEvents_(EPOLL_MAX_EVENTS_INIT) {}
303f4cbf05Sopenharmony_ci
313f4cbf05Sopenharmony_ciIOEventEpoll::~IOEventEpoll()
323f4cbf05Sopenharmony_ci{
333f4cbf05Sopenharmony_ci    CleanUp();
343f4cbf05Sopenharmony_ci}
353f4cbf05Sopenharmony_ci
363f4cbf05Sopenharmony_ciErrCode IOEventEpoll::SetUp()
373f4cbf05Sopenharmony_ci{
383f4cbf05Sopenharmony_ci    if (epollFd_ < 0) {
393f4cbf05Sopenharmony_ci        epollFd_ = epoll_create1(EPOLL_CLOEXEC);
403f4cbf05Sopenharmony_ci        if (epollFd_ < 0) {
413f4cbf05Sopenharmony_ci            return EVENT_SYS_ERR_BADF;
423f4cbf05Sopenharmony_ci        }
433f4cbf05Sopenharmony_ci    }
443f4cbf05Sopenharmony_ci    return EVENT_SYS_ERR_OK;
453f4cbf05Sopenharmony_ci}
463f4cbf05Sopenharmony_ci
473f4cbf05Sopenharmony_civoid IOEventEpoll::CleanUp()
483f4cbf05Sopenharmony_ci{
493f4cbf05Sopenharmony_ci    if (epollFd_ != IO_EVENT_INVALID_FD) {
503f4cbf05Sopenharmony_ci        if (close(epollFd_) != 0) {
513f4cbf05Sopenharmony_ci            UTILS_LOGW("%{public}s: Failed, cannot close fd: %{public}s.", __FUNCTION__, strerror(errno));
523f4cbf05Sopenharmony_ci        }
533f4cbf05Sopenharmony_ci        epollFd_ = IO_EVENT_INVALID_FD;
543f4cbf05Sopenharmony_ci    }
553f4cbf05Sopenharmony_ci}
563f4cbf05Sopenharmony_ci
573f4cbf05Sopenharmony_cibool IOEventEpoll::OperateEpoll(int op, int fd, EPEventId epollEvents)
583f4cbf05Sopenharmony_ci{
593f4cbf05Sopenharmony_ci    struct epoll_event event;
603f4cbf05Sopenharmony_ci    bzero(&event, sizeof(event));
613f4cbf05Sopenharmony_ci    event.events = epollEvents;
623f4cbf05Sopenharmony_ci    event.data.fd = fd;
633f4cbf05Sopenharmony_ci
643f4cbf05Sopenharmony_ci    if (epoll_ctl(epollFd_, op, fd, &event) != 0) {
653f4cbf05Sopenharmony_ci        UTILS_LOGE("%{public}s: Operate on epoll failed, %{public}s. epoll_fd: %{public}d , operation: %{public}d, \
663f4cbf05Sopenharmony_ci                   target fd: %{public}d", __FUNCTION__, strerror(errno), epollFd_, op, fd);
673f4cbf05Sopenharmony_ci        return false;
683f4cbf05Sopenharmony_ci    }
693f4cbf05Sopenharmony_ci
703f4cbf05Sopenharmony_ci    switch (op) {
713f4cbf05Sopenharmony_ci        case EPOLL_CTL_ADD:
723f4cbf05Sopenharmony_ci            interestFds_.insert(fd);
733f4cbf05Sopenharmony_ci            break;
743f4cbf05Sopenharmony_ci        case EPOLL_CTL_DEL:
753f4cbf05Sopenharmony_ci            interestFds_.erase(fd);
763f4cbf05Sopenharmony_ci            break;
773f4cbf05Sopenharmony_ci        default:
783f4cbf05Sopenharmony_ci            break;
793f4cbf05Sopenharmony_ci    }
803f4cbf05Sopenharmony_ci    return true;
813f4cbf05Sopenharmony_ci}
823f4cbf05Sopenharmony_ci
833f4cbf05Sopenharmony_ciErrCode IOEventEpoll::ModifyEvents(int fd, REventId events)
843f4cbf05Sopenharmony_ci{
853f4cbf05Sopenharmony_ci    if (fd == -1) {
863f4cbf05Sopenharmony_ci        UTILS_LOGE("%{public}s: Failed, bad fd.", __FUNCTION__);
873f4cbf05Sopenharmony_ci        return EVENT_SYS_ERR_BADF;
883f4cbf05Sopenharmony_ci    }
893f4cbf05Sopenharmony_ci
903f4cbf05Sopenharmony_ci    int op = EPOLL_CTL_ADD;
913f4cbf05Sopenharmony_ci    if (interestFds_.find(fd) != interestFds_.end()) {
923f4cbf05Sopenharmony_ci        if (events == Events::EVENT_NONE) {
933f4cbf05Sopenharmony_ci            op = EPOLL_CTL_DEL;
943f4cbf05Sopenharmony_ci        } else {
953f4cbf05Sopenharmony_ci            op = EPOLL_CTL_MOD;
963f4cbf05Sopenharmony_ci        }
973f4cbf05Sopenharmony_ci    }
983f4cbf05Sopenharmony_ci
993f4cbf05Sopenharmony_ci    if (!OperateEpoll(op, fd, Reactor2Epoll(events))) {
1003f4cbf05Sopenharmony_ci        UTILS_LOGE("%{public}s: Modify events failed.", __FUNCTION__);
1013f4cbf05Sopenharmony_ci        return EVENT_SYS_ERR_FAILED;
1023f4cbf05Sopenharmony_ci    }
1033f4cbf05Sopenharmony_ci    return EVENT_SYS_ERR_OK;
1043f4cbf05Sopenharmony_ci}
1053f4cbf05Sopenharmony_ci
1063f4cbf05Sopenharmony_ciErrCode IOEventEpoll::Polling(int timeout /* ms */, std::vector<std::pair<int, REventId>>& res)
1073f4cbf05Sopenharmony_ci{
1083f4cbf05Sopenharmony_ci    struct epoll_event epollEvents[maxEvents_];
1093f4cbf05Sopenharmony_ci    int nfds = epoll_wait(epollFd_, &epollEvents[0], maxEvents_, timeout);
1103f4cbf05Sopenharmony_ci    if (nfds == 0) {
1113f4cbf05Sopenharmony_ci        return EVENT_SYS_ERR_NOEVENT;
1123f4cbf05Sopenharmony_ci    }
1133f4cbf05Sopenharmony_ci    if (nfds == -1) {
1143f4cbf05Sopenharmony_ci        UTILS_LOGE("%{public}s: epoll_wait() failed, %{public}s", __FUNCTION__, strerror(errno));
1153f4cbf05Sopenharmony_ci        return EVENT_SYS_ERR_FAILED;
1163f4cbf05Sopenharmony_ci    }
1173f4cbf05Sopenharmony_ci    for (int idx = 0; idx < nfds; ++idx) {
1183f4cbf05Sopenharmony_ci        res.emplace_back(std::make_pair(epollEvents[idx].data.fd, Epoll2Reactor(epollEvents[idx].events)));
1193f4cbf05Sopenharmony_ci    }
1203f4cbf05Sopenharmony_ci
1213f4cbf05Sopenharmony_ci    if (nfds == maxEvents_) {
1223f4cbf05Sopenharmony_ci        maxEvents_ *= EXPANSION_COEFF;
1233f4cbf05Sopenharmony_ci    }
1243f4cbf05Sopenharmony_ci    return EVENT_SYS_ERR_OK;
1253f4cbf05Sopenharmony_ci}
1263f4cbf05Sopenharmony_ci
1273f4cbf05Sopenharmony_ciREventId IOEventEpoll::Epoll2Reactor(EPEventId epollEvents)
1283f4cbf05Sopenharmony_ci{
1293f4cbf05Sopenharmony_ci    REventId res = Events::EVENT_NONE;
1303f4cbf05Sopenharmony_ci    if ((epollEvents & EPOLLHUP) && !(epollEvents & EPOLLIN)) {
1313f4cbf05Sopenharmony_ci        res |= Events::EVENT_CLOSE;
1323f4cbf05Sopenharmony_ci    }
1333f4cbf05Sopenharmony_ci
1343f4cbf05Sopenharmony_ci    if (epollEvents & EPOLLERR) {
1353f4cbf05Sopenharmony_ci        res |= Events::EVENT_ERROR;
1363f4cbf05Sopenharmony_ci    }
1373f4cbf05Sopenharmony_ci
1383f4cbf05Sopenharmony_ci    if (epollEvents & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) {
1393f4cbf05Sopenharmony_ci        res |= Events::EVENT_READ;
1403f4cbf05Sopenharmony_ci    }
1413f4cbf05Sopenharmony_ci
1423f4cbf05Sopenharmony_ci    if (epollEvents & EPOLLOUT) {
1433f4cbf05Sopenharmony_ci        res |= Events::EVENT_WRITE;
1443f4cbf05Sopenharmony_ci    }
1453f4cbf05Sopenharmony_ci
1463f4cbf05Sopenharmony_ci    return res;
1473f4cbf05Sopenharmony_ci}
1483f4cbf05Sopenharmony_ci
1493f4cbf05Sopenharmony_ciEPEventId IOEventEpoll::Reactor2Epoll(REventId reactorEvent)
1503f4cbf05Sopenharmony_ci{
1513f4cbf05Sopenharmony_ci    EPEventId res = 0u;
1523f4cbf05Sopenharmony_ci
1533f4cbf05Sopenharmony_ci    if (reactorEvent & Events::EVENT_READ) {
1543f4cbf05Sopenharmony_ci        res |= EPOLLIN | EPOLLPRI;
1553f4cbf05Sopenharmony_ci    }
1563f4cbf05Sopenharmony_ci
1573f4cbf05Sopenharmony_ci    if (reactorEvent & Events::EVENT_WRITE) {
1583f4cbf05Sopenharmony_ci        res |= EPOLLOUT;
1593f4cbf05Sopenharmony_ci    }
1603f4cbf05Sopenharmony_ci
1613f4cbf05Sopenharmony_ci    if (reactorEvent & Events::EVENT_ERROR) {
1623f4cbf05Sopenharmony_ci        res |= EPOLLERR;
1633f4cbf05Sopenharmony_ci    }
1643f4cbf05Sopenharmony_ci
1653f4cbf05Sopenharmony_ci    return res;
1663f4cbf05Sopenharmony_ci}
1673f4cbf05Sopenharmony_ci
1683f4cbf05Sopenharmony_ci} // namespace Utils
1693f4cbf05Sopenharmony_ci} // namespace OHOS
170