• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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