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_io_waiter.h"
17 
18 #include <map>
19 #include <memory>
20 #include <mutex>
21 
22 #include <uv.h>
23 
24 #include "event_handler_utils.h"
25 #include "file_descriptor_listener.h"
26 
27 DEFINE_HILOG_LABEL("EpollIoWaiter");
28 
29 #define UVERRLOG(call, err) HILOGE(#call " failed because %{public}s", uv_strerror(err))
30 #define UVERR(call, err) { if (err) { UVERRLOG(call, err); } }
31 #define UVERRRET(call, err) { if (err) { UVERRLOG(call, err); return; } }
32 #define UVERRRETVAL(call, err) { if (err) { UVERRLOG(call, err); return err; } }
33 #define UVCALL(call, ...) { if (auto err = call(__VA_ARGS__)) { UVERR(#call, err); } }
34 #define UVCALLRET(call, ...) { if (auto err = call(__VA_ARGS__)) { UVERRRET(#call, err); } }
35 #define UVCALLRETVAL(call, ...) { if (auto err = call(__VA_ARGS__)) { UVERRRETVAL(#call, err); } }
36 
37 namespace OHOS {
38 namespace AppExecFwk {
~EpollIoWaiter()39 EpollIoWaiter::~EpollIoWaiter()
40 {
41     uv_signal_stop(&signal_);
42     uv_timer_stop(&timer_);
43     uv_stop(&loop_);
44     uv_loop_close(&loop_);
45 }
46 
Init()47 bool EpollIoWaiter::Init()
48 {
49     UVCALL(uv_loop_init, &loop_);
50     UVCALL(uv_signal_init, &loop_, &signal_);
51     UVCALL(uv_signal_start, &signal_, OnSignal, SIGINT);
52     UVCALL(uv_timer_init, &loop_, &timer_);
53     return true;
54 }
55 
WaitFor(std::unique_lock<std::mutex> & lock,int64_t nanoseconds)56 bool EpollIoWaiter::WaitFor(std::unique_lock<std::mutex> &lock, int64_t nanoseconds)
57 {
58     UVCALL(uv_timer_start, &timer_, OnTimer, nanoseconds / 1e6, 0);
59     lock.unlock();
60     uv_run(&loop_, UV_RUN_DEFAULT);
61     lock.lock();
62     return overtime;
63 }
64 
NotifyOne()65 void EpollIoWaiter::NotifyOne()
66 {
67     NotifyAll();
68 }
69 
NotifyAll()70 void EpollIoWaiter::NotifyAll()
71 {
72     std::lock_guard lock(timerMutex_);
73     UVCALL(uv_timer_start, &timer_, OnTimer, 0, 0);
74 }
75 
SupportListeningFileDescriptor() const76 bool EpollIoWaiter::SupportListeningFileDescriptor() const
77 {
78     return true;
79 }
80 
AddFileDescriptor(int32_t fd,uint32_t events)81 bool EpollIoWaiter::AddFileDescriptor(int32_t fd, uint32_t events)
82 {
83     if (pollMap_.find(fd) != pollMap_.end()) {
84         return false;
85     }
86 
87     pollMap_[fd] = {.data = this};
88     UVCALL(uv_poll_init, &loop_, &pollMap_[fd], fd);
89     UVCALL(uv_poll_start, &pollMap_[fd], static_cast<uint8_t>(events), OnPoll);
90     return true;
91 }
92 
RemoveFileDescriptor(int32_t fd)93 void EpollIoWaiter::RemoveFileDescriptor(int32_t fd)
94 {
95     const auto &it = pollMap_.find(fd);
96     if (it == pollMap_.end()) {
97         return;
98     }
99 
100     UVCALL(uv_poll_stop, &it->second);
101 }
102 
SetFileDescriptorEventCallback(const IoWaiter::FileDescriptorEventCallback & callback)103 void EpollIoWaiter::SetFileDescriptorEventCallback(const IoWaiter::FileDescriptorEventCallback &callback)
104 {
105     fdcallback_ = callback;
106 }
107 
OnPoll(uv_poll_t * poll,int status,int events)108 void EpollIoWaiter::OnPoll(uv_poll_t *poll, int status, int events)
109 {
110     UVERR(OnPoll, status);
111     auto &that = GetInstance(poll);
112     std::lock_guard lock(that.timerMutex_);
113     UVCALL(uv_timer_stop, &that.timer_);
114     uv_stop(&that.loop_);
115     if (that.fdcallback_) {
116         int32_t pollfd = -1;
117         for (const auto &[fd, p] : that.pollMap_) {
118             if (&p == poll) {
119                 pollfd = fd;
120                 break;
121             }
122         }
123         that.fdcallback_(pollfd, events);
124     }
125     that.overtime = false;
126 }
127 
OnTimer(uv_timer_t * timer)128 void EpollIoWaiter::OnTimer(uv_timer_t *timer)
129 {
130     auto &that = GetInstance(timer);
131     std::lock_guard lock(that.timerMutex_);
132     UVCALL(uv_timer_stop, timer);
133     uv_stop(&that.loop_);
134     that.overtime = true;
135 }
136 
OnSignal(uv_signal_t * signal,int32_t signum)137 void EpollIoWaiter::OnSignal(uv_signal_t *signal, int32_t signum)
138 {
139     auto &that = GetInstance(signal);
140     if (signum == SIGINT) {
141         UVCALL(uv_signal_stop, signal);
142         that.NotifyAll();
143     }
144 }
145 }  // namespace AppExecFwk
146 }  // namespace OHOS
147