1 /*
2 * Copyright (c) 2025 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 "ark_native_timer.h"
17
18 #include "securec.h"
19
20 #include "utils/log.h"
21
TimerCallback(uv_timer_t * timerReq)22 void NativeTimerCallbackInfo::TimerCallback(uv_timer_t* timerReq)
23 {
24 NativeTimerCallbackInfo* info = reinterpret_cast<NativeTimerCallbackInfo*>(timerReq->data);
25 bool repeat = info->repeat_;
26 if (!repeat) {
27 info->timeoutExecuting_ = true;
28 }
29 info->cb_(info->data_);
30 if (!repeat) {
31 info->Erase();
32 delete info;
33 info = nullptr;
34 }
35 }
36
TimerTaskCallback(EcmaVM * vm,void * data,TimerCallbackFunc func,uint64_t timeout,bool repeat)37 void *NativeTimerCallbackInfo::TimerTaskCallback(EcmaVM* vm, void* data, TimerCallbackFunc func,
38 uint64_t timeout, bool repeat)
39 {
40 if (vm == nullptr || func == nullptr) {
41 HILOG_ERROR("TimerTaskCallback input is nullptr");
42 return nullptr;
43 }
44 ArkNativeEngine* engine = reinterpret_cast<ArkNativeEngine*>(JSNApi::GetEnv(vm));
45 NativeTimerCallbackInfo* info = new NativeTimerCallbackInfo(engine, func, data, repeat);
46 if (!info->Init(timeout)) {
47 HILOG_ERROR("NativeTimerCallbackInfo init failed");
48 delete info;
49 info = nullptr;
50 return nullptr;
51 }
52 info->Insert();
53 if (JSNApi::IsJSMainThreadOfEcmaVM(vm)) {
54 uv_loop_t* loop = reinterpret_cast<uv_loop_t*>(engine->GetUVLoop());
55 // main thread need send signal to trigger timer
56 uv_async_send(&loop->wq_async);
57 }
58 return reinterpret_cast<void*>(info);
59 }
60
CancelTimerCallback(void * timerCallbackInfo)61 void NativeTimerCallbackInfo::CancelTimerCallback(void* timerCallbackInfo)
62 {
63 if (timerCallbackInfo == nullptr) {
64 HILOG_ERROR("CancelTimerCallback info is nullptr");
65 return;
66 }
67 NativeTimerCallbackInfo* info = reinterpret_cast<NativeTimerCallbackInfo*>(timerCallbackInfo);
68 // Timeout will auto delete after executed, if timerCallback contains cancle task will be invalid.
69 // Timeout can be canceled by user only before executing.
70 if (info->timeoutExecuting_) {
71 return;
72 }
73 info->Erase();
74 delete info;
75 info = nullptr;
76 }
77
Insert()78 void NativeTimerCallbackInfo::Insert()
79 {
80 NativeTimerCallbackInfo* timerListHead = engine_->GetTimerListHead();
81 if (timerListHead) {
82 timerListHead->prev_ = this;
83 next_ = timerListHead;
84 }
85 timerListHead = this;
86 engine_->SetTimerListHead(timerListHead);
87 }
88
Erase()89 void NativeTimerCallbackInfo::Erase()
90 {
91 if (prev_) {
92 prev_->next_ = next_;
93 }
94 if (this == engine_->GetTimerListHead()) {
95 engine_->SetTimerListHead(next_);
96 }
97 if (next_) {
98 next_->prev_ = prev_;
99 }
100 next_ = nullptr;
101 prev_ = nullptr;
102 }
103
ReleaseTimerList(ArkNativeEngine * engine)104 void NativeTimerCallbackInfo::ReleaseTimerList(ArkNativeEngine* engine)
105 {
106 for (NativeTimerCallbackInfo* info = engine->GetTimerListHead();
107 info != nullptr; info = engine->GetTimerListHead()) {
108 info->Erase();
109 delete info;
110 info = nullptr;
111 }
112 }
113
Init(uint64_t timeout)114 bool NativeTimerCallbackInfo::Init(uint64_t timeout)
115 {
116 if (!engine_) {
117 HILOG_ERROR("NativeTimerCallbackInfo engine_ is nullptr");
118 return false;
119 }
120 uv_loop_t* loop = reinterpret_cast<uv_loop_t*>(engine_->GetUVLoop());
121 if (!loop) {
122 HILOG_ERROR("NativeTimerCallbackInfo loop is nullptr");
123 return false;
124 }
125 timerReq_ = new uv_timer_t();
126 if (!timerReq_) {
127 HILOG_ERROR("NativeTimerCallbackInfo timerReq_ is nullptr");
128 return false;
129 }
130 timerReq_->data = this;
131 if (uv_timer_init(loop, timerReq_) != EOK) {
132 HILOG_ERROR("NativeTimerCallbackInfo uv_timer_init failed");
133 delete timerReq_;
134 timerReq_ = nullptr;
135 return false;
136 }
137 if (uv_timer_start(timerReq_, TimerCallback, timeout, timeout) != EOK) {
138 HILOG_ERROR("NativeTimerCallbackInfo uv_timer_start failed");
139 uv_close(reinterpret_cast<uv_handle_t*>(timerReq_), nullptr);
140 delete timerReq_;
141 timerReq_ = nullptr;
142 return false;
143 }
144 return true;
145 }