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 "timer_manager.h"
17
18 #undef MMI_LOG_TAG
19 #define MMI_LOG_TAG "TimerManager"
20 #undef MMI_LOG_DOMAIN
21 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
22
23 namespace OHOS {
24 namespace MMI {
25 namespace {
26 constexpr int32_t MIN_DELAY { -1 };
27 constexpr int32_t MIN_INTERVAL { 36 };
28 constexpr int32_t MAX_INTERVAL_MS { 10000 };
29 constexpr int32_t MAX_TIMER_COUNT { 64 };
30 constexpr int32_t NONEXISTENT_ID { -1 };
31 } // namespace
32
TimerManager()33 TimerManager::TimerManager() {}
~TimerManager()34 TimerManager::~TimerManager() {}
35
AddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)36 int32_t TimerManager::AddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
37 {
38 return AddTimerInternal(intervalMs, repeatCount, callback);
39 }
40
RemoveTimer(int32_t timerId)41 int32_t TimerManager::RemoveTimer(int32_t timerId)
42 {
43 return RemoveTimerInternal(timerId);
44 }
45
ResetTimer(int32_t timerId)46 int32_t TimerManager::ResetTimer(int32_t timerId)
47 {
48 return ResetTimerInternal(timerId);
49 }
50
IsExist(int32_t timerId)51 bool TimerManager::IsExist(int32_t timerId)
52 {
53 return IsExistInternal(timerId);
54 }
55
CalcNextDelay()56 int32_t TimerManager::CalcNextDelay()
57 {
58 return CalcNextDelayInternal();
59 }
60
ProcessTimers()61 void TimerManager::ProcessTimers()
62 {
63 ProcessTimersInternal();
64 }
65
TakeNextTimerId()66 int32_t TimerManager::TakeNextTimerId()
67 {
68 uint64_t timerSlot = 0;
69 uint64_t one = 1;
70 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
71 for (const auto &timer : timers_) {
72 timerSlot |= (one << timer->id);
73 }
74
75 for (int32_t i = 0; i < MAX_TIMER_COUNT; i++) {
76 if ((timerSlot & (one << i)) == 0) {
77 return i;
78 }
79 }
80 return NONEXISTENT_ID;
81 }
82
AddTimerInternal(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)83 int32_t TimerManager::AddTimerInternal(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
84 {
85 if (intervalMs < MIN_INTERVAL) {
86 intervalMs = MIN_INTERVAL;
87 } else if (intervalMs > MAX_INTERVAL_MS) {
88 intervalMs = MAX_INTERVAL_MS;
89 }
90 if (!callback) {
91 return NONEXISTENT_ID;
92 }
93 int32_t timerId = TakeNextTimerId();
94 if (timerId < 0) {
95 return NONEXISTENT_ID;
96 }
97 auto timer = std::make_unique<TimerItem>();
98 timer->id = timerId;
99 timer->intervalMs = intervalMs;
100 timer->repeatCount = repeatCount;
101 timer->callbackCount = 0;
102 auto nowTime = GetMillisTime();
103 if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
104 MMI_HILOGE("The addition of nextCallTime in TimerItem overflows");
105 return NONEXISTENT_ID;
106 }
107 timer->callback = callback;
108 InsertTimerInternal(timer);
109 return timerId;
110 }
111
RemoveTimerInternal(int32_t timerId)112 int32_t TimerManager::RemoveTimerInternal(int32_t timerId)
113 {
114 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
115 for (auto it = timers_.begin(); it != timers_.end(); ++it) {
116 if ((*it)->id == timerId) {
117 timers_.erase(it);
118 return RET_OK;
119 }
120 }
121 return RET_ERR;
122 }
123
ResetTimerInternal(int32_t timerId)124 int32_t TimerManager::ResetTimerInternal(int32_t timerId)
125 {
126 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
127 for (auto it = timers_.begin(); it != timers_.end(); ++it) {
128 if ((*it)->id == timerId) {
129 auto timer = std::move(*it);
130 timers_.erase(it);
131 auto nowTime = GetMillisTime();
132 if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
133 MMI_HILOGE("The addition of nextCallTime in TimerItem overflows");
134 return RET_ERR;
135 }
136 timer->callbackCount = 0;
137 InsertTimerInternal(timer);
138 return RET_OK;
139 }
140 }
141 return RET_ERR;
142 }
143
IsExistInternal(int32_t timerId)144 bool TimerManager::IsExistInternal(int32_t timerId)
145 {
146 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
147 for (auto it = timers_.begin(); it != timers_.end(); ++it) {
148 if ((*it)->id == timerId) {
149 return true;
150 }
151 }
152 return false;
153 }
154
InsertTimerInternal(std::unique_ptr<TimerItem> & timer)155 void TimerManager::InsertTimerInternal(std::unique_ptr<TimerItem>& timer)
156 {
157 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
158 for (auto it = timers_.begin(); it != timers_.end(); ++it) {
159 if ((*it)->nextCallTime > timer->nextCallTime) {
160 timers_.insert(it, std::move(timer));
161 return;
162 }
163 }
164 timers_.push_back(std::move(timer));
165 }
166
CalcNextDelayInternal()167 int32_t TimerManager::CalcNextDelayInternal()
168 {
169 auto delay = MIN_DELAY;
170 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
171 if (!timers_.empty()) {
172 auto nowTime = GetMillisTime();
173 const auto& item = *timers_.begin();
174 if (nowTime >= item->nextCallTime) {
175 delay = 0;
176 } else {
177 delay = item->nextCallTime - nowTime;
178 }
179 }
180 return delay;
181 }
182
ProcessTimersInternal()183 void TimerManager::ProcessTimersInternal()
184 {
185 std::lock_guard<std::recursive_mutex> lock(timerMutex_);
186 if (timers_.empty()) {
187 return;
188 }
189 auto nowTime = GetMillisTime();
190 for (;;) {
191 auto it = timers_.begin();
192 if (it == timers_.end()) {
193 break;
194 }
195 if ((*it)->nextCallTime > nowTime) {
196 break;
197 }
198 auto curTimer = std::move(*it);
199 timers_.erase(it);
200 ++curTimer->callbackCount;
201 if ((curTimer->repeatCount >= 1) && (curTimer->callbackCount >= curTimer->repeatCount)) {
202 curTimer->callback();
203 continue;
204 }
205 if (!AddInt64(curTimer->nextCallTime, curTimer->intervalMs, curTimer->nextCallTime)) {
206 MMI_HILOGE("The addition of nextCallTime in TimerItem overflows");
207 return;
208 }
209 auto callback = curTimer->callback;
210 InsertTimerInternal(curTimer);
211 callback();
212 }
213 }
214 } // namespace MMI
215 } // namespace OHOS
216