• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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 MIN_INTERVAL { 50 };
33 constexpr int32_t MAX_INTERVAL_MS { 10000 };
34 constexpr int32_t NONEXISTENT_ID { -1 };
35 constexpr int32_t TIME_CONVERSION { 1000 };
36 constexpr size_t MAX_TIMER_COUNT { 64 };
37 } // namespace
38 
Init(IContext * context)39 int32_t TimerManager::Init(IContext *context)
40 {
41     CHKPR(context, RET_ERR);
42     return context->GetDelegateTasks().PostSyncTask(std::bind(&TimerManager::OnInit, this, context));
43 }
44 
OnInit(IContext * context)45 int32_t TimerManager::OnInit(IContext *context)
46 {
47     CHKPR(context, RET_ERR);
48     context_ = context;
49 
50     timerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
51     if (timerFd_ < 0) {
52         FI_HILOGE("timer: timerfd_create failed");
53         return RET_ERR;
54     }
55     return RET_OK;
56 }
57 
AddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)58 int32_t TimerManager::AddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
59 {
60     CALL_INFO_TRACE;
61     CHKPR(context_, RET_ERR);
62     return context_->GetDelegateTasks().PostSyncTask(
63         std::bind(&TimerManager::OnAddTimer, this, intervalMs, repeatCount, callback));
64 }
65 
OnAddTimer(int32_t intervalMs,int32_t repeatCount,std::function<void ()> callback)66 int32_t TimerManager::OnAddTimer(int32_t intervalMs, int32_t repeatCount, std::function<void()> callback)
67 {
68     int32_t timerId = AddTimerInternal(intervalMs, repeatCount, callback);
69     ArmTimer();
70     return timerId;
71 }
72 
RemoveTimer(int32_t timerId)73 int32_t TimerManager::RemoveTimer(int32_t timerId)
74 {
75     CALL_INFO_TRACE;
76     CHKPR(context_, RET_ERR);
77     return context_->GetDelegateTasks().PostSyncTask(std::bind(&TimerManager::OnRemoveTimer, this, timerId));
78 }
79 
OnRemoveTimer(int32_t timerId)80 int32_t TimerManager::OnRemoveTimer(int32_t timerId)
81 {
82     int32_t ret = RemoveTimerInternal(timerId);
83     if (ret == RET_OK) {
84         ArmTimer();
85     }
86     return ret;
87 }
88 
ResetTimer(int32_t timerId)89 int32_t TimerManager::ResetTimer(int32_t timerId)
90 {
91     CALL_INFO_TRACE;
92     CHKPR(context_, RET_ERR);
93     return context_->GetDelegateTasks().PostSyncTask(std::bind(&TimerManager::OnResetTimer, this, timerId));
94 }
95 
OnResetTimer(int32_t timerId)96 int32_t TimerManager::OnResetTimer(int32_t timerId)
97 {
98     int32_t ret = ResetTimerInternal(timerId);
99     ArmTimer();
100     return ret;
101 }
102 
IsExist(int32_t timerId) const103 bool TimerManager::IsExist(int32_t timerId) const
104 {
105     CHKPR(context_, false);
106     std::packaged_task<bool(int32_t)> task { std::bind(&TimerManager::OnIsExist, this, std::placeholders::_1) };
107     auto fu = task.get_future();
108 
109     int32_t ret = context_->GetDelegateTasks().PostSyncTask(
110         std::bind(&TimerManager::RunIsExist, this, std::ref(task), timerId));
111     if (ret != RET_OK) {
112         FI_HILOGE("Post task failed");
113         return false;
114     }
115     return fu.get();
116 }
117 
OnIsExist(int32_t timerId) const118 bool TimerManager::OnIsExist(int32_t timerId) const
119 {
120     for (auto tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
121         if ((*tIter)->id == timerId) {
122             return true;
123         }
124     }
125     return false;
126 }
127 
RunIsExist(std::packaged_task<bool (int32_t)> & task,int32_t timerId) const128 int32_t TimerManager::RunIsExist(std::packaged_task<bool(int32_t)> &task, int32_t timerId) const
129 {
130     task(timerId);
131     return RET_OK;
132 }
133 
ProcessTimers()134 void TimerManager::ProcessTimers()
135 {
136     CALL_INFO_TRACE;
137     CHKPV(context_);
138     context_->GetDelegateTasks().PostAsyncTask(std::bind(&TimerManager::OnProcessTimers, this));
139 }
140 
OnProcessTimers()141 int32_t TimerManager::OnProcessTimers()
142 {
143     ProcessTimersInternal();
144     ArmTimer();
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 i = 0; i < MAX_TIMER_COUNT; ++i) {
155         if ((timerSlot & (uint64_t(1U) << i)) == 0) {
156             return i;
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_INFO_TRACE;
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 timerId = TakeNextTimerId();
174     if (timerId < 0) {
175         return NONEXISTENT_ID;
176     }
177     auto timer = std::make_unique<TimerItem>();
178     timer->id = timerId;
179     timer->intervalMs = intervalMs;
180     timer->repeatCount = repeatCount;
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 timerId;
190 }
191 
RemoveTimerInternal(int32_t timerId)192 int32_t TimerManager::RemoveTimerInternal(int32_t timerId)
193 {
194     for (auto tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
195         if ((*tIter)->id == timerId) {
196             timers_.erase(tIter);
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 tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
206         if ((*tIter)->id == timerId) {
207             auto timer = std::move(*tIter);
208             timers_.erase(tIter);
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 tIter = timers_.begin(); tIter != timers_.end(); ++tIter) {
225         if ((*tIter)->nextCallTime > timer->nextCallTime) {
226             timers_.insert(tIter, 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 delay = MIN_DELAY;
236     if (!timers_.empty()) {
237         int64_t nowTime = GetMillisTime();
238         const auto& item = *timers_.begin();
239         if (nowTime >= item->nextCallTime) {
240             delay = 0;
241         } else {
242             delay = item->nextCallTime - nowTime;
243         }
244     }
245     return delay;
246 }
247 
ProcessTimersInternal()248 void TimerManager::ProcessTimersInternal()
249 {
250     if (timers_.empty()) {
251         return;
252     }
253     int64_t nowTime = GetMillisTime();
254     for (;;) {
255         auto tIter = timers_.begin();
256         if (tIter == timers_.end()) {
257             break;
258         }
259         if ((*tIter)->nextCallTime > nowTime) {
260             break;
261         }
262         auto curTimer = std::move(*tIter);
263         timers_.erase(tIter);
264         ++curTimer->callbackCount;
265         if ((curTimer->repeatCount >= 1) && (curTimer->callbackCount >= curTimer->repeatCount)) {
266             curTimer->callback();
267             continue;
268         }
269         if (!AddInt64(curTimer->nextCallTime, curTimer->intervalMs, curTimer->nextCallTime)) {
270             FI_HILOGE("The addition of nextCallTime in TimerItem overflows");
271             return;
272         }
273         auto callback = curTimer->callback;
274         InsertTimerInternal(curTimer);
275         callback();
276     }
277 }
278 
ArmTimer()279 int32_t TimerManager::ArmTimer()
280 {
281     CALL_INFO_TRACE;
282     if (timerFd_ < 0) {
283         FI_HILOGE("TimerManager is uninitialized");
284         return RET_ERR;
285     }
286     struct itimerspec tspec {};
287     int64_t expire = CalcNextDelayInternal();
288     FI_HILOGI("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: timerfd_settime error");
300         return RET_ERR;
301     }
302     return RET_OK;
303 }
304 } // namespace DeviceStatus
305 } // namespace Msdp
306 } // namespace OHOS
307