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