1 /*
2 * Copyright (c) 2024 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 "epoll_manager.h"
17
18 #include <algorithm>
19 #include <thread>
20 #include <vector>
21
22 #include <unistd.h>
23
24 #include <sys/epoll.h>
25 #include <sys/timerfd.h>
26
27 #include "dfx_define.h"
28 #include "dfx_log.h"
29
30 #ifdef LOG_DOMAIN
31 #undef LOG_DOMAIN
32 #define LOG_DOMAIN 0xD002D11
33 #endif
34
35 namespace OHOS {
36 namespace HiviewDFX {
37
38 namespace {
39 constexpr const char *const EPOLL_MANAGER = "EPOLL_MANAGER";
40 }
41
EpollListener(SmartFd fd,bool persist)42 EpollListener::EpollListener(SmartFd fd, bool persist) : fd_(std::move(fd)), persist_(persist) {}
43
IsPersist() const44 bool EpollListener::IsPersist() const
45 {
46 return persist_;
47 }
48
GetFd() const49 int32_t EpollListener::GetFd() const
50 {
51 return fd_.GetFd();
52 }
53
~EpollManager()54 EpollManager::~EpollManager()
55 {
56 StopEpoll();
57 }
58
AddEpollEvent(EpollListener & epollListener) const59 bool EpollManager::AddEpollEvent(EpollListener& epollListener) const
60 {
61 if (!eventFd_) {
62 return false;
63 }
64 epoll_event ev{};
65 ev.events = EPOLLIN;
66 ev.data.fd = epollListener.GetFd();
67 if (epoll_ctl(eventFd_.GetFd(), EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) {
68 DFXLOGE("%s :: Failed to epoll ctl add fd %{public}d, errno %{public}d",
69 EPOLL_MANAGER, epollListener.GetFd(), errno);
70 return false;
71 }
72 return true;
73 }
74
DelEpollEvent(int32_t fd) const75 bool EpollManager::DelEpollEvent(int32_t fd) const
76 {
77 if (!eventFd_) {
78 return false;
79 }
80 epoll_event ev{};
81 ev.events = EPOLLIN;
82 ev.data.fd = fd;
83 if (epoll_ctl(eventFd_.GetFd(), EPOLL_CTL_DEL, fd, &ev) < 0) {
84 DFXLOGW("%s :: Failed to epoll ctl delete Fd %{public}d, errno %{public}d", EPOLL_MANAGER, fd, errno);
85 return false;
86 }
87 return true;
88 }
89
AddListener(std::unique_ptr<EpollListener> epollListener)90 bool EpollManager::AddListener(std::unique_ptr<EpollListener> epollListener)
91 {
92 if (!epollListener || epollListener->GetFd() < 0 || !AddEpollEvent(*epollListener)) {
93 return false;
94 }
95 epollListener->IsPersist() ? listeners_.push_back(std::move(epollListener)) :
96 listeners_.push_front(std::move(epollListener));
97 return true;
98 }
99
RemoveListener(int32_t fd)100 bool EpollManager::RemoveListener(int32_t fd)
101 {
102 if (fd < 0 || !DelEpollEvent(fd)) {
103 return false;
104 }
105 listeners_.remove_if([fd](const std::unique_ptr<EpollListener>& epollLister) {
106 return epollLister->GetFd() == fd;
107 });
108 return true;
109 }
110
GetTargetListener(int32_t fd)111 EpollListener* EpollManager::GetTargetListener(int32_t fd)
112 {
113 auto iter = std::find_if(listeners_.begin(), listeners_.end(),
114 [fd](const std::unique_ptr<EpollListener>& listener) {
115 return listener->GetFd() == fd;
116 });
117 return iter == listeners_.end() ? nullptr : iter->get();
118 }
119
Init(int maxPollEvent)120 bool EpollManager::Init(int maxPollEvent)
121 {
122 eventFd_ = SmartFd{epoll_create(maxPollEvent)};
123 if (!eventFd_) {
124 DFXLOGE("%s :: Failed to create eventFd.", EPOLL_MANAGER);
125 return false;
126 }
127 return true;
128 }
129
StartEpoll(int maxConnection,int epollTimeoutInMilliseconds)130 void EpollManager::StartEpoll(int maxConnection, int epollTimeoutInMilliseconds)
131 {
132 std::vector<epoll_event> events(maxConnection);
133 while (eventFd_) {
134 int32_t timeOut = (!listeners_.empty() && !listeners_.front()->IsPersist()) ? epollTimeoutInMilliseconds : -1;
135 int epollNum = OHOS_TEMP_FAILURE_RETRY(epoll_wait(eventFd_.GetFd(), events.data(), maxConnection, timeOut));
136 std::lock_guard<std::mutex> lck(epollMutex_);
137 if (epollNum < 0 || !eventFd_) {
138 continue;
139 }
140 if (epollNum == 0) {
141 DFXLOGE("%{public}s :: epoll_wait timeout, clean up all temporary event listeners.", EPOLL_MANAGER);
142 listeners_.remove_if([](const std::unique_ptr<EpollListener>& epollLister) {
143 return !epollLister->IsPersist();
144 });
145 continue;
146 }
147 for (int i = 0; i < epollNum; i++) {
148 if (!(events[i].events & EPOLLIN)) {
149 DFXLOGE("%{public}s :: client fd %{public}d disconnected", EPOLL_MANAGER, events[i].data.fd);
150 RemoveListener(events[i].data.fd);
151 continue;
152 }
153 const auto listener = GetTargetListener(events[i].data.fd);
154 if (listener == nullptr) {
155 RemoveListener(events[i].data.fd);
156 continue;
157 }
158 listener->OnEventPoll();
159 if (!listener->IsPersist()) {
160 RemoveListener(events[i].data.fd);
161 }
162 }
163 }
164 }
165
StopEpoll()166 void EpollManager::StopEpoll()
167 {
168 std::lock_guard<std::mutex> lck(epollMutex_);
169 if (eventFd_) {
170 for (const auto& listener : listeners_) {
171 (void)DelEpollEvent(listener->GetFd());
172 }
173 eventFd_.Reset();
174 }
175 }
176
CreateInstance(std::function<void ()> workFunc,int32_t timeout)177 std::unique_ptr<DelayTask> DelayTask::CreateInstance(std::function<void()> workFunc, int32_t timeout)
178 {
179 if (timeout <= 0) {
180 return nullptr;
181 }
182 SmartFd timefd{timerfd_create(CLOCK_MONOTONIC, 0)};
183 if (!timefd) {
184 DFXLOGE("%{public}s :: failed to create time fd, errno: %{public}d", EPOLL_MANAGER, errno);
185 return nullptr;
186 }
187 struct itimerspec timeOption{};
188 timeOption.it_value.tv_sec = timeout;
189 if (timerfd_settime(timefd.GetFd(), 0, &timeOption, nullptr) == -1) {
190 DFXLOGE("%{public}s :: failed to set delay time for fd, errno: %{public}d.", EPOLL_MANAGER, errno);
191 return nullptr;
192 }
193 return std::unique_ptr<DelayTask>(new (std::nothrow)DelayTask(workFunc, std::move(timefd)));
194 }
195
DelayTask(std::function<void ()> workFunc,SmartFd timeFd)196 DelayTask::DelayTask(std::function<void()> workFunc, SmartFd timeFd)
197 : EpollListener(std::move(timeFd)), work_(std::move(workFunc)) {}
198
OnEventPoll()199 void DelayTask::OnEventPoll()
200 {
201 uint64_t exp = 0;
202 auto ret = OHOS_TEMP_FAILURE_RETRY(read(GetFd(), &exp, sizeof(exp)));
203 if (ret < 0 || static_cast<uint64_t>(ret) != sizeof(exp)) {
204 DFXLOGE("%{public}s :: failed read time fd %{public}" PRId32, EPOLL_MANAGER, GetFd());
205 } else {
206 work_();
207 }
208 }
209 }
210 }