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