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