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