1/* 2 * Copyright (c) 2023 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#include <cstdio> 16#include <cstring> 17#include <queue> 18#include <vector> 19#include <sys/epoll.h> 20#include <unistd.h> 21#include "utils_log.h" 22#include "io_event_common.h" 23#include "common_event_sys_errors.h" 24#include "io_event_epoll.h" 25 26namespace OHOS { 27namespace Utils { 28IOEventEpoll::IOEventEpoll() 29 : epollFd_(epoll_create1(EPOLL_CLOEXEC)), maxEvents_(EPOLL_MAX_EVENTS_INIT) {} 30 31IOEventEpoll::~IOEventEpoll() 32{ 33 CleanUp(); 34} 35 36ErrCode IOEventEpoll::SetUp() 37{ 38 if (epollFd_ < 0) { 39 epollFd_ = epoll_create1(EPOLL_CLOEXEC); 40 if (epollFd_ < 0) { 41 return EVENT_SYS_ERR_BADF; 42 } 43 } 44 return EVENT_SYS_ERR_OK; 45} 46 47void IOEventEpoll::CleanUp() 48{ 49 if (epollFd_ != IO_EVENT_INVALID_FD) { 50 if (close(epollFd_) != 0) { 51 UTILS_LOGW("%{public}s: Failed, cannot close fd: %{public}s.", __FUNCTION__, strerror(errno)); 52 } 53 epollFd_ = IO_EVENT_INVALID_FD; 54 } 55} 56 57bool IOEventEpoll::OperateEpoll(int op, int fd, EPEventId epollEvents) 58{ 59 struct epoll_event event; 60 bzero(&event, sizeof(event)); 61 event.events = epollEvents; 62 event.data.fd = fd; 63 64 if (epoll_ctl(epollFd_, op, fd, &event) != 0) { 65 UTILS_LOGE("%{public}s: Operate on epoll failed, %{public}s. epoll_fd: %{public}d , operation: %{public}d, \ 66 target fd: %{public}d", __FUNCTION__, strerror(errno), epollFd_, op, fd); 67 return false; 68 } 69 70 switch (op) { 71 case EPOLL_CTL_ADD: 72 interestFds_.insert(fd); 73 break; 74 case EPOLL_CTL_DEL: 75 interestFds_.erase(fd); 76 break; 77 default: 78 break; 79 } 80 return true; 81} 82 83ErrCode IOEventEpoll::ModifyEvents(int fd, REventId events) 84{ 85 if (fd == -1) { 86 UTILS_LOGE("%{public}s: Failed, bad fd.", __FUNCTION__); 87 return EVENT_SYS_ERR_BADF; 88 } 89 90 int op = EPOLL_CTL_ADD; 91 if (interestFds_.find(fd) != interestFds_.end()) { 92 if (events == Events::EVENT_NONE) { 93 op = EPOLL_CTL_DEL; 94 } else { 95 op = EPOLL_CTL_MOD; 96 } 97 } 98 99 if (!OperateEpoll(op, fd, Reactor2Epoll(events))) { 100 UTILS_LOGE("%{public}s: Modify events failed.", __FUNCTION__); 101 return EVENT_SYS_ERR_FAILED; 102 } 103 return EVENT_SYS_ERR_OK; 104} 105 106ErrCode IOEventEpoll::Polling(int timeout /* ms */, std::vector<std::pair<int, REventId>>& res) 107{ 108 struct epoll_event epollEvents[maxEvents_]; 109 int nfds = epoll_wait(epollFd_, &epollEvents[0], maxEvents_, timeout); 110 if (nfds == 0) { 111 return EVENT_SYS_ERR_NOEVENT; 112 } 113 if (nfds == -1) { 114 UTILS_LOGE("%{public}s: epoll_wait() failed, %{public}s", __FUNCTION__, strerror(errno)); 115 return EVENT_SYS_ERR_FAILED; 116 } 117 for (int idx = 0; idx < nfds; ++idx) { 118 res.emplace_back(std::make_pair(epollEvents[idx].data.fd, Epoll2Reactor(epollEvents[idx].events))); 119 } 120 121 if (nfds == maxEvents_) { 122 maxEvents_ *= EXPANSION_COEFF; 123 } 124 return EVENT_SYS_ERR_OK; 125} 126 127REventId IOEventEpoll::Epoll2Reactor(EPEventId epollEvents) 128{ 129 REventId res = Events::EVENT_NONE; 130 if ((epollEvents & EPOLLHUP) && !(epollEvents & EPOLLIN)) { 131 res |= Events::EVENT_CLOSE; 132 } 133 134 if (epollEvents & EPOLLERR) { 135 res |= Events::EVENT_ERROR; 136 } 137 138 if (epollEvents & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) { 139 res |= Events::EVENT_READ; 140 } 141 142 if (epollEvents & EPOLLOUT) { 143 res |= Events::EVENT_WRITE; 144 } 145 146 return res; 147} 148 149EPEventId IOEventEpoll::Reactor2Epoll(REventId reactorEvent) 150{ 151 EPEventId res = 0u; 152 153 if (reactorEvent & Events::EVENT_READ) { 154 res |= EPOLLIN | EPOLLPRI; 155 } 156 157 if (reactorEvent & Events::EVENT_WRITE) { 158 res |= EPOLLOUT; 159 } 160 161 if (reactorEvent & Events::EVENT_ERROR) { 162 res |= EPOLLERR; 163 } 164 165 return res; 166} 167 168} // namespace Utils 169} // namespace OHOS 170