• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }