1 /*
2 * Copyright (c) 2021 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 #include "graphic_timer.h"
16
17 #include "gfx_utils/graphic_log.h"
18 #ifdef _WIN32
19 #include "windows.h"
20 #else
21 #include <cerrno>
22 #include <csignal>
23 #include <cstring>
24 #include "securec.h"
25 #endif
26
27 namespace {
28 #ifdef _WIN32
29 constexpr int32_t HUNDRED_NS_PER_MS = 10000;
30 #elif defined(__LITEOS_M__)
31 #else
32 constexpr int16_t MS_PER_SECOND = 1000;
33 constexpr int32_t NS_PER_MS = 1000000;
34 #endif
35 } // namespace
36
37 namespace OHOS {
SetPeriod(int32_t periodMs)38 bool GraphicTimer::SetPeriod(int32_t periodMs)
39 {
40 if (periodMs_ < 0) {
41 GRAPHIC_LOGE("Timer set period failed, timer should be created first.");
42 return false;
43 }
44
45 if ((periodMs > MAX_PERIOD_MS) || (periodMs <= 0)) {
46 GRAPHIC_LOGE("Timer set period failed, period should be within (0, %d].(period=%d)", MAX_PERIOD_MS, periodMs);
47 return false;
48 }
49
50 periodMs_ = periodMs;
51 return true;
52 }
53
54 #ifdef _WIN32
TimerCallback(LPVOID lpArg,DWORD dwTimerLowValue,DWORD dwTimerHighValue)55 static void CALLBACK TimerCallback(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
56 {
57 UNREFERENCED_PARAMETER(dwTimerLowValue);
58 UNREFERENCED_PARAMETER(dwTimerHighValue);
59
60 GraphicTimer* timer = reinterpret_cast<GraphicTimer*>(lpArg);
61 if (timer != nullptr) {
62 (void)timer->Callback();
63 }
64 }
65
WinAsyncThread(LPVOID lpParam)66 static DWORD WINAPI WinAsyncThread(LPVOID lpParam)
67 {
68 GraphicTimer* timer = reinterpret_cast<GraphicTimer*>(lpParam);
69 LARGE_INTEGER liDueTime;
70 liDueTime.QuadPart = -(timer->GetPeriod() * HUNDRED_NS_PER_MS);
71
72 LONG period = (timer->IsPeriodic() ? timer->GetPeriod() : 0);
73 if (!SetWaitableTimer(timer->GetNativeTimer(), &liDueTime, period, TimerCallback, timer, FALSE)) {
74 GRAPHIC_LOGE("Timer start failed.(Error=%d)", GetLastError());
75 return 1;
76 }
77 SleepEx(INFINITE, TRUE);
78 return 0;
79 }
80
GraphicTimer(int32_t periodMs,GraphicTimerCb cb,void * arg,bool isPeriodic)81 GraphicTimer::GraphicTimer(int32_t periodMs, GraphicTimerCb cb, void* arg, bool isPeriodic)
82 : cb_(cb), arg_(arg), isPeriodic_(isPeriodic)
83 {
84 if ((periodMs > MAX_PERIOD_MS) || (periodMs <= 0)) {
85 GRAPHIC_LOGE("Timer create failed, period should be within (0, %d].(period=%d)", MAX_PERIOD_MS, periodMs);
86 return;
87 }
88
89 timer_ = CreateWaitableTimer(nullptr, TRUE, nullptr);
90 if (timer_ == nullptr) {
91 GRAPHIC_LOGE("Timer create failed.(err=%s)", strerror(errno));
92 return;
93 }
94 periodMs_ = periodMs;
95 }
96
~GraphicTimer()97 GraphicTimer::~GraphicTimer()
98 {
99 if (timer_ != nullptr) {
100 CloseHandle(timer_);
101 }
102 }
103
Start()104 bool GraphicTimer::Start()
105 {
106 if (timer_ == nullptr) {
107 GRAPHIC_LOGE("Timer start failed, timer should be created first.");
108 return false;
109 }
110
111 DWORD dwThreadId;
112 HANDLE hThread = CreateThread(NULL, // default security attributes
113 0, // use default stack size
114 WinAsyncThread, // thread function name
115 this, // argument to thread function
116 0, // use default creation flags
117 &dwThreadId); // returns the thread identifier
118 if (hThread == nullptr) {
119 GRAPHIC_LOGE("Timer start failed.(Error=%d)", GetLastError());
120 return false;
121 }
122 return true;
123 }
124
Stop()125 void GraphicTimer::Stop()
126 {
127 if (timer_ == nullptr) {
128 GRAPHIC_LOGE("Timer stop failed, timer should be created first.");
129 return;
130 }
131 if (CancelWaitableTimer(timer_) == 0) {
132 GRAPHIC_LOGE("Timer stop failed.(Error=%d)", GetLastError());
133 return;
134 }
135 }
136
137 #elif defined(__LITEOS_M__)
TimerCallback(void * args)138 static void TimerCallback(void* args)
139 {
140 GraphicTimer* timer = reinterpret_cast<GraphicTimer*>(args);
141 if (timer != nullptr) {
142 timer->Callback();
143 }
144 }
145
GraphicTimer(int32_t periodMs,GraphicTimerCb cb,void * arg,bool isPeriodic)146 GraphicTimer::GraphicTimer(int32_t periodMs, GraphicTimerCb cb, void* arg, bool isPeriodic)
147 : cb_(cb), arg_(arg), isPeriodic_(isPeriodic)
148 {
149 if ((periodMs > MAX_PERIOD_MS) || (periodMs <= 0)) {
150 GRAPHIC_LOGE("Timer create failed, period should be within (0, %d].(period=%d)", MAX_PERIOD_MS, periodMs);
151 return;
152 }
153
154 osTimerType_t timerType = isPeriodic ? osTimerPeriodic : osTimerOnce;
155 timer_ = osTimerNew(reinterpret_cast<osTimerFunc_t>(TimerCallback), timerType, this, nullptr);
156 if (timer_ == nullptr) {
157 GRAPHIC_LOGE("Timer create failed");
158 return;
159 }
160 periodMs_ = periodMs;
161 }
162
~GraphicTimer()163 GraphicTimer::~GraphicTimer()
164 {
165 if (periodMs_ >= 0) {
166 osStatus_t ret = osTimerDelete(timer_);
167 if (ret != osStatus_t::osOK) {
168 GRAPHIC_LOGE("Timer delete failed.");
169 }
170 }
171 }
172
Start()173 bool GraphicTimer::Start()
174 {
175 if (periodMs_ < 0) {
176 GRAPHIC_LOGE("Timer start failed, timer should be created first.");
177 return false;
178 }
179 osStatus_t ret = osTimerStart(timer_, periodMs_);
180 if (ret != osStatus_t::osOK) {
181 GRAPHIC_LOGE("Timer start failed.");
182 return false;
183 }
184 return true;
185 }
186
Stop()187 void GraphicTimer::Stop()
188 {
189 if (periodMs_ < 0) {
190 return;
191 }
192 osStatus_t ret = osTimerStop(timer_);
193 bool isRunning = osTimerIsRunning(timer_);
194 if ((ret != osStatus_t::osOK) || (isRunning)) {
195 GRAPHIC_LOGE("Timer stop failed.");
196 return;
197 }
198 }
199
200 #else
TimerCallback(union sigval v)201 static void TimerCallback(union sigval v)
202 {
203 GraphicTimer* timer = reinterpret_cast<GraphicTimer*>(v.sival_ptr);
204 if (timer != nullptr) {
205 timer->Callback();
206 }
207 }
208
GraphicTimer(int32_t periodMs,GraphicTimerCb cb,void * arg,bool isPeriodic)209 GraphicTimer::GraphicTimer(int32_t periodMs, GraphicTimerCb cb, void* arg, bool isPeriodic)
210 : cb_(cb), arg_(arg), isPeriodic_(isPeriodic)
211 {
212 if ((periodMs > MAX_PERIOD_MS) || (periodMs <= 0)) {
213 GRAPHIC_LOGE("Timer create failed, period should be within (0, %d].(period=%d)", MAX_PERIOD_MS, periodMs);
214 return;
215 }
216
217 struct sigevent sev;
218 (void)memset_s(&sev, sizeof(sev), 0, sizeof(sev));
219 sev.sigev_notify = SIGEV_THREAD;
220 sev.sigev_notify_function = TimerCallback;
221 sev.sigev_value.sival_ptr = this;
222
223 if (timer_create(CLOCK_REALTIME, &sev, &timer_) == -1) {
224 GRAPHIC_LOGE("Timer create failed.(err=%s)", strerror(errno));
225 return;
226 }
227 periodMs_ = periodMs;
228 }
229
~GraphicTimer()230 GraphicTimer::~GraphicTimer()
231 {
232 if (periodMs_ >= 0) {
233 if (timer_delete(timer_) == -1) {
234 GRAPHIC_LOGE("Timer delete failed.(err=%s)", strerror(errno));
235 }
236 }
237 }
238
Start()239 bool GraphicTimer::Start()
240 {
241 if (periodMs_ < 0) {
242 GRAPHIC_LOGE("Timer start failed, timer should be created first.");
243 return false;
244 }
245
246 struct itimerspec its;
247 its.it_value.tv_nsec = (periodMs_ % MS_PER_SECOND) * NS_PER_MS;
248 its.it_value.tv_sec = periodMs_ / MS_PER_SECOND;
249 if (isPeriodic_) {
250 its.it_interval.tv_nsec = its.it_value.tv_nsec;
251 its.it_interval.tv_sec = its.it_value.tv_sec;
252 } else {
253 its.it_interval.tv_nsec = 0;
254 its.it_interval.tv_sec = 0;
255 }
256 if (timer_settime(timer_, 0, &its, nullptr) == -1) {
257 GRAPHIC_LOGE("Timer start failed.(timerid=%d, err=%s)", timer_, strerror(errno));
258 return false;
259 }
260 return true;
261 }
262
Stop()263 void GraphicTimer::Stop()
264 {
265 if (periodMs_ < 0) {
266 return;
267 }
268 struct itimerspec its;
269 its.it_value.tv_nsec = 0;
270 its.it_value.tv_sec = 0;
271 if (timer_settime(timer_, 0, &its, nullptr) == -1) {
272 GRAPHIC_LOGE("Timer stop failed.(timerid=%d, err=%s)", timer_, strerror(errno));
273 return;
274 }
275 }
276 #endif
277 }; // namespace OHOS
278