• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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