/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "inner_event.h" #include #include #include #include "event_handler_utils.h" #include "singleton.h" DEFINE_HILOG_LABEL("InnerEvent"); namespace OHOS { namespace AppExecFwk { namespace { static constexpr int DATETIME_STRING_LENGTH = 80; static constexpr int MAX_MS_LENGTH = 3; static constexpr int MS_PER_SECOND = 1000; class WaiterImp final : public InnerEvent::Waiter { public: WaiterImp(){}; ~WaiterImp() override{}; DISALLOW_COPY_AND_MOVE(WaiterImp); void Wait() final { std::unique_lock lock(mutex_); while (!finished_) { ++waitingCount_; condition_.wait(lock); --waitingCount_; } } void Notify() final { std::lock_guard lock(mutex_); finished_ = true; if (waitingCount_ > 0) { condition_.notify_all(); } } private: std::mutex mutex_; std::condition_variable condition_; uint32_t waitingCount_ {0}; bool finished_ {false}; }; } // unnamed namespace // Implementation for event pool. class InnerEventPool : public DelayedRefSingleton { DECLARE_DELAYED_REF_SINGLETON(InnerEventPool); public: DISALLOW_COPY_AND_MOVE(InnerEventPool); InnerEvent::Pointer Get() { size_t newPeakUsingCount = 0; { // Check whether pool is empty. std::lock_guard lock(poolLock_); ++usingCount_; if (!events_.empty()) { auto event = std::move(events_.back()); events_.pop_back(); return InnerEvent::Pointer(event.release(), Drop); } // Update peak using events count. if (usingCount_ >= nextPeakUsingCount_) { if (UINT32_MAX - nextPeakUsingCount_ > MAX_BUFFER_POOL_SIZE) { nextPeakUsingCount_ += MAX_BUFFER_POOL_SIZE; } else { nextPeakUsingCount_ = UINT32_MAX; } newPeakUsingCount = usingCount_; } } // Print the new peak using count of inner events if (newPeakUsingCount > 0) { HILOGD("Peak using count of inner events is up to %{public}zu", newPeakUsingCount); } // Allocate new memory, while pool is empty. return InnerEvent::Pointer(new InnerEvent, Drop); } private: static void Drop(InnerEvent *event) { if (event == nullptr) { return; } auto destructor = [](InnerEvent *event) { if (event != nullptr) { delete event; } }; // Clear content of the event event->ClearEvent(); // Put event into event buffer pool GetInstance().Put(InnerEvent::Pointer(event, destructor)); } void Put(InnerEvent::Pointer &&event) { // Check whether pool is full. std::lock_guard lock(poolLock_); --usingCount_; if (events_.size() < MAX_BUFFER_POOL_SIZE) { events_.push_back(std::move(event)); } } static const size_t MAX_BUFFER_POOL_SIZE = 64; std::mutex poolLock_; std::vector events_; // Used to statistical peak value of count of using inner events. size_t usingCount_ {0}; size_t nextPeakUsingCount_ {MAX_BUFFER_POOL_SIZE}; }; InnerEventPool::InnerEventPool() : poolLock_(), events_() { // Reserve enough memory std::lock_guard lock(poolLock_); events_.reserve(MAX_BUFFER_POOL_SIZE); } InnerEventPool::~InnerEventPool() { // Release all memory in the poll std::lock_guard lock(poolLock_); events_.clear(); } InnerEvent::Pointer InnerEvent::Get() { auto event = InnerEventPool::GetInstance().Get(); return event; } InnerEvent::Pointer InnerEvent::Get(uint32_t innerEventId, int64_t param) { auto event = InnerEventPool::GetInstance().Get(); if (event != nullptr) { event->innerEventId_ = innerEventId; event->param_ = param; } return event; } InnerEvent::Pointer InnerEvent::Get(const Callback &callback, const std::string &name) { // Returns nullptr while callback is invalid. if (!callback) { HILOGW("Failed to create inner event with an invalid callback"); return InnerEvent::Pointer(nullptr, nullptr); } auto event = InnerEventPool::GetInstance().Get(); if (event != nullptr) { event->taskCallback_ = callback; event->taskName_ = name; } return event; } void InnerEvent::ClearEvent() { // Wake up all waiting threads. if (waiter_) { waiter_->Notify(); waiter_.reset(); } if (HasTask()) { // Clear members for task taskCallback_ = nullptr; taskName_.clear(); } else { // Clear members for event if (smartPtrDtor_) { smartPtrDtor_(smartPtr_); smartPtrDtor_ = nullptr; smartPtr_ = nullptr; smartPtrTypeId_ = 0; } } if (hiTraceId_) { hiTraceId_.reset(); } // Clear owner owner_.reset(); } void InnerEvent::WarnSmartPtrCastMismatch() { HILOGE("Type of the shared_ptr, weak_ptr or unique_ptr mismatched"); } const std::shared_ptr &InnerEvent::CreateWaiter() { waiter_ = std::make_shared(); return waiter_; } bool InnerEvent::HasWaiter() const { return (waiter_ != nullptr); } const std::shared_ptr InnerEvent::GetOrCreateTraceId() { if (hiTraceId_) { return hiTraceId_; } auto traceId = HiTraceChain::GetId(); if (!traceId.IsValid()) { return nullptr; } hiTraceId_ = std::make_shared(HiTraceChain::CreateSpan()); return hiTraceId_; } const std::shared_ptr InnerEvent::GetTraceId() { return hiTraceId_; } std::string InnerEvent::DumpTimeToString(const std::chrono::system_clock::time_point &time) { auto tp = std::chrono::time_point_cast(time); auto tt = std::chrono::system_clock::to_time_t(time); auto ms = tp.time_since_epoch().count() % MS_PER_SECOND; auto msString = std::to_string(ms); if (msString.length() < MAX_MS_LENGTH) { msString = std::string(MAX_MS_LENGTH - msString.length(), '0') + msString; } struct tm curTime = {0}; localtime_r(&tt, &curTime); char sysTime[DATETIME_STRING_LENGTH]; std::strftime(sysTime, sizeof(char) * DATETIME_STRING_LENGTH, "%Y-%m-%d %I:%M:%S.", &curTime); return std::string(sysTime) + msString; } std::string InnerEvent::DumpTimeToString(const TimePoint &time) { auto tp = std::chrono::system_clock::now() + std::chrono::duration_cast(time - std::chrono::steady_clock::now()); return DumpTimeToString(tp); } std::string InnerEvent::Dump() { std::string content; content.append("Event { "); if (!owner_.expired()) { content.append("send thread = " + std::to_string(senderKernelThreadId_)); content.append(", send time = " + DumpTimeToString(sendTime_)); content.append(", handle time = " + DumpTimeToString(handleTime_)); if (HasTask()) { content.append(", task name = " + taskName_); } else { content.append(", id = " + std::to_string(innerEventId_)); } if (param_ != 0) { content.append(", param = " + std::to_string(param_)); } } else { content.append("No handler"); } content.append(" }" + LINE_SEPARATOR); return content; } } // namespace AppExecFwk } // namespace OHOS