• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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.h"
17 
18 #include "utils/log.h"
19 
20 namespace Commonlibrary::Concurrent::Common::Plugin {
21 uint32_t Timer::timeCallbackId = 0;
22 std::map<uint32_t, TimerCallbackInfo*> Timer::timerTable;
23 std::mutex Timer::timeLock;
24 
~TimerCallbackInfo()25 TimerCallbackInfo::~TimerCallbackInfo()
26 {
27     Helper::NapiHelper::DeleteReference(env_, callback_);
28     for (size_t idx = 0; idx < argc_; idx++) {
29         Helper::NapiHelper::DeleteReference(env_, argv_[idx]);
30     }
31     Helper::CloseHelp::DeletePointer(argv_, true);
32 
33     uv_timer_stop(timeReq_);
34     uv_close(reinterpret_cast<uv_handle_t*>(timeReq_), [](uv_handle_t* handle) {
35         if (handle != nullptr) {
36             delete (uv_timer_t*)handle;
37             handle = nullptr;
38         }
39     });
40 }
41 
RegisterTime(napi_env env)42 bool Timer::RegisterTime(napi_env env)
43 {
44     if (env == nullptr) {
45         return false;
46     }
47     napi_property_descriptor properties[] = {
48         DECLARE_NAPI_FUNCTION("setTimeout", SetTimeout),
49         DECLARE_NAPI_FUNCTION("setInterval", SetInterval),
50         DECLARE_NAPI_FUNCTION("clearTimeout", ClearTimer),
51         DECLARE_NAPI_FUNCTION("clearInterval", ClearTimer)
52     };
53     napi_value globalObj = Helper::NapiHelper::GetGlobalObject(env);
54     napi_status status = napi_define_properties(env, globalObj, sizeof(properties) / sizeof(properties[0]), properties);
55     return status == napi_ok;
56 }
57 
SetTimeout(napi_env env,napi_callback_info cbinfo)58 napi_value Timer::SetTimeout(napi_env env, napi_callback_info cbinfo)
59 {
60     return Timer::SetTimeoutInner(env, cbinfo, false);
61 }
62 
SetInterval(napi_env env,napi_callback_info cbinfo)63 napi_value Timer::SetInterval(napi_env env, napi_callback_info cbinfo)
64 {
65     return Timer::SetTimeoutInner(env, cbinfo, true);
66 }
67 
ClearTimer(napi_env env,napi_callback_info cbinfo)68 napi_value Timer::ClearTimer(napi_env env, napi_callback_info cbinfo)
69 {
70     // 1. check args
71     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, cbinfo);
72     if (argc < 1) {
73         HILOG_WARN("first arg should be number");
74         return nullptr;
75     }
76     napi_value* argv = new napi_value[argc];
77     Helper::ObjectScope<napi_value> scope(argv, true);
78     napi_value thisVar = nullptr;
79     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
80 
81     uint32_t tId;
82     napi_status status = napi_get_value_uint32(env, argv[0], &tId);
83     if (status != napi_ok) {
84         HILOG_WARN("handler should be number");
85         return nullptr;
86     }
87     TimerCallbackInfo* callbackInfo = nullptr;
88     {
89         std::lock_guard<std::mutex> lock(timeLock);
90         auto iter = timerTable.find(tId);
91         if (iter == timerTable.end()) {
92             HILOG_INFO("handler not in table");
93             return nullptr;
94         }
95         callbackInfo = iter->second;
96         timerTable.erase(tId);
97     }
98     Helper::CloseHelp::DeletePointer(callbackInfo, false);
99     return Helper::NapiHelper::GetUndefinedValue(env);
100 }
101 
TimerCallback(uv_timer_t * handle)102 void Timer::TimerCallback(uv_timer_t* handle)
103 {
104     TimerCallbackInfo* callbackInfo = static_cast<TimerCallbackInfo*>(handle->data);
105     if (callbackInfo == nullptr) {
106         return;
107     }
108     napi_value callback = Helper::NapiHelper::GetReferenceValue(callbackInfo->env_, callbackInfo->callback_);
109     napi_value undefinedValue = Helper::NapiHelper::GetUndefinedValue(callbackInfo->env_);
110     napi_value callbackResult = nullptr;
111     napi_value* callbackArgv = new napi_value[callbackInfo->argc_];
112     Helper::ObjectScope<napi_value> scope(callbackArgv, true);
113     for (size_t idx = 0; idx < callbackInfo->argc_; idx++) {
114         callbackArgv[idx] = Helper::NapiHelper::GetReferenceValue(callbackInfo->env_, callbackInfo->argv_[idx]);
115     }
116     napi_call_function(callbackInfo->env_, undefinedValue, callback,
117                        callbackInfo->argc_, callbackArgv, &callbackResult);
118     if (callbackResult == nullptr) {
119         HILOG_WARN("call callback error");
120         return;
121     }
122     if (!callbackInfo->repeat_) {
123         {
124             std::lock_guard<std::mutex> lock(timeLock);
125             if (timerTable.find(callbackInfo->tId_) == timerTable.end()) {
126                 HILOG_ERROR("erase inexistent timerCallbackInfo");
127             } else {
128                 timerTable.erase(callbackInfo->tId_);
129             }
130         }
131         Helper::CloseHelp::DeletePointer(callbackInfo, false);
132     } else {
133         uv_timer_again(handle);
134     }
135 }
136 
SetTimeoutInner(napi_env env,napi_callback_info cbinfo,bool repeat)137 napi_value Timer::SetTimeoutInner(napi_env env, napi_callback_info cbinfo, bool repeat)
138 {
139     // 1. check args
140     size_t argc = Helper::NapiHelper::GetCallbackInfoArgc(env, cbinfo);
141     if (argc < 1) {
142         napi_throw_error(env, nullptr, "callback must be a function. received undefined");
143         return nullptr;
144     }
145     napi_value* argv = new napi_value[argc];
146     Helper::ObjectScope<napi_value> scope(argv, true);
147     napi_value thisVar = nullptr;
148     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
149     if (!Helper::NapiHelper::IsCallable(env, argv[0])) {
150         napi_throw_error(env, nullptr, "callback must be a function.");
151         return nullptr;
152     }
153     int32_t timeout = 0;
154     if (argc > 1) {
155         napi_status status = napi_get_value_int32(env, argv[1], &timeout);
156         if (status != napi_ok) {
157             HILOG_WARN("timeout should be number");
158             timeout = 0;
159         }
160     }
161     if (timeout < 0) {
162         HILOG_WARN("worker:: timeout < 0 is unreasonable");
163     }
164     // 2. get callback args
165     size_t callbackArgc = argc >= 2 ? argc - 2 : 0; // 2 include callback and timeout
166     napi_ref* callbackArgv = nullptr;
167     if (callbackArgc > 0) {
168         callbackArgv = new napi_ref[callbackArgc];
169         for (size_t idx = 0; idx < callbackArgc; idx++) {
170             callbackArgv[idx] =
171                 Helper::NapiHelper::CreateReference(env, argv[idx + 2], 1); // 2 include callback and timeout
172         }
173     }
174 
175     // 3. generate time callback id
176     // 4. generate time callback info
177     // 5. push callback info into timerTable
178     uint32_t tId = 0;
179     TimerCallbackInfo* callbackInfo = nullptr;
180     {
181         std::lock_guard<std::mutex> lock(timeLock);
182         tId = timeCallbackId++;
183         napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, argv[0], 1);
184         callbackInfo = new TimerCallbackInfo(env, tId, timeout, callbackRef, repeat, callbackArgc, callbackArgv);
185         if (timerTable.find(tId) != timerTable.end()) {
186             HILOG_ERROR("timerTable occurs error");
187         } else {
188             timerTable[tId] = callbackInfo;
189         }
190     }
191 
192     // 6. start timer
193     uv_timer_start(callbackInfo->timeReq_, TimerCallback, timeout >= 0 ? timeout : 1, timeout > 0 ? timeout : 1);
194     return Helper::NapiHelper::CreateUint32(env, tId);
195 }
196 
ClearEnvironmentTimer(napi_env env)197 void Timer::ClearEnvironmentTimer(napi_env env)
198 {
199     std::lock_guard<std::mutex> lock(timeLock);
200     auto iter = timerTable.begin();
201     while (iter != timerTable.end()) {
202         TimerCallbackInfo* callbackInfo = iter->second;
203         if (callbackInfo->env_ == env) {
204             iter = timerTable.erase(iter);
205             Helper::CloseHelp::DeletePointer(callbackInfo, false);
206         } else {
207             iter++;
208         }
209     }
210 }
211 } // namespace Commonlibrary::Concurrent::Common::Plugin
212