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
26 namespace OHOS {
27 namespace Utils {
IOEventEpoll()28 IOEventEpoll::IOEventEpoll()
29 : epollFd_(epoll_create1(EPOLL_CLOEXEC)), maxEvents_(EPOLL_MAX_EVENTS_INIT) {}
30
~IOEventEpoll()31 IOEventEpoll::~IOEventEpoll()
32 {
33 CleanUp();
34 }
35
SetUp()36 ErrCode 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
CleanUp()47 void 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
OperateEpoll(int op,int fd,EPEventId epollEvents)57 bool 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
ModifyEvents(int fd,REventId events)83 ErrCode 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
Polling(int timeout,std::vector<std::pair<int,REventId>> & res)106 ErrCode 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
Epoll2Reactor(EPEventId epollEvents)127 REventId 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
Reactor2Epoll(REventId reactorEvent)149 EPEventId 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