• 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 #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 }