1 /*
2 * Copyright (c) 2021-2022 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 "inner_event.h"
17
18 #include <condition_variable>
19 #include <mutex>
20 #include <vector>
21
22 #include "event_handler_utils.h"
23 #include "singleton.h"
24
25 DEFINE_HILOG_LABEL("InnerEvent");
26
27 namespace OHOS {
28 namespace AppExecFwk {
29 namespace {
30 class WaiterImp final : public InnerEvent::Waiter {
31 public:
WaiterImp()32 WaiterImp(){};
~WaiterImp()33 ~WaiterImp() override{};
34 DISALLOW_COPY_AND_MOVE(WaiterImp);
35
Wait()36 void Wait() final
37 {
38 std::unique_lock<std::mutex> lock(mutex_);
39 while (!finished_) {
40 ++waitingCount_;
41 condition_.wait(lock);
42 --waitingCount_;
43 }
44 }
45
Notify()46 void Notify() final
47 {
48 std::lock_guard<std::mutex> lock(mutex_);
49 finished_ = true;
50 if (waitingCount_ > 0) {
51 condition_.notify_all();
52 }
53 }
54
55 private:
56 std::mutex mutex_;
57 std::condition_variable condition_;
58 uint32_t waitingCount_ {0};
59 bool finished_ {false};
60 };
61 } // unnamed namespace
62
63 // Implementation for event pool.
64 class InnerEventPool : public DelayedRefSingleton<InnerEventPool> {
65 DECLARE_DELAYED_REF_SINGLETON(InnerEventPool);
66
67 public:
68 DISALLOW_COPY_AND_MOVE(InnerEventPool);
69
Get()70 InnerEvent::Pointer Get()
71 {
72 size_t newPeakUsingCount = 0;
73
74 {
75 // Check whether pool is empty.
76 std::lock_guard<std::mutex> lock(poolLock_);
77 ++usingCount_;
78 if (!events_.empty()) {
79 auto event = std::move(events_.back());
80 events_.pop_back();
81 return InnerEvent::Pointer(event.release(), Drop);
82 }
83
84 // Update peak using events count.
85 if (usingCount_ >= nextPeakUsingCount_) {
86 if (UINT32_MAX - nextPeakUsingCount_ > MAX_BUFFER_POOL_SIZE) {
87 nextPeakUsingCount_ += MAX_BUFFER_POOL_SIZE;
88 } else {
89 nextPeakUsingCount_ = UINT32_MAX;
90 }
91
92 newPeakUsingCount = usingCount_;
93 }
94 }
95
96 // Print the new peak using count of inner events
97 if (newPeakUsingCount > 0) {
98 HILOGD("Peak using count of inner events is up to %{public}zu", newPeakUsingCount);
99 }
100
101 // Allocate new memory, while pool is empty.
102 return InnerEvent::Pointer(new InnerEvent, Drop);
103 }
104
105 private:
Drop(InnerEvent * event)106 static void Drop(InnerEvent *event)
107 {
108 if (event == nullptr) {
109 return;
110 }
111
112 auto destructor = [](InnerEvent *event) {
113 if (event != nullptr) {
114 delete event;
115 }
116 };
117
118 // Clear content of the event
119 event->ClearEvent();
120 // Put event into event buffer pool
121 GetInstance().Put(InnerEvent::Pointer(event, destructor));
122 }
123
Put(InnerEvent::Pointer && event)124 void Put(InnerEvent::Pointer &&event)
125 {
126 // Check whether pool is full.
127 std::lock_guard<std::mutex> lock(poolLock_);
128 --usingCount_;
129 if (events_.size() < MAX_BUFFER_POOL_SIZE) {
130 events_.push_back(std::move(event));
131 }
132 }
133
134 static const size_t MAX_BUFFER_POOL_SIZE = 64;
135
136 std::mutex poolLock_;
137 std::vector<InnerEvent::Pointer> events_;
138
139 // Used to statistical peak value of count of using inner events.
140 size_t usingCount_ {0};
141 size_t nextPeakUsingCount_ {MAX_BUFFER_POOL_SIZE};
142 };
143
InnerEventPool()144 InnerEventPool::InnerEventPool() : poolLock_(), events_()
145 {
146 // Reserve enough memory
147 std::lock_guard<std::mutex> lock(poolLock_);
148 events_.reserve(MAX_BUFFER_POOL_SIZE);
149 }
150
~InnerEventPool()151 InnerEventPool::~InnerEventPool()
152 {
153 // Release all memory in the poll
154 std::lock_guard<std::mutex> lock(poolLock_);
155 events_.clear();
156 }
157
Get()158 InnerEvent::Pointer InnerEvent::Get()
159 {
160 auto event = InnerEventPool::GetInstance().Get();
161 return event;
162 }
163
Get(uint32_t innerEventId,int64_t param)164 InnerEvent::Pointer InnerEvent::Get(uint32_t innerEventId, int64_t param)
165 {
166 auto event = InnerEventPool::GetInstance().Get();
167 if (event != nullptr) {
168 event->innerEventId_ = innerEventId;
169 event->param_ = param;
170 }
171 return event;
172 }
173
Get(const Callback & callback,const std::string & name)174 InnerEvent::Pointer InnerEvent::Get(const Callback &callback, const std::string &name)
175 {
176 // Returns nullptr while callback is invalid.
177 if (!callback) {
178 HILOGW("Failed to create inner event with an invalid callback");
179 return InnerEvent::Pointer(nullptr, nullptr);
180 }
181
182 auto event = InnerEventPool::GetInstance().Get();
183 if (event != nullptr) {
184 event->taskCallback_ = callback;
185 event->taskName_ = name;
186 }
187 return event;
188 }
189
ClearEvent()190 void InnerEvent::ClearEvent()
191 {
192 // Wake up all waiting threads.
193 if (waiter_) {
194 waiter_->Notify();
195 waiter_.reset();
196 }
197
198 if (HasTask()) {
199 // Clear members for task
200 taskCallback_ = nullptr;
201 taskName_.clear();
202 } else {
203 // Clear members for event
204 if (smartPtrDtor_) {
205 smartPtrDtor_(smartPtr_);
206 smartPtrDtor_ = nullptr;
207 smartPtr_ = nullptr;
208 smartPtrTypeId_ = 0;
209 }
210 }
211
212 if (hiTraceId_) {
213 hiTraceId_.reset();
214 }
215
216 // Clear owner
217 owner_.reset();
218 }
219
WarnSmartPtrCastMismatch()220 void InnerEvent::WarnSmartPtrCastMismatch()
221 {
222 HILOGE("Type of the shared_ptr, weak_ptr or unique_ptr mismatched");
223 }
224
CreateWaiter()225 const std::shared_ptr<InnerEvent::Waiter> &InnerEvent::CreateWaiter()
226 {
227 waiter_ = std::make_shared<WaiterImp>();
228 return waiter_;
229 }
230
HasWaiter() const231 bool InnerEvent::HasWaiter() const
232 {
233 return (waiter_ != nullptr);
234 }
235
GetOrCreateTraceId()236 const std::shared_ptr<HiTraceId> InnerEvent::GetOrCreateTraceId()
237 {
238 if (hiTraceId_) {
239 return hiTraceId_;
240 }
241
242 auto traceId = HiTraceChain::GetId();
243 if (!traceId.IsValid()) {
244 return nullptr;
245 }
246
247 hiTraceId_ = std::make_shared<HiTraceId>(HiTraceChain::CreateSpan());
248 return hiTraceId_;
249 }
250
GetTraceId()251 const std::shared_ptr<HiTraceId> InnerEvent::GetTraceId()
252 {
253 return hiTraceId_;
254 }
255
Dump()256 std::string InnerEvent::Dump()
257 {
258 std::string content;
259
260 content.append("Event { ");
261 if (!owner_.expired()) {
262 if (HasTask()) {
263 content.append("task name = " + taskName_);
264 } else {
265 content.append("id = " + std::to_string(innerEventId_));
266 }
267 if (param_ != 0) {
268 content.append(", param = " + std::to_string(param_));
269 }
270 } else {
271 content = "No handler";
272 }
273 content.append(" }" + LINE_SEPARATOR);
274
275 return content;
276 }
277 } // namespace AppExecFwk
278 } // namespace OHOS
279