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 
16 #include "epoll_manager.h"
17 
18 #include <unistd.h>
19 
20 #include "devicestatus_define.h"
21 
22 #undef LOG_TAG
23 #define LOG_TAG "EpollManager"
24 
25 namespace OHOS {
26 namespace Msdp {
27 namespace DeviceStatus {
28 namespace {
29 constexpr int32_t MAX_N_EVENTS { 64 };
30 } // namespace
31 
~EpollManager()32 EpollManager::~EpollManager()
33 {
34     Close();
35 }
36 
Open()37 bool EpollManager::Open()
38 {
39     if (epollFd_ != -1) {
40         return true;
41     }
42     epollFd_ = ::epoll_create1(EPOLL_CLOEXEC);
43     if (epollFd_ == -1) {
44         FI_HILOGE("epoll_create1 failed:%{public}s", ::strerror(errno));
45         return false;
46     }
47     return true;
48 }
49 
Close()50 void EpollManager::Close()
51 {
52     if (epollFd_ != -1) {
53         if (::close(epollFd_) != 0) {
54             FI_HILOGE("close(%d) failed:%{public}s", epollFd_, ::strerror(errno));
55         }
56         epollFd_ = -1;
57     }
58 }
59 
Add(std::shared_ptr<IEpollEventSource> source)60 bool EpollManager::Add(std::shared_ptr<IEpollEventSource> source)
61 {
62     CHKPF(source);
63     auto [iter, isNew] = sources_.emplace(source->GetFd(), source);
64     if (!isNew) {
65         FI_HILOGW("Epoll source(%d) has been added", source->GetFd());
66         return true;
67     }
68     struct epoll_event ev {};
69     ev.events = source->GetEvents();
70     ev.data.ptr = source.get();
71 
72     int32_t ret = ::epoll_ctl(epollFd_, EPOLL_CTL_ADD, source->GetFd(), &ev);
73     if (ret != 0) {
74         FI_HILOGE("epoll_ctl failed:%{public}s", ::strerror(errno));
75         sources_.erase(iter);
76         return false;
77     }
78     FI_HILOGI("Add epoll source(%d)", source->GetFd());
79     return true;
80 }
81 
Remove(std::shared_ptr<IEpollEventSource> source)82 void EpollManager::Remove(std::shared_ptr<IEpollEventSource> source)
83 {
84     CHKPV(source);
85     auto iter = sources_.find(source->GetFd());
86     if (iter == sources_.cend()) {
87         FI_HILOGE("No epoll source(%d)", source->GetFd());
88         return;
89     }
90     FI_HILOGI("Remove epoll source(%d)", source->GetFd());
91     int32_t ret = ::epoll_ctl(epollFd_, EPOLL_CTL_DEL, source->GetFd(), nullptr);
92     if (ret != 0) {
93         FI_HILOGE("epoll_ctl failed:%{public}s", ::strerror(errno));
94     }
95     sources_.erase(iter);
96 }
97 
Update(std::shared_ptr<IEpollEventSource> source)98 bool EpollManager::Update(std::shared_ptr<IEpollEventSource> source)
99 {
100     CHKPF(source);
101     auto iter = sources_.find(source->GetFd());
102     if (iter == sources_.cend()) {
103         FI_HILOGE("No epoll source(%d)", source->GetFd());
104         return false;
105     }
106     struct epoll_event ev {};
107     ev.events = source->GetEvents();
108     ev.data.ptr = source.get();
109 
110     int32_t ret = ::epoll_ctl(epollFd_, EPOLL_CTL_MOD, source->GetFd(), &ev);
111     if (ret != 0) {
112         FI_HILOGE("epoll_ctl failed:%{public}s", ::strerror(errno));
113         return false;
114     }
115     sources_.insert_or_assign(source->GetFd(), source);
116     return true;
117 }
118 
Wait(struct epoll_event *events, int32_t maxevents)119 int32_t EpollManager::Wait(struct epoll_event *events, int32_t maxevents)
120 {
121     return WaitTimeout(events, maxevents, -1);
122 }
123 
WaitTimeout(struct epoll_event *events, int32_t maxevents, int32_t timeout)124 int32_t EpollManager::WaitTimeout(struct epoll_event *events, int32_t maxevents, int32_t timeout)
125 {
126     int32_t ret = ::epoll_wait(epollFd_, events, maxevents, timeout);
127     if (ret < 0) {
128         FI_HILOGE("epoll_wait failed:%{public}s", ::strerror(errno));
129     } else if (ret == 0) {
130         FI_HILOGE("epoll_wait timeout");
131     }
132     return ret;
133 }
134 
Dispatch(const struct epoll_event &ev)135 void EpollManager::Dispatch(const struct epoll_event &ev)
136 {
137     CALL_DEBUG_ENTER;
138     if ((ev.events & EPOLLIN) == EPOLLIN) {
139         DispatchOne(ev);
140     } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
141         FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
142     }
143 }
144 
DispatchOne(const struct epoll_event &ev)145 void EpollManager::DispatchOne(const struct epoll_event &ev)
146 {
147     struct epoll_event evs[MAX_N_EVENTS];
148     int32_t cnt = WaitTimeout(evs, MAX_N_EVENTS, 0);
149 
150     for (int32_t index = 0; index < cnt; ++index) {
151         IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
152         CHKPC(source);
153         if ((evs[index].events & EPOLLIN) == EPOLLIN) {
154             source->Dispatch(evs[index]);
155         } else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
156             FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
157         }
158     }
159 }
160 } // namespace DeviceStatus
161 } // namespace Msdp
162 } // namespace OHOS