1 /*
2 * Copyright (c) 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 "timer_manager.h"
17
18 #include <numeric>
19
20 #include <sys/timerfd.h>
21
22 #include "devicestatus_define.h"
23 #include "include/util.h"
24
25 namespace OHOS {
26 namespace Msdp {
27 namespace DeviceStatus {
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "TimerManager" };
30 constexpr int32_t MIN_DELAY { -1 };
31 constexpr int32_t MIN_INTERVAL { 50 };
32 constexpr int32_t MAX_INTERVAL_MS { 10000 };
33 constexpr int32_t NONEXISTENT_ID { -1 };
34 constexpr int32_t TIME_CONVERSION { 1000 };
35 constexpr size_t MAX_TIMER_COUNT { 64 };
36 } // namespace
37
Init(IContext * context)38 int32_t TimerManager::Init(IContext *context)
39 {
40 CHKPR(context, RET_ERR);
41 return context->GetDelegateTasks().PostSyncTask(std::bind(&TimerManager::OnInit, this, context));
42 }
43
OnInit(IContext * context)44 int32_t TimerManager::OnInit(IContext *context)
45 {
46 CHKPR(context, RET_ERR);
47 context_ = context;
48
49 timerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
50 if (timerFd_ < 0) {
51 FI_HILOGE("Timer: timerfd_create failed");
52 return RET_ERR;
53 }
54 return RET_OK;
55 }
56
AddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)57 int32_t TimerManager::AddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
58 {
59 CALL_DEBUG_ENTER;
60 CHKPR(context_, RET_ERR);
61 return context_->GetDelegateTasks().PostSyncTask(
62 std::bind(&TimerManager::OnAddTimer, this, intervalMs, repeatCount, callback));
63 }
64
OnAddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)65 int32_t TimerManager::OnAddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
66 {
67 int32_t timerId = AddTimerInternal(intervalMs, repeatCount, callback);
68 ArmTimer();
69 return timerId;
70 }
71
RemoveTimer(int32_t timerId)72 int32_t TimerManager::RemoveTimer(int32_t timerId)
73 {
74 CALL_DEBUG_ENTER;
75 CHKPR(context_, RET_ERR);
76 return context_->GetDelegateTasks().PostSyncTask(std::bind(&TimerManager::OnRemoveTimer, this, timerId));
77 }
78
OnRemoveTimer(int32_t timerId)79 int32_t TimerManager::OnRemoveTimer(int32_t timerId)
80 {
81 int32_t ret = RemoveTimerInternal(timerId);
82 if (ret == RET_OK) {
83 ArmTimer();
84 }
85 return ret;
86 }
87
ResetTimer(int32_t timerId)88 int32_t TimerManager::ResetTimer(int32_t timerId)
89 {
90 CALL_INFO_TRACE;
91 CHKPR(context_, RET_ERR);
92 return context_->GetDelegateTasks().PostSyncTask(std::bind(&TimerManager::OnResetTimer, this, timerId));
93 }
94
OnResetTimer(int32_t timerId)95 int32_t TimerManager::OnResetTimer(int32_t timerId)
96 {
97 int32_t ret = ResetTimerInternal(timerId);
98 ArmTimer();
99 return ret;
100 }
101
IsExist(int32_t timerId) const102 bool TimerManager::IsExist(int32_t timerId) const
103 {
104 CHKPR(context_, false);
105 std::packaged_task<bool(int32_t)> task { std::bind(&TimerManager::OnIsExist, this, std::placeholders::_1) };
106 auto fu = task.get_future();
107
108 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
109 std::bind(&TimerManager::RunIsExist, this, std::ref(task), timerId));
110 if (ret != RET_OK) {
111 FI_HILOGE("Post task failed");
112 return false;
113 }
114 return fu.get();
115 }
116
OnIsExist(int32_t timerId) const117 bool TimerManager::OnIsExist(int32_t timerId) const
118 {
119 for (auto tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
120 if ((*tIter)->id == timerId) {
121 return true;
122 }
123 }
124 return false;
125 }
126
RunIsExist(std::packaged_task<bool (int32_t)> & task,int32_t timerId) const127 int32_t TimerManager::RunIsExist(std::packaged_task<bool(int32_t)> &task, int32_t timerId) const
128 {
129 task(timerId);
130 return RET_OK;
131 }
132
ProcessTimers()133 void TimerManager::ProcessTimers()
134 {
135 CALL_INFO_TRACE;
136 CHKPV(context_);
137 context_->GetDelegateTasks().PostAsyncTask(std::bind(&TimerManager::OnProcessTimers, this));
138 }
139
OnProcessTimers()140 int32_t TimerManager::OnProcessTimers()
141 {
142 ProcessTimersInternal();
143 ArmTimer();
144 return RET_OK;
145 }
146
TakeNextTimerId()147 int32_t TimerManager::TakeNextTimerId()
148 {
149 uint64_t timerSlot = std::accumulate(timers_.cbegin(), timers_.cend(), uint64_t(0U),
150 [] (uint64_t s, const auto &timer) {
151 return (s |= (uint64_t(1U) << timer->id));
152 });
153 for (size_t i = 0; i < MAX_TIMER_COUNT; ++i) {
154 if ((timerSlot & (uint64_t(1U) << i)) == 0) {
155 return i;
156 }
157 }
158 return NONEXISTENT_ID;
159 }
160
AddTimerInternal(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)161 int32_t TimerManager::AddTimerInternal(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
162 {
163 CALL_DEBUG_ENTER;
164 if (intervalMs < MIN_INTERVAL) {
165 intervalMs = MIN_INTERVAL;
166 } else if (intervalMs > MAX_INTERVAL_MS) {
167 intervalMs = MAX_INTERVAL_MS;
168 }
169 CHKPR(callback, NONEXISTENT_ID);
170 int32_t timerId = TakeNextTimerId();
171 if (timerId < 0) {
172 return NONEXISTENT_ID;
173 }
174 auto timer = std::make_unique<TimerItem>();
175 timer->intervalMs = intervalMs;
176 timer->id = timerId;
177 timer->repeatCount = repeatCount;
178 timer->callbackCount = 0;
179 int64_t nowTime = GetMillisTime();
180 if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
181 FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
182 return NONEXISTENT_ID;
183 }
184 timer->callback = callback;
185 InsertTimerInternal(timer);
186 return timerId;
187 }
188
RemoveTimerInternal(int32_t timerId)189 int32_t TimerManager::RemoveTimerInternal(int32_t timerId)
190 {
191 for (auto tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
192 if ((*tIter)->id == timerId) {
193 timers_.erase(tIter);
194 return RET_OK;
195 }
196 }
197 return RET_ERR;
198 }
199
ResetTimerInternal(int32_t timerId)200 int32_t TimerManager::ResetTimerInternal(int32_t timerId)
201 {
202 for (auto tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
203 if ((*tIter)->id == timerId) {
204 auto timer = std::move(*tIter);
205 timers_.erase(tIter);
206 int64_t nowTime = GetMillisTime();
207 if (!AddInt64(nowTime, timer->intervalMs, timer->nextCallTime)) {
208 FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
209 return RET_ERR;
210 }
211 timer->callbackCount = 0;
212 InsertTimerInternal(timer);
213 return RET_OK;
214 }
215 }
216 return RET_ERR;
217 }
218
InsertTimerInternal(std::unique_ptr<TimerItem> & timer)219 void TimerManager::InsertTimerInternal(std::unique_ptr<TimerItem> &timer)
220 {
221 for (auto tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
222 if ((*tIter)->nextCallTime > timer->nextCallTime) {
223 timers_.insert(tIter, std::move(timer));
224 return;
225 }
226 }
227 timers_.push_back(std::move(timer));
228 }
229
CalcNextDelayInternal()230 int64_t TimerManager::CalcNextDelayInternal()
231 {
232 int64_t latency = MIN_DELAY;
233 if (!timers_.empty()) {
234 int64_t nowTime = GetMillisTime();
235 const auto& item = *timers_.begin();
236 if (nowTime >= item->nextCallTime) {
237 latency = 0;
238 } else {
239 latency = item->nextCallTime - nowTime;
240 }
241 }
242 return latency;
243 }
244
ProcessTimersInternal()245 void TimerManager::ProcessTimersInternal()
246 {
247 if (timers_.empty()) {
248 return;
249 }
250 int64_t nowTime = GetMillisTime();
251 for (;;) {
252 auto tIter = timers_.begin();
253 if (tIter == timers_.end()) {
254 break;
255 }
256 if ((*tIter)->nextCallTime > nowTime) {
257 break;
258 }
259 auto curTimer = std::move(*tIter);
260 timers_.erase(tIter);
261 ++curTimer->callbackCount;
262 if ((curTimer->repeatCount >= 1) && (curTimer->callbackCount >= curTimer->repeatCount)) {
263 curTimer->callback();
264 continue;
265 }
266 if (!AddInt64(curTimer->nextCallTime, curTimer->intervalMs, curTimer->nextCallTime)) {
267 FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
268 return;
269 }
270 auto callback = curTimer->callback;
271 InsertTimerInternal(curTimer);
272 callback();
273 }
274 }
275
ArmTimer()276 int32_t TimerManager::ArmTimer()
277 {
278 CALL_DEBUG_ENTER;
279 if (timerFd_ < 0) {
280 FI_HILOGE("TimerManager is uninitialized");
281 return RET_ERR;
282 }
283 struct itimerspec tspec {};
284 int64_t expire = CalcNextDelayInternal();
285 FI_HILOGI("Next expire %{public}" PRId64, expire);
286
287 if (expire == 0) {
288 expire = 1;
289 }
290 if (expire > 0) {
291 tspec.it_value.tv_sec = expire / TIME_CONVERSION;
292 tspec.it_value.tv_nsec = (expire % TIME_CONVERSION) * TIME_CONVERSION * TIME_CONVERSION;
293 }
294
295 if (timerfd_settime(timerFd_, 0, &tspec, NULL) != 0) {
296 FI_HILOGE("Timer: timerfd_settime error");
297 return RET_ERR;
298 }
299 return RET_OK;
300 }
301 } // namespace DeviceStatus
302 } // namespace Msdp
303 } // namespace OHOS
304