1 /*
2 * Copyright (c) 2023-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 <securec.h>
17 #include <algorithm>
18 #include "timer_core.h"
19 #include "thread_utils.h"
20 #include "steady_clock.h"
21 #include "dp_log.h"
22
23 namespace OHOS {
24 namespace CameraStandard {
25 namespace {
26 constexpr uint32_t EXPIREATION_TIME_MILLI_SECONDS = 12 * 60 * 1000;
27 } //namespace
28
29 namespace DeferredProcessing {
GetInstance()30 TimerCore& TimerCore::GetInstance()
31 {
32 static TimerCore instance;
33 return instance;
34 }
35
TimerCore()36 TimerCore::TimerCore()
37 {
38 DP_DEBUG_LOG("entered.");
39 }
40
~TimerCore()41 TimerCore::~TimerCore()
42 {
43 DP_DEBUG_LOG("entered.");
44 {
45 std::unique_lock<std::mutex> lock(mutex_);
46 registeredTimers_.clear();
47 active_ = false;
48 cv_.notify_one();
49 }
50 if (worker_.joinable()) {
51 worker_.join();
52 }
53 DP_DEBUG_LOG("exited.");
54 }
55
Initialize()56 bool TimerCore::Initialize()
57 {
58 DP_DEBUG_LOG("entered.");
59 std::unique_lock<std::mutex> lock(mutex_);
60 if (!active_) {
61 active_ = true;
62 const std::string threadName = "TimerCore";
63 worker_ = std::thread([this, threadName]() { TimerLoop(threadName); });
64 SetThreadName(worker_.native_handle(), threadName);
65 SetThreadPriority(worker_.native_handle(), PRIORITY_NORMAL);
66 }
67 return true;
68 }
69
RegisterTimer(uint64_t timestampMs,const std::shared_ptr<Timer> & timer)70 bool TimerCore::RegisterTimer(uint64_t timestampMs, const std::shared_ptr<Timer>& timer)
71 {
72 if (!active_) {
73 return false;
74 }
75 if (timer == nullptr) {
76 DP_DEBUG_LOG("failed due to nullptr.");
77 return false;
78 }
79 std::unique_lock<std::mutex> lock(mutex_);
80 if (registeredTimers_.count(timestampMs) == 0) {
81 timeline_.push(timestampMs);
82 if (timestampMs == timeline_.top()) {
83 resetTimer_ = true;
84 cv_.notify_one();
85 }
86 }
87 registeredTimers_[timestampMs].push_back(timer);
88 DP_DEBUG_LOG("register timer (%s), timestamp: %{public}d, timeline.top: %{public}d", timer->GetName().c_str(),
89 static_cast<int>(timestampMs), static_cast<int>(timeline_.top()));
90 return true;
91 }
92
DeregisterTimer(uint64_t timestampMs,const std::shared_ptr<Timer> & timer)93 bool TimerCore::DeregisterTimer(uint64_t timestampMs, const std::shared_ptr<Timer>& timer)
94 {
95 if (!active_) {
96 return true;
97 }
98 if (timer == nullptr) {
99 DP_ERR_LOG("failed due to nullptr.");
100 return false;
101 }
102 DP_DEBUG_LOG("(%s, %{public}d) entered.", timer->GetName().c_str(), static_cast<int>(timestampMs));
103 std::unique_lock<std::mutex> lock(mutex_);
104 if (registeredTimers_.count(timestampMs)) {
105 auto& timers = registeredTimers_[timestampMs];
106 timers.erase(std::remove_if(timers.begin(), timers.end(),
107 [this, &timer](auto& weakTimer) { return IsSameOwner(timer, weakTimer); }), timers.end());
108 if (timers.empty()) {
109 registeredTimers_.erase(timestampMs);
110 }
111 }
112 return true;
113 }
114
TimerLoop(const std::string & threadName)115 void TimerCore::TimerLoop(const std::string& threadName)
116 {
117 DP_DEBUG_LOG("(%s) entered.", threadName.c_str());
118 while (active_.load()) {
119 {
120 std::unique_lock<std::mutex> lock(mutex_);
121 bool stopWaiting = cv_.wait_for(lock, GetNextExpirationTimeUnlocked(), [this] {
122 bool stopWaiting = !active_.load() || resetTimer_.load();
123 resetTimer_ = false;
124 return stopWaiting;
125 });
126 if (stopWaiting) {
127 continue;
128 }
129 }
130 DoTimeout();
131 }
132 DP_DEBUG_LOG("(%s) exited.", threadName.c_str());
133 }
134
GetNextExpirationTimeUnlocked()135 std::chrono::milliseconds TimerCore::GetNextExpirationTimeUnlocked()
136 {
137 std::chrono::milliseconds expirationTime(EXPIREATION_TIME_MILLI_SECONDS);
138 if (!timeline_.empty()) {
139 expirationTime = SteadyClock::GetRemainingTimeMs(timeline_.top());
140 }
141 DP_DEBUG_LOG("expiration time: %lld.", expirationTime.count());
142 return expirationTime;
143 }
144
DoTimeout()145 void TimerCore::DoTimeout()
146 {
147 std::vector<std::weak_ptr<Timer>> timers;
148 {
149 std::unique_lock<std::mutex> lock(mutex_);
150 if (timeline_.empty()) {
151 DP_DEBUG_LOG("no register timer.");
152 return;
153 }
154 auto timestamp = timeline_.top();
155 timeline_.pop();
156 if (registeredTimers_.count(timestamp) == 0) {
157 DP_DEBUG_LOG("timer for timestamp %{public}d hasn't been registered.", static_cast<int>(timestamp));
158 return;
159 }
160 DP_DEBUG_LOG("expired timestamp: %{public}d", static_cast<int>(timestamp));
161 timers = std::move(registeredTimers_[timestamp]);
162 registeredTimers_.erase(timestamp);
163 }
164 for (auto& weakTimer : timers) {
165 if (auto timer = weakTimer.lock()) {
166 timer->TimerExpired();
167 }
168 }
169 }
170
IsSameOwner(const std::shared_ptr<Timer> & lhs,const std::weak_ptr<Timer> & rhs)171 bool TimerCore::IsSameOwner(const std::shared_ptr<Timer>& lhs, const std::weak_ptr<Timer>& rhs)
172 {
173 return !lhs.owner_before(rhs) && !rhs.owner_before(lhs);
174 }
175 } //namespace DeferredProcessing
176 } // namespace CameraStandard
177 } // namespace OHOS
178