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 namespace OHOS {
31 namespace HiviewDFX {
32
33 namespace {
34 constexpr const char *const EPOLL_MANAGER = "EPOLL_MANAGER";
35 }
36
EpollListener(int32_t fd)37 EpollListener::EpollListener(int32_t fd) : fd_(fd) {}
38
GetFd() const39 int32_t EpollListener::GetFd() const
40 {
41 return fd_;
42 }
43
~EpollManager()44 EpollManager::~EpollManager()
45 {
46 StopEpoll();
47 }
48
AddEpollEvent(EpollListener & epollListener) const49 bool EpollManager::AddEpollEvent(EpollListener& epollListener) const
50 {
51 if (eventFd_ < 0) {
52 return false;
53 }
54 epoll_event ev{};
55 ev.events = EPOLLIN;
56 ev.data.fd = epollListener.GetFd();
57 if (epoll_ctl(eventFd_, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) {
58 DFXLOGE("%s :: Failed to epoll ctl add fd(%d), errno(%d)", EPOLL_MANAGER, epollListener.GetFd(), errno);
59 return false;
60 }
61 return true;
62 }
63
DelEpollEvent(int32_t fd) const64 bool EpollManager::DelEpollEvent(int32_t fd) const
65 {
66 if (eventFd_ < 0) {
67 return false;
68 }
69 epoll_event ev{};
70 ev.events = EPOLLIN;
71 ev.data.fd = fd;
72 if (epoll_ctl(eventFd_, EPOLL_CTL_DEL, fd, &ev) < 0) {
73 DFXLOGW("%s :: Failed to epoll ctl delete Fd(%d), errno(%d)", EPOLL_MANAGER, fd, errno);
74 return false;
75 }
76 return true;
77 }
78
AddListener(std::unique_ptr<EpollListener> epollListener)79 bool EpollManager::AddListener(std::unique_ptr<EpollListener> epollListener)
80 {
81 if (!epollListener || epollListener->GetFd() < 0 || !AddEpollEvent(*epollListener)) {
82 return false;
83 }
84 listeners_.emplace_back(std::move(epollListener));
85 return true;
86 }
87
RemoveListener(int32_t fd)88 bool EpollManager::RemoveListener(int32_t fd)
89 {
90 if (fd < 0 || !DelEpollEvent(fd)) {
91 return false;
92 }
93 listeners_.remove_if([fd](const std::unique_ptr<EpollListener>& epollLister) {
94 return epollLister->GetFd() == fd;
95 });
96 return true;
97 }
98
GetTargetListener(int32_t fd)99 EpollListener* EpollManager::GetTargetListener(int32_t fd)
100 {
101 auto iter = std::find_if(listeners_.begin(), listeners_.end(),
102 [fd](const std::unique_ptr<EpollListener>& listener) {
103 return listener->GetFd() == fd;
104 });
105 return iter == listeners_.end() ? nullptr : iter->get();
106 }
107
Init(int maxPollEvent)108 bool EpollManager::Init(int maxPollEvent)
109 {
110 eventFd_ = epoll_create(maxPollEvent);
111 if (eventFd_ < 0) {
112 DFXLOGE("%s :: Failed to create eventFd.", EPOLL_MANAGER);
113 return false;
114 }
115 return true;
116 }
117
StartEpoll(int maxConnection)118 void EpollManager::StartEpoll(int maxConnection)
119 {
120 std::vector<epoll_event> events(maxConnection);
121 while (eventFd_ >= 0) {
122 int epollNum = OHOS_TEMP_FAILURE_RETRY(epoll_wait(eventFd_, events.data(), maxConnection, -1));
123 std::lock_guard<std::mutex> lck(epollMutex_);
124 if (epollNum < 0 || eventFd_ < 0) {
125 continue;
126 }
127 for (int i = 0; i < epollNum; i++) {
128 if (!(events[i].events & EPOLLIN)) {
129 continue;
130 }
131 auto listener = GetTargetListener(events[i].data.fd);
132 if (listener != nullptr) {
133 listener->OnEventPoll();
134 }
135 }
136 }
137 }
138
StopEpoll()139 void EpollManager::StopEpoll()
140 {
141 std::lock_guard<std::mutex> lck(epollMutex_);
142 if (eventFd_ >= 0) {
143 for (const auto& listener : listeners_) {
144 DelEpollEvent(listener->GetFd());
145 }
146 close(eventFd_);
147 eventFd_ = -1;
148 }
149 }
150
CreateInstance(std::function<void ()> workFunc,int32_t timeout,EpollManager & epollManager)151 std::unique_ptr<DelayTask> DelayTask::CreateInstance(std::function<void()> workFunc,
152 int32_t timeout, EpollManager& epollManager)
153 {
154 if (timeout <= 0) {
155 return nullptr;
156 }
157 int timefd = timerfd_create(CLOCK_MONOTONIC, 0);
158 if (timefd == -1) {
159 DFXLOGE("%{public}s :: failed to create time fd, errno: %{public}d", EPOLL_MANAGER, errno);
160 return nullptr;
161 }
162 struct itimerspec timeOption{};
163 timeOption.it_value.tv_sec = timeout;
164 if (timerfd_settime(timefd, 0, &timeOption, nullptr) == -1) {
165 close(timefd);
166 DFXLOGE("%{public}s :: failed to set delay time for fd, errno: %{public}d.", EPOLL_MANAGER, errno);
167 return nullptr;
168 }
169 return std::unique_ptr<DelayTask>(new (std::nothrow)DelayTask(workFunc, timefd, epollManager));
170 }
171
DelayTask(std::function<void ()> workFunc,int32_t timeFd,EpollManager & epollManager)172 DelayTask::DelayTask(std::function<void()> workFunc, int32_t timeFd, EpollManager& epollManager)
173 : EpollListener(timeFd), work_(std::move(workFunc)), epollManager_(epollManager) {}
174
OnEventPoll()175 void DelayTask::OnEventPoll()
176 {
177 uint64_t exp;
178 auto ret = OHOS_TEMP_FAILURE_RETRY(read(GetFd(), &exp, sizeof(exp)));
179 if (ret < 0 || static_cast<uint64_t>(ret) != sizeof(exp)) {
180 DFXLOGE("%{public}s :: failed read time fd %{public}" PRId32, EPOLL_MANAGER, GetFd());
181 } else {
182 work_();
183 }
184 epollManager_.RemoveListener(GetFd());
185 }
186 }
187 }