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