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 "task.h"
17
18 #include "async_runner_manager.h"
19 #include "helper/concurrent_helper.h"
20 #include "helper/hitrace_helper.h"
21 #include "sequence_runner_manager.h"
22 #include "taskpool.h"
23 #include "worker.h"
24
25 namespace Commonlibrary::Concurrent::TaskPoolModule {
26 static constexpr char ONRECEIVEDATA_STR[] = "onReceiveData";
27 static constexpr char SETTRANSFERLIST_STR[] = "setTransferList";
28 static constexpr char SET_CLONE_LIST_STR[] = "setCloneList";
29 static constexpr char ONENQUEUED_STR[] = "onEnqueued";
30 static constexpr char ONSTARTEXECUTION_STR[] = "onStartExecution";
31 static constexpr char ONEXECUTIONFAILED_STR[] = "onExecutionFailed";
32 static constexpr char ONEXECUTIONSUCCEEDED_STR[] = "onExecutionSucceeded";
33 static constexpr char ISDONE_STR[] = "isDone";
34 static constexpr char ON_RESULT_STR[] = "TaskPoolOnResultTask";
35
36 const std::unordered_map<Priority, napi_event_priority> g_napiPriorityMap = {
37 {Priority::IDLE, napi_eprio_idle},
38 {Priority::LOW, napi_eprio_low},
39 {Priority::MEDIUM, napi_eprio_high},
40 {Priority::HIGH, napi_eprio_immediate},
41 };
42
43 using namespace Commonlibrary::Concurrent::Common::Helper;
44
TaskConstructor(napi_env env,napi_callback_info cbinfo)45 napi_value Task::TaskConstructor(napi_env env, napi_callback_info cbinfo)
46 {
47 // check argv count
48 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
49 std::string errMessage = "";
50 if (argc < 1) {
51 errMessage = "taskpool:: create task need more than one param";
52 HILOG_ERROR("%{public}s", errMessage.c_str());
53 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
54 return nullptr;
55 }
56 napi_value* args = new napi_value[argc];
57 ObjectScope<napi_value> scope(args, true);
58 napi_value thisVar = nullptr;
59 napi_value func = nullptr;
60 napi_value name = nullptr;
61 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
62 // if the first is task name, the second might be func
63 if (argc > 1 && NapiHelper::IsString(env, args[0])) {
64 name = args[0];
65 func = args[1];
66 args += 2; // 2: name and func
67 argc -= 2; // 2: name and func
68 } else {
69 func = args[0];
70 args += 1; // 1: func
71 argc -= 1; // 1: func
72 }
73 if (!NapiHelper::IsFunction(env, func)) {
74 errMessage = "taskpool:: the first or second param of task must be function";
75 HILOG_ERROR("%{public}s", errMessage.c_str());
76 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
77 "the type of the first or second param of task must be function.");
78 return nullptr;
79 }
80
81 Task* task = GenerateTask(env, thisVar, func, name, args, argc);
82 napi_status status = napi_wrap(env, thisVar, task, TaskDestructor, nullptr, nullptr);
83 if (status != napi_ok) {
84 HILOG_ERROR("taskpool::TaskConstructor napi_wrap return value is %{public}d", status);
85 TaskManager::GetInstance().RemoveTask(task->taskId_);
86 delete task;
87 task = nullptr;
88 return nullptr;
89 }
90 napi_create_reference(env, thisVar, 0, &task->taskRef_);
91 if (!task->IsMainThreadTask()) {
92 napi_add_env_cleanup_hook(env, Task::CleanupHookFunc, task);
93 }
94 return thisVar;
95 }
96
LongTaskConstructor(napi_env env,napi_callback_info cbinfo)97 napi_value Task::LongTaskConstructor(napi_env env, napi_callback_info cbinfo)
98 {
99 auto thisVar = TaskConstructor(env, cbinfo);
100 if (thisVar == nullptr) {
101 return nullptr;
102 }
103 Task* task;
104 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
105 task->isLongTask_ = true;
106 return thisVar;
107 }
108
TaskDestructor(napi_env env,void * data,void * hint)109 void Task::TaskDestructor(napi_env env, void* data, [[maybe_unused]] void* hint)
110 {
111 Task* task = static_cast<Task*>(data);
112 HILOG_DEBUG("taskpool:: taskId:%{public}s TaskDestructor", std::to_string(task->taskId_).c_str());
113 if (!task->IsMainThreadTask()) {
114 napi_remove_env_cleanup_hook(env, Task::CleanupHookFunc, task);
115 }
116 // for performance, do not lock first
117 if (task->IsMainThreadTask() || task->lifecycleCount_ == 0) {
118 TaskManager::GetInstance().ReleaseTaskData(env, task);
119 napi_delete_reference(env, task->taskRef_);
120 delete task;
121 return;
122 }
123 bool shouldDelete = false;
124 {
125 std::lock_guard<std::recursive_mutex> lock(task->taskMutex_);
126 task->SetValid(false);
127 if (task->lifecycleCount_ == 0) {
128 shouldDelete = true;
129 }
130 TaskManager::GetInstance().ReleaseTaskData(env, task, shouldDelete);
131 napi_delete_reference(env, task->taskRef_);
132 }
133 if (shouldDelete) {
134 delete task;
135 }
136 }
137
CleanupHookFunc(void * arg)138 void Task::CleanupHookFunc(void* arg)
139 {
140 if (arg == nullptr) {
141 HILOG_ERROR("taskpool:: cleanupHook arg is nullptr");
142 return;
143 }
144 Task* task = static_cast<Task*>(arg);
145 {
146 std::lock_guard<std::recursive_mutex> lock(task->taskMutex_);
147 ConcurrentHelper::UvHandleClose(task->onStartCancelSignal_);
148 ConcurrentHelper::UvHandleClose(task->onStartExecutionSignal_);
149 ConcurrentHelper::UvHandleClose(task->onStartDiscardSignal_);
150 if (task->IsFunctionTask()) {
151 task->SetValid(false);
152 }
153 }
154 if (task->IsAsyncRunnerTask()) {
155 AsyncRunnerManager::GetInstance().RemoveWaitingTask(task);
156 }
157 if (task->IsSeqRunnerTask()) {
158 SequenceRunnerManager::GetInstance().RemoveWaitingTask(task);
159 }
160 }
161
Cancel(const uv_async_t * req)162 void Task::Cancel(const uv_async_t* req)
163 {
164 auto message = static_cast<CancelTaskMessage*>(req->data);
165 if (message == nullptr) {
166 HILOG_DEBUG("taskpool:: cancel message is nullptr");
167 return;
168 }
169 Task* task = TaskManager::GetInstance().GetTask(message->taskId);
170 if (task == nullptr) {
171 HILOG_DEBUG("taskpool:: cancel task is nullptr");
172 CloseHelp::DeletePointer(message, false);
173 return;
174 }
175 napi_status status = napi_ok;
176 HandleScope scope(task->env_, status);
177 if (status != napi_ok) {
178 HILOG_ERROR("taskpool:: napi_open_handle_scope failed");
179 CloseHelp::DeletePointer(message, false);
180 return;
181 }
182 task->CancelInner(message->state);
183 CloseHelp::DeletePointer(message, false);
184 }
185
GenerateTask(napi_env env,napi_value napiTask,napi_value func,napi_value name,napi_value * args,size_t argc)186 Task* Task::GenerateTask(napi_env env, napi_value napiTask, napi_value func,
187 napi_value name, napi_value* args, size_t argc)
188 {
189 HILOG_DEBUG("taskpool:: task GenerateTask");
190 napi_value argsArray = NapiHelper::CreateArrayWithLength(env, argc);
191 for (size_t i = 0; i < argc; i++) {
192 napi_set_element(env, argsArray, i, args[i]);
193 }
194 if (name == nullptr) {
195 name = NapiHelper::GetNameProperty(env, func, NAME);
196 }
197 char* nameStr = NapiHelper::GetChars(env, name);
198 Task* task = new Task(env, TaskType::TASK, nameStr);
199 delete[] nameStr;
200 TaskManager::GetInstance().StoreTask(task);
201 task->InitHandle(env);
202
203 napi_value taskId = NapiHelper::CreateUint32(env, task->taskId_);
204 napi_set_named_property(env, napiTask, FUNCTION_STR, func);
205 napi_set_named_property(env, napiTask, TASKID_STR, taskId);
206 napi_set_named_property(env, napiTask, ARGUMENTS_STR, argsArray);
207 napi_property_descriptor properties[] = {
208 DECLARE_NAPI_FUNCTION(SETTRANSFERLIST_STR, SetTransferList),
209 DECLARE_NAPI_FUNCTION(SET_CLONE_LIST_STR, SetCloneList),
210 DECLARE_NAPI_FUNCTION(ONRECEIVEDATA_STR, OnReceiveData),
211 DECLARE_NAPI_FUNCTION(ADD_DEPENDENCY_STR, AddDependency),
212 DECLARE_NAPI_FUNCTION(REMOVE_DEPENDENCY_STR, RemoveDependency),
213 DECLARE_NAPI_FUNCTION(ONENQUEUED_STR, OnEnqueued),
214 DECLARE_NAPI_FUNCTION(ONSTARTEXECUTION_STR, OnStartExecution),
215 DECLARE_NAPI_FUNCTION(ONEXECUTIONFAILED_STR, OnExecutionFailed),
216 DECLARE_NAPI_FUNCTION(ONEXECUTIONSUCCEEDED_STR, OnExecutionSucceeded),
217 DECLARE_NAPI_FUNCTION(ISDONE_STR, IsDone),
218 DECLARE_NAPI_GETTER(TASK_TOTAL_TIME, GetTotalDuration),
219 DECLARE_NAPI_GETTER(TASK_CPU_TIME, GetCPUDuration),
220 DECLARE_NAPI_GETTER(TASK_IO_TIME, GetIODuration),
221 DECLARE_NAPI_GETTER(NAME, GetName),
222 DECLARE_NAPI_GETTER(TASKID_STR, GetTaskId)
223 };
224 napi_define_properties(env, napiTask, sizeof(properties) / sizeof(properties[0]), properties);
225 return task;
226 }
227
GenerateFunctionTask(napi_env env,napi_value func,napi_value * args,size_t argc,TaskType type)228 Task* Task::GenerateFunctionTask(napi_env env, napi_value func, napi_value* args, size_t argc, TaskType type)
229 {
230 HILOG_DEBUG("taskpool:: task GenerateFunctionTask");
231 napi_value argsArray;
232 napi_create_array_with_length(env, argc, &argsArray);
233 for (size_t i = 0; i < argc; i++) {
234 napi_set_element(env, argsArray, i, args[i]);
235 }
236 napi_value undefined = NapiHelper::GetUndefinedValue(env);
237 TaskInfo* taskInfo = GenerateTaskInfo(env, func, argsArray, undefined, undefined, Priority::DEFAULT);
238 if (taskInfo == nullptr) {
239 HILOG_ERROR("taskpool:: task GenerateFunctionTask end, taskInfo is nullptr");
240 return nullptr;
241 }
242 napi_value napiFuncName = NapiHelper::GetNameProperty(env, func, NAME);
243 char* nameStr = NapiHelper::GetChars(env, napiFuncName);
244 Task* task = new Task(env, type, nameStr);
245 delete[] nameStr;
246 task->currentTaskInfo_ = taskInfo;
247 task->InitHandle(env);
248 if (!task->IsMainThreadTask()) {
249 napi_add_env_cleanup_hook(env, CleanupHookFunc, task);
250 }
251 TaskManager::GetInstance().StoreTask(task);
252 return task;
253 }
254
GetTaskInfoPromise(napi_env env,napi_value task,TaskType taskType,Priority priority)255 napi_value Task::GetTaskInfoPromise(napi_env env, napi_value task, TaskType taskType, Priority priority)
256 {
257 TaskInfo* taskInfo = GetTaskInfo(env, task, priority);
258 if (taskInfo == nullptr) {
259 return nullptr;
260 }
261 UpdateTaskType(taskType);
262 return NapiHelper::CreatePromise(env, &taskInfo->deferred);
263 }
264
GetTaskInfo(napi_env env,napi_value napiTask,Priority priority)265 TaskInfo* Task::GetTaskInfo(napi_env env, napi_value napiTask, Priority priority)
266 {
267 auto [func, args, transferList, cloneList] = GetSerializeParams(env, napiTask);
268 if (func == nullptr || args == nullptr) {
269 return nullptr;
270 }
271
272 TaskInfo* pendingInfo = GenerateTaskInfo(env, func, args, transferList, cloneList, priority,
273 defaultTransfer_, defaultCloneSendable_);
274 if (pendingInfo == nullptr) {
275 return nullptr;
276 }
277 {
278 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
279 if (currentTaskInfo_ == nullptr) {
280 currentTaskInfo_ = pendingInfo;
281 } else {
282 pendingTaskInfos_.push_back(pendingInfo);
283 }
284 }
285 if (name_.empty()) {
286 napi_value funcName = NapiHelper::GetNameProperty(env, func, NAME);
287 name_ = NapiHelper::GetString(env, funcName);
288 }
289 return pendingInfo;
290 }
291
SetTransferList(napi_env env,napi_callback_info cbinfo)292 napi_value Task::SetTransferList(napi_env env, napi_callback_info cbinfo)
293 {
294 size_t argc = 1;
295 napi_value args[1];
296 napi_value thisVar;
297 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
298 // Check whether clone list has been set
299 if (NapiHelper::HasNameProperty(env, thisVar, CLONE_LIST_STR)) {
300 ErrorHelper::ThrowError(env, ErrorHelper::ERR_IN_BOTH_CLONE_AND_TRANSFER);
301 return nullptr;
302 }
303 if (argc > 1) {
304 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
305 "the number of setTransferList parma must be less than 2.");
306 return nullptr;
307 }
308 Task* task = nullptr;
309 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
310 if (task == nullptr) {
311 HILOG_ERROR("taskpool:: task is nullptr");
312 return nullptr;
313 }
314 napi_value undefined = NapiHelper::GetUndefinedValue(env);
315 napi_value falseVal = NapiHelper::CreateBooleanValue(env, false);
316 if (argc == 0) {
317 HILOG_DEBUG("taskpool:: set task params not transfer");
318 napi_set_named_property(env, thisVar, TRANSFERLIST_STR, undefined);
319 // set task.defaultTransfer false
320 task->defaultTransfer_ = false;
321 return nullptr;
322 }
323 if (!NapiHelper::IsArray(env, args[0])) {
324 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
325 "the type of setTransferList first param must be array.");
326 return nullptr;
327 }
328 // set task.defaultTransfer false
329 task->defaultTransfer_ = false;
330 uint32_t arrayLength = NapiHelper::GetArrayLength(env, args[0]);
331 if (arrayLength == 0) {
332 HILOG_DEBUG("taskpool:: set task params not transfer");
333 napi_set_named_property(env, thisVar, TRANSFERLIST_STR, undefined);
334 return nullptr;
335 }
336 for (size_t i = 0; i < arrayLength; i++) {
337 napi_value transferVal = NapiHelper::GetElement(env, args[0], i);
338 if (!NapiHelper::IsArrayBuffer(env, transferVal)) {
339 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
340 "the type of the element in array must be arraybuffer.");
341 return nullptr;
342 }
343 }
344 HILOG_DEBUG("taskpool:: check setTransferList param success");
345 napi_set_named_property(env, thisVar, TRANSFERLIST_STR, args[0]);
346 return nullptr;
347 }
348
SetCloneList(napi_env env,napi_callback_info cbinfo)349 napi_value Task::SetCloneList(napi_env env, napi_callback_info cbinfo)
350 {
351 size_t argc = 1;
352 napi_value args[1];
353 napi_value thisVar;
354 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
355 // Check whether transfer list has been set
356 if (NapiHelper::HasNameProperty(env, thisVar, TRANSFERLIST_STR)) {
357 ErrorHelper::ThrowError(env, ErrorHelper::ERR_IN_BOTH_CLONE_AND_TRANSFER);
358 return nullptr;
359 }
360 if (argc != 1) {
361 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of setCloneList parma must be 1.");
362 return nullptr;
363 }
364 if (!NapiHelper::IsArray(env, args[0])) {
365 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of setCloneList first param must be array.");
366 return nullptr;
367 }
368 Task* task = nullptr;
369 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
370 if (task == nullptr) {
371 HILOG_ERROR("taskpool:: task is nullptr");
372 return nullptr;
373 }
374 napi_value undefined = NapiHelper::GetUndefinedValue(env);
375 uint32_t arrayLength = NapiHelper::GetArrayLength(env, args[0]);
376 if (arrayLength == 0) {
377 HILOG_DEBUG("taskpool:: clone list is empty");
378 napi_set_named_property(env, thisVar, CLONE_LIST_STR, undefined);
379 return nullptr;
380 }
381 for (size_t i = 0; i < arrayLength; i++) {
382 napi_value cloneVal = NapiHelper::GetElement(env, args[0], i);
383 if (NapiHelper::IsBitVector(env, cloneVal)) {
384 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "BitVector not support setCloneList.");
385 return nullptr;
386 }
387 if (!NapiHelper::IsArrayBuffer(env, cloneVal) && !NapiHelper::IsSendable(env, cloneVal)) {
388 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
389 "the type of setCloneList elements in array must be arraybuffer or sendable.");
390 return nullptr;
391 }
392 }
393 napi_set_named_property(env, thisVar, CLONE_LIST_STR, args[0]);
394 return nullptr;
395 }
396
IsCanceled(napi_env env,napi_callback_info cbinfo)397 napi_value Task::IsCanceled(napi_env env, napi_callback_info cbinfo)
398 {
399 bool isCanceled = false;
400 auto engine = reinterpret_cast<NativeEngine*>(env);
401 if (!engine->IsTaskPoolThread()) {
402 HILOG_ERROR("taskpool:: call isCanceled not in taskpool thread");
403 return NapiHelper::CreateBooleanValue(env, isCanceled);
404 }
405 // Get task and query task cancel state
406 void* data = engine->GetCurrentTaskInfo();
407 if (data == nullptr) {
408 HILOG_ERROR("taskpool:: call isCanceled not in Concurrent function");
409 } else {
410 Task* task = static_cast<Task*>(data);
411 isCanceled = task->taskState_ == ExecuteState::CANCELED ? true : false;
412 }
413 return NapiHelper::CreateBooleanValue(env, isCanceled);
414 }
415
OnReceiveData(napi_env env,napi_callback_info cbinfo)416 napi_value Task::OnReceiveData(napi_env env, napi_callback_info cbinfo)
417 {
418 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
419 if (argc >= 2) { // 2: the number of parmas
420 HILOG_ERROR("taskpool:: the number of OnReceiveData parma must be less than 2");
421 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
422 "the number of OnReceiveData parma must be less than 2.");
423 return nullptr;
424 }
425
426 napi_value thisVar;
427 if (argc == 0) {
428 HILOG_INFO("taskpool:: Set taskpool.Task.onReceiveData to undefined");
429 napi_get_cb_info(env, cbinfo, &argc, nullptr, &thisVar, nullptr);
430 napi_value id = NapiHelper::GetNameProperty(env, thisVar, "taskId");
431 uint32_t taskId = NapiHelper::GetUint32Value(env, id);
432 TaskManager::GetInstance().RegisterCallback(env, taskId, nullptr, "OnReceiveData: Cancel listener");
433 return nullptr;
434 }
435
436 napi_value args[1];
437 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
438 napi_valuetype type;
439 NAPI_CALL(env, napi_typeof(env, args[0], &type));
440 if (type != napi_function) {
441 HILOG_ERROR("taskpool:: OnReceiveData's parameter should be function");
442 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
443 "the type of onReceiveData's parameter must be function.");
444 return nullptr;
445 }
446 // store callbackInfo
447 napi_value napiTaskId = NapiHelper::GetNameProperty(env, thisVar, "taskId");
448 uint32_t taskId = NapiHelper::GetUint32Value(env, napiTaskId);
449 auto task = TaskManager::GetInstance().GetTask(taskId);
450 if (task == nullptr) {
451 HILOG_ERROR("taskpool:: OnReceiveData's task is nullptr");
452 return nullptr;
453 }
454 napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
455 std::shared_ptr<CallbackInfo> callbackInfo = std::make_shared<CallbackInfo>(env, 1, callbackRef);
456 TaskManager::GetInstance().RegisterCallback(env, taskId, callbackInfo, "OnReceiveData: Add listener");
457 return nullptr;
458 }
459
SendData(napi_env env,napi_callback_info cbinfo)460 napi_value Task::SendData(napi_env env, napi_callback_info cbinfo)
461 {
462 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
463 napi_value args[argc];
464 napi_get_cb_info(env, cbinfo, &argc, args, nullptr, nullptr);
465
466 napi_value argsArray;
467 napi_create_array_with_length(env, argc, &argsArray);
468 for (size_t i = 0; i < argc; i++) {
469 napi_set_element(env, argsArray, i, args[i]);
470 }
471
472 auto engine = reinterpret_cast<NativeEngine*>(env);
473 if (!engine->IsTaskPoolThread()) {
474 HILOG_ERROR("taskpool:: SendData is not called in the taskpool thread");
475 ErrorHelper::ThrowError(env, ErrorHelper::ERR_NOT_IN_TASKPOOL_THREAD);
476 return nullptr;
477 }
478 void* data = engine->GetCurrentTaskInfo();
479 if (data == nullptr) {
480 HILOG_ERROR("taskpool:: SendData is not called in the concurrent function");
481 ErrorHelper::ThrowError(env, ErrorHelper::ERR_NOT_IN_CONCURRENT_FUNCTION);
482 return nullptr;
483 }
484
485 Task* task = static_cast<Task*>(data);
486 napi_value undefined = NapiHelper::GetUndefinedValue(env);
487 void* serializationArgs = nullptr;
488 bool defaultClone = false;
489 bool defaultTransfer = true;
490 std::string errString = "";
491 napi_status status = napi_serialize_inner_with_error(env, argsArray, undefined, undefined, defaultTransfer,
492 defaultClone, &serializationArgs, errString);
493 if (status != napi_ok || serializationArgs == nullptr) {
494 std::string errMessage = "taskpool:: failed to serialize function.\nSerialize error: " + errString;
495 HILOG_ERROR("%{public}s in SendData", errMessage.c_str());
496 ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
497 return nullptr;
498 }
499
500 TaskResultInfo* resultInfo = new TaskResultInfo(env, task->GetTaskId(), serializationArgs);
501 TaskManager::GetInstance().ExecuteSendData(env, resultInfo, task);
502 return nullptr;
503 }
504
AddDependency(napi_env env,napi_callback_info cbinfo)505 napi_value Task::AddDependency(napi_env env, napi_callback_info cbinfo)
506 {
507 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
508 if (argc == 0) {
509 std::string errMessage = "taskpool:: addDependency has no params";
510 HILOG_ERROR("%{public}s", errMessage.c_str());
511 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "addDependency has no params.");
512 return nullptr;
513 }
514
515 napi_status status = napi_ok;
516 HandleScope scope(env, status);
517 napi_value args[argc];
518 napi_value napiTask;
519 napi_get_cb_info(env, cbinfo, &argc, args, &napiTask, nullptr);
520 Task* task = nullptr;
521 napi_unwrap(env, napiTask, reinterpret_cast<void**>(&task));
522 if (task == nullptr) {
523 HILOG_ERROR("taskpool:: task is nullptr");
524 return nullptr;
525 }
526 std::string errMessage = "";
527 if (task->IsPeriodicTask()) {
528 HILOG_ERROR("taskpool:: the periodic task cannot have a dependency");
529 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
530 return nullptr;
531 }
532 if (task->IsCommonTask() || task->IsSeqRunnerTask()) {
533 errMessage = "taskpool:: seqRunnerTask or executedTask cannot addDependency";
534 HILOG_ERROR("%{public}s", errMessage.c_str());
535 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
536 return nullptr;
537 }
538 if (task->IsAsyncRunnerTask()) {
539 HILOG_ERROR("taskpool:: AsyncRunnerTask cannot addDependency.");
540 ErrorHelper::ThrowError(env, ErrorHelper::ERR_ASYNCRUNNER_TASK_HAVE_DEPENDENCY);
541 return nullptr;
542 }
543 if (task->IsGroupCommonTask()) {
544 errMessage = "taskpool:: groupTask cannot addDependency";
545 HILOG_ERROR("%{public}s", errMessage.c_str());
546 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
547 return nullptr;
548 }
549 task->SetHasDependency(true);
550 std::set<uint32_t> idSet;
551 for (size_t i = 0; i < argc; i++) {
552 if (!NapiHelper::HasNameProperty(env, args[i], TASKID_STR)) {
553 errMessage = "taskpool:: addDependency param is not task";
554 HILOG_ERROR("%{public}s", errMessage.c_str());
555 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the addDependency param must be task.");
556 return nullptr;
557 } else {
558 Task* dependentTask = nullptr;
559 napi_unwrap(env, args[i], reinterpret_cast<void**>(&dependentTask));
560 if (dependentTask == nullptr) {
561 HILOG_ERROR("taskpool:: dependentTask is nullptr");
562 return nullptr;
563 }
564 if (dependentTask->taskId_ == task->taskId_) {
565 HILOG_ERROR("taskpool:: there is a circular dependency");
566 ErrorHelper::ThrowError(env, ErrorHelper::ERR_CIRCULAR_DEPENDENCY);
567 return nullptr;
568 }
569 if (dependentTask->IsPeriodicTask()) {
570 HILOG_ERROR("taskpool:: the periodic task cannot have a dependency");
571 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
572 return nullptr;
573 }
574 if (dependentTask->IsCommonTask() || dependentTask->IsSeqRunnerTask()) {
575 errMessage = "taskpool:: seqRunnerTask or executedTask cannot be relied on";
576 HILOG_ERROR("%{public}s", errMessage.c_str());
577 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
578 return nullptr;
579 }
580 if (dependentTask->IsAsyncRunnerTask()) {
581 HILOG_ERROR("taskpool:: AsyncRunnerTask cannot be relied on.");
582 ErrorHelper::ThrowError(env, ErrorHelper::ERR_ASYNCRUNNER_TASK_HAVE_DEPENDENCY);
583 return nullptr;
584 }
585 if (dependentTask->IsGroupCommonTask()) {
586 errMessage = "taskpool:: groupTask cannot be relied on";
587 HILOG_ERROR("%{public}s", errMessage.c_str());
588 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
589 return nullptr;
590 }
591 idSet.emplace(dependentTask->taskId_);
592 dependentTask->SetHasDependency(true);
593 }
594 }
595 if (!TaskManager::GetInstance().StoreTaskDependency(task->taskId_, idSet)) {
596 HILOG_ERROR("taskpool:: there is a circular dependency");
597 ErrorHelper::ThrowError(env, ErrorHelper::ERR_CIRCULAR_DEPENDENCY);
598 }
599 std::string strTrace = "Task::AddDependency: ";
600 HITRACE_HELPER_METER_NAME(strTrace + TaskManager::GetInstance().GetTaskDependInfoToString(task->taskId_));
601 return nullptr;
602 }
603
RemoveDependency(napi_env env,napi_callback_info cbinfo)604 napi_value Task::RemoveDependency(napi_env env, napi_callback_info cbinfo)
605 {
606 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
607 if (argc == 0) {
608 std::string errMessage = "taskpool:: removeDependency has no params";
609 HILOG_ERROR("%{public}s", errMessage.c_str());
610 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "removeDependency has no params.");
611 return nullptr;
612 }
613 napi_status status = napi_ok;
614 HandleScope scope(env, status);
615 napi_value args[argc];
616 napi_value napiTask;
617 napi_get_cb_info(env, cbinfo, &argc, args, &napiTask, nullptr);
618 Task* task = nullptr;
619 napi_unwrap(env, napiTask, reinterpret_cast<void**>(&task));
620 if (task == nullptr) {
621 HILOG_ERROR("taskpool:: the task is nullptr");
622 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the task is nullptr");
623 return nullptr;
624 }
625 if (!task->HasDependency()) {
626 ThrowNoDependencyError(env);
627 return nullptr;
628 }
629 if (task->IsPeriodicTask()) {
630 HILOG_ERROR("taskpool:: the periodic task cannot call removeDependency");
631 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
632 return nullptr;
633 }
634 if (task->IsCommonTask()) {
635 std::string errMessage = "taskpool:: executedTask cannot removeDependency";
636 HILOG_ERROR("%{public}s", errMessage.c_str());
637 ErrorHelper::ThrowError(env, ErrorHelper::ERR_INEXISTENT_DEPENDENCY, errMessage.c_str());
638 return nullptr;
639 }
640 if (task->IsAsyncRunnerTask()) {
641 HILOG_ERROR("taskpool:: AsyncRunnerTask cannot call removeDependency.");
642 ErrorHelper::ThrowError(env, ErrorHelper::ERR_ASYNCRUNNER_TASK_HAVE_DEPENDENCY);
643 return nullptr;
644 }
645 for (size_t i = 0; i < argc; i++) {
646 if (!NapiHelper::HasNameProperty(env, args[i], TASKID_STR)) {
647 std::string errMessage = "taskpool:: removeDependency param is not task";
648 HILOG_ERROR("%{public}s", errMessage.c_str());
649 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of removeDependency param must be task.");
650 return nullptr;
651 }
652 Task* dependentTask = nullptr;
653 napi_unwrap(env, args[i], reinterpret_cast<void**>(&dependentTask));
654 if (dependentTask == nullptr) {
655 HILOG_ERROR("taskpool:: the dependent task is nullptr");
656 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the dependent task is nullptr");
657 return nullptr;
658 }
659 if (!dependentTask->HasDependency()) {
660 ThrowNoDependencyError(env);
661 return nullptr;
662 }
663 if (dependentTask->IsPeriodicTask()) {
664 HILOG_ERROR("taskpool:: the periodic task cannot call removeDependency");
665 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
666 return nullptr;
667 }
668 if (dependentTask->IsCommonTask()) {
669 std::string errMessage = "taskpool:: cannot removeDependency on a dependent and executed task";
670 HILOG_ERROR("%{public}s", errMessage.c_str());
671 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
672 return nullptr;
673 }
674 if (dependentTask->IsAsyncRunnerTask()) {
675 HILOG_ERROR("taskpool:: AsyncRunnerTask cannot call removeDependency.");
676 ErrorHelper::ThrowError(env, ErrorHelper::ERR_ASYNCRUNNER_TASK_HAVE_DEPENDENCY);
677 return nullptr;
678 }
679 if (!TaskManager::GetInstance().RemoveTaskDependency(task->taskId_, dependentTask->taskId_)) {
680 HILOG_ERROR("taskpool:: the dependency does not exist");
681 ErrorHelper::ThrowError(env, ErrorHelper::ERR_INEXISTENT_DEPENDENCY);
682 return nullptr;
683 }
684 dependentTask->TryClearHasDependency();
685 }
686 task->TryClearHasDependency();
687 std::string strTrace = "Task::RemoveDependency: ";
688 HITRACE_HELPER_METER_NAME(strTrace + TaskManager::GetInstance().GetTaskDependInfoToString(task->taskId_));
689 return nullptr;
690 }
691
StartExecutionCallback(const uv_async_t * req)692 void Task::StartExecutionCallback(const uv_async_t* req)
693 {
694 HILOG_DEBUG("taskpool:: task StartExecutionCallback");
695 auto listenerCallBackInfo = static_cast<ListenerCallBackInfo*>(req->data);
696 if (listenerCallBackInfo == nullptr) { // LCOV_EXCL_BR_LINE
697 HILOG_FATAL("taskpool:: StartExecutionCallBackInfo is null");
698 return;
699 }
700 StartExecutionTask(listenerCallBackInfo);
701 }
702
StartExecutionTask(ListenerCallBackInfo * listenerCallBackInfo)703 void Task::StartExecutionTask(ListenerCallBackInfo* listenerCallBackInfo)
704 {
705 auto env = listenerCallBackInfo->env_;
706 napi_status status = napi_ok;
707 HandleScope scope(env, status);
708 if (status != napi_ok) {
709 HILOG_ERROR("taskpool:: napi_open_handle_scope failed");
710 return;
711 }
712 auto func = NapiHelper::GetReferenceValue(env, listenerCallBackInfo->callbackRef_);
713 if (func == nullptr) {
714 HILOG_INFO("taskpool:: StartExecutionCallback func is null");
715 return;
716 }
717
718 napi_value result;
719 napi_call_function(env, NapiHelper::GetGlobalObject(env), func, 0, nullptr, &result);
720 if (NapiHelper::IsExceptionPending(env)) {
721 napi_value exception = nullptr;
722 napi_get_and_clear_last_exception(env, &exception);
723 std::string funcStr = NapiHelper::GetPrintString(env, func);
724 HILOG_ERROR("taskpool:: an exception has occurred napi_call_function, func is %{public}s", funcStr.c_str());
725 }
726 }
727
ExecuteListenerCallback(ListenerCallBackInfo * listenerCallBackInfo,uint32_t taskId)728 void Task::ExecuteListenerCallback(ListenerCallBackInfo* listenerCallBackInfo, uint32_t taskId)
729 {
730 HILOG_DEBUG("taskpool:: task ExecuteListenerCallback");
731 if (listenerCallBackInfo == nullptr) { // LCOV_EXCL_BR_LINE
732 HILOG_FATAL("taskpool:: listenerCallBackInfo is null");
733 return;
734 }
735
736 napi_env env = listenerCallBackInfo->env_;
737 napi_value func = NapiHelper::GetReferenceValue(env, listenerCallBackInfo->callbackRef_);
738 if (func == nullptr) {
739 HILOG_INFO("taskpool:: ExecuteListenerCallback func is null");
740 return;
741 }
742
743 std::string callbackType = listenerCallBackInfo->type_;
744 HITRACE_HELPER_METER_NAME("ExecuteListenerCallback: type = " + callbackType + ", taskId = " +
745 std::to_string(taskId));
746
747 napi_value result;
748 napi_value args = listenerCallBackInfo->taskError_;
749 if (args != nullptr) {
750 napi_call_function(env, NapiHelper::GetGlobalObject(env), func, 1, &args, &result);
751 } else {
752 napi_call_function(env, NapiHelper::GetGlobalObject(env), func, 0, nullptr, &result);
753 }
754
755 if (NapiHelper::IsExceptionPending(env)) {
756 napi_value exception = nullptr;
757 napi_get_and_clear_last_exception(env, &exception);
758 std::string funcStr = NapiHelper::GetPrintString(env, func);
759 HILOG_ERROR("taskpool:: an exception has occurred napi_call_function, func is %{public}s", funcStr.c_str());
760 }
761 }
762
OnEnqueued(napi_env env,napi_callback_info cbinfo)763 napi_value Task::OnEnqueued(napi_env env, napi_callback_info cbinfo)
764 {
765 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
766 napi_value thisVar;
767 if (argc == 0) {
768 HILOG_INFO("taskpool:: the number of the params must be one");
769 return nullptr;
770 }
771
772 napi_value args[1];
773 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
774 napi_valuetype type;
775 NAPI_CALL(env, napi_typeof(env, args[0], &type));
776 if (type != napi_function) {
777 HILOG_ERROR("taskpool:: OnEnqueued's parameter should be function");
778 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of OnEnqueued's parameter must be function.");
779 return nullptr;
780 }
781
782 Task* task = nullptr;
783 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
784 if (task == nullptr) {
785 HILOG_ERROR("taskpool:: task is nullptr");
786 return nullptr;
787 }
788
789 if (task->taskState_ != ExecuteState::NOT_FOUND) {
790 HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
791 ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
792 return nullptr;
793 }
794
795 napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
796 task->onEnqueuedCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
797 task->onEnqueuedCallBackInfo_->type_ = "onEnqueued";
798 return nullptr;
799 }
800
OnStartExecution(napi_env env,napi_callback_info cbinfo)801 napi_value Task::OnStartExecution(napi_env env, napi_callback_info cbinfo)
802 {
803 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
804 napi_value thisVar;
805 if (argc == 0) {
806 HILOG_INFO("taskpool:: the number of the params must be one");
807 return nullptr;
808 }
809
810 napi_value args[1];
811 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
812 napi_valuetype type;
813 NAPI_CALL(env, napi_typeof(env, args[0], &type));
814 if (type != napi_function) {
815 HILOG_ERROR("taskpool:: OnStartExecution's parameter should be function");
816 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
817 "the type of OnStartExecution's parameter must be function.");
818 return nullptr;
819 }
820
821 Task* task = nullptr;
822 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
823 if (task == nullptr) {
824 HILOG_ERROR("taskpool:: task is nullptr");
825 return nullptr;
826 }
827
828 if (task->taskState_ != ExecuteState::NOT_FOUND) {
829 HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
830 ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
831 return nullptr;
832 }
833
834 napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
835 task->onStartExecutionCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
836 task->onStartExecutionCallBackInfo_->type_ = "onStartExecution";
837 #if defined(ENABLE_TASKPOOL_EVENTHANDLER)
838 if (!task->IsMainThreadTask()) {
839 auto loop = NapiHelper::GetLibUV(env);
840 ConcurrentHelper::UvHandleInit(loop, task->onStartExecutionSignal_,
841 Task::StartExecutionCallback, task->onStartExecutionCallBackInfo_);
842 }
843 #else
844 auto loop = NapiHelper::GetLibUV(env);
845 ConcurrentHelper::UvHandleInit(loop, task->onStartExecutionSignal_,
846 Task::StartExecutionCallback, task->onStartExecutionCallBackInfo_);
847 #endif
848
849 return nullptr;
850 }
851
OnExecutionFailed(napi_env env,napi_callback_info cbinfo)852 napi_value Task::OnExecutionFailed(napi_env env, napi_callback_info cbinfo)
853 {
854 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
855 napi_value thisVar;
856 if (argc == 0) {
857 HILOG_INFO("taskpool:: the number of the params must be one");
858 return nullptr;
859 }
860
861 napi_value args[1];
862 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
863 napi_valuetype type;
864 NAPI_CALL(env, napi_typeof(env, args[0], &type));
865 if (type != napi_function) {
866 HILOG_ERROR("taskpool:: OnExecutionFailed's parameter should be function");
867 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
868 "the type of OnExecutionFailed's parameter must be function.");
869 return nullptr;
870 }
871
872 Task* task = nullptr;
873 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
874 if (task == nullptr) {
875 HILOG_ERROR("taskpool:: task is nullptr");
876 return nullptr;
877 }
878
879 if (task->taskState_ != ExecuteState::NOT_FOUND) {
880 HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
881 ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
882 return nullptr;
883 }
884
885 napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
886 task->onExecutionFailedCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
887 task->onExecutionFailedCallBackInfo_->type_ = "onExecutionFailed";
888 return nullptr;
889 }
890
OnExecutionSucceeded(napi_env env,napi_callback_info cbinfo)891 napi_value Task::OnExecutionSucceeded(napi_env env, napi_callback_info cbinfo)
892 {
893 size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
894 napi_value thisVar;
895 if (argc == 0) {
896 HILOG_INFO("taskpool:: the number of the params must be one");
897 return nullptr;
898 }
899
900 napi_value args[1];
901 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
902 napi_valuetype type;
903 NAPI_CALL(env, napi_typeof(env, args[0], &type));
904 if (type != napi_function) {
905 HILOG_ERROR("taskpool:: OnExecutionSucceeded's parameter should be function");
906 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
907 "the type of OnExecutionSucceeded's parameter must be function");
908 return nullptr;
909 }
910
911 Task* task = nullptr;
912 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
913 if (task == nullptr) {
914 HILOG_ERROR("taskpool:: task is nullptr");
915 return nullptr;
916 }
917
918 if (task->taskState_ != ExecuteState::NOT_FOUND) {
919 HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
920 ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
921 return nullptr;
922 }
923
924 napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
925 task->onExecutionSucceededCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
926 task->onExecutionSucceededCallBackInfo_->type_ = "onExecutionSucceeded";
927 return nullptr;
928 }
929
IsDone(napi_env env,napi_callback_info cbinfo)930 napi_value Task::IsDone(napi_env env, napi_callback_info cbinfo)
931 {
932 napi_value thisVar = nullptr;
933 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
934 Task* task = nullptr;
935 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
936 if (task == nullptr) {
937 HILOG_ERROR("taskpool:: task is nullptr");
938 return NapiHelper::CreateBooleanValue(env, false);
939 }
940
941 if (task->taskState_ == ExecuteState::FINISHED || task->taskState_ == ExecuteState::ENDING) {
942 return NapiHelper::CreateBooleanValue(env, true);
943 }
944 return NapiHelper::CreateBooleanValue(env, false);
945 }
946
GetTaskDuration(napi_env env,napi_callback_info & cbinfo,std::string durationType)947 napi_value Task::GetTaskDuration(napi_env env, napi_callback_info& cbinfo, std::string durationType)
948 {
949 napi_value thisVar = nullptr;
950 Task* task = nullptr;
951 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
952 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
953 if (task == nullptr) {
954 uint64_t totalDuration = 0;
955 return NapiHelper::CreateUint32(env, totalDuration);
956 }
957 uint64_t totalDuration = TaskManager::GetInstance().GetTaskDuration(task->taskId_, durationType);
958 return NapiHelper::CreateUint32(env, totalDuration);
959 }
960
GetTotalDuration(napi_env env,napi_callback_info cbinfo)961 napi_value Task::GetTotalDuration(napi_env env, napi_callback_info cbinfo)
962 {
963 return GetTaskDuration(env, cbinfo, TASK_TOTAL_TIME);
964 }
965
GetCPUDuration(napi_env env,napi_callback_info cbinfo)966 napi_value Task::GetCPUDuration(napi_env env, napi_callback_info cbinfo)
967 {
968 return GetTaskDuration(env, cbinfo, TASK_CPU_TIME);
969 }
970
GetIODuration(napi_env env,napi_callback_info cbinfo)971 napi_value Task::GetIODuration(napi_env env, napi_callback_info cbinfo)
972 {
973 return GetTaskDuration(env, cbinfo, TASK_IO_TIME);
974 }
975
GetName(napi_env env,napi_callback_info cbinfo)976 napi_value Task::GetName(napi_env env, napi_callback_info cbinfo)
977 {
978 napi_value thisVar = nullptr;
979 Task* task = nullptr;
980 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
981 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
982 if (task == nullptr) {
983 return NapiHelper::CreateEmptyString(env);
984 }
985 napi_value name = nullptr;
986 napi_create_string_utf8(env, task->name_.c_str(), NAPI_AUTO_LENGTH, &name);
987 return name;
988 }
989
GetTaskId(napi_env env,napi_callback_info cbinfo)990 napi_value Task::GetTaskId(napi_env env, napi_callback_info cbinfo)
991 {
992 napi_value thisVar = nullptr;
993 Task* task = nullptr;
994 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
995 napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
996 if (task == nullptr) {
997 return NapiHelper::CreateUint32(env, 0); // 0 : default value
998 }
999 return NapiHelper::CreateUint32(env, task->taskId_);
1000 }
1001
UpdateTaskType(TaskType taskType)1002 void Task::UpdateTaskType(TaskType taskType)
1003 {
1004 taskType_ = taskType;
1005 napi_reference_ref(env_, taskRef_, nullptr);
1006 }
1007
IsRepeatableTask() const1008 bool Task::IsRepeatableTask() const
1009 {
1010 return IsCommonTask() || IsGroupCommonTask() || IsGroupFunctionTask();
1011 }
1012
IsGroupTask() const1013 bool Task::IsGroupTask() const
1014 {
1015 return IsGroupCommonTask() || IsGroupFunctionTask();
1016 }
1017
IsGroupCommonTask() const1018 bool Task::IsGroupCommonTask() const
1019 {
1020 return taskType_ == TaskType::GROUP_COMMON_TASK;
1021 }
1022
IsGroupFunctionTask() const1023 bool Task::IsGroupFunctionTask() const
1024 {
1025 return taskType_ == TaskType::GROUP_FUNCTION_TASK;
1026 }
1027
IsCommonTask() const1028 bool Task::IsCommonTask() const
1029 {
1030 return taskType_ == TaskType::COMMON_TASK;
1031 }
1032
IsSeqRunnerTask() const1033 bool Task::IsSeqRunnerTask() const
1034 {
1035 return taskType_ == TaskType::SEQRUNNER_TASK;
1036 }
1037
IsFunctionTask() const1038 bool Task::IsFunctionTask() const
1039 {
1040 return taskType_ == TaskType::FUNCTION_TASK;
1041 }
1042
IsLongTask() const1043 bool Task::IsLongTask() const
1044 {
1045 return isLongTask_;
1046 }
1047
IsPeriodicTask() const1048 bool Task::IsPeriodicTask() const
1049 {
1050 return isPeriodicTask_;
1051 }
1052
IsMainThreadTask() const1053 bool Task::IsMainThreadTask() const
1054 {
1055 return isMainThreadTask_;
1056 }
1057
1058 // The uninitialized state is Task, and then taskType_ will be updated based on the task type.
IsExecuted() const1059 bool Task::IsExecuted() const
1060 {
1061 return taskType_ != TaskType::TASK;
1062 }
1063
GenerateTaskInfo(napi_env env,napi_value func,napi_value args,napi_value transferList,napi_value cloneList,Priority priority,bool defaultTransfer,bool defaultCloneSendable)1064 TaskInfo* Task::GenerateTaskInfo(napi_env env, napi_value func, napi_value args,
1065 napi_value transferList, napi_value cloneList, Priority priority,
1066 bool defaultTransfer, bool defaultCloneSendable)
1067 {
1068 HILOG_DEBUG("taskpool:: task GenerateTaskInfo");
1069 std::tuple<napi_value, napi_value, bool, bool> params = {
1070 transferList, cloneList, defaultTransfer, defaultCloneSendable
1071 };
1072 auto [serializationFunction, serializationArguments] = GetSerializeResult(env, func, args, params);
1073 if (serializationFunction == nullptr || serializationArguments == nullptr) {
1074 return nullptr;
1075 }
1076 TaskInfo* taskInfo = new TaskInfo();
1077 taskInfo->serializationFunction = serializationFunction;
1078 taskInfo->serializationArguments = serializationArguments;
1079 taskInfo->priority = priority;
1080 reinterpret_cast<NativeEngine*>(env)->IncreaseSubEnvCounter();
1081 return taskInfo;
1082 }
1083
IncreaseRefCount()1084 void Task::IncreaseRefCount()
1085 {
1086 taskRefCount_.fetch_add(2); // 2 : for PerformTask and TaskResultCallback
1087 }
1088
DecreaseRefCount()1089 void Task::DecreaseRefCount()
1090 {
1091 taskRefCount_.fetch_sub(1);
1092 }
1093
IsReadyToHandle() const1094 bool Task::IsReadyToHandle() const
1095 {
1096 return (taskRefCount_ & 1) == 0;
1097 }
1098
NotifyPendingTask()1099 void Task::NotifyPendingTask()
1100 {
1101 HILOG_DEBUG("taskpool:: task:%{public}s NotifyPendingTask", std::to_string(taskId_).c_str());
1102 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1103 delete currentTaskInfo_;
1104 if (pendingTaskInfos_.empty()) {
1105 currentTaskInfo_ = nullptr;
1106 HILOG_DEBUG("taskpool:: task:%{public}s NotifyPendingTask end, currentTaskInfo_ nullptr",
1107 std::to_string(taskId_).c_str());
1108 return;
1109 }
1110 if (IsPeriodicTask() && taskState_ == ExecuteState::CANCELED) {
1111 currentTaskInfo_ = nullptr;
1112 HILOG_DEBUG("taskpool:: task:%{public}s NotifyPendingTask end, periodicTask is canceled",
1113 std::to_string(taskId_).c_str());
1114 return;
1115 }
1116 currentTaskInfo_ = pendingTaskInfos_.front();
1117 pendingTaskInfos_.pop_front();
1118 taskState_ = ExecuteState::WAITING;
1119 TaskManager::GetInstance().EnqueueTaskId(taskId_, currentTaskInfo_->priority);
1120 }
1121
CancelPendingTask(napi_env env)1122 void Task::CancelPendingTask(napi_env env)
1123 {
1124 HILOG_DEBUG("taskpool:: task:%{public}s CancelPendingTask", std::to_string(taskId_).c_str());
1125 std::list<napi_deferred> deferreds {};
1126 {
1127 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1128 if (pendingTaskInfos_.empty()) {
1129 HILOG_DEBUG("taskpool:: task CancelPendingTask end, pendingTaskInfos_ nullptr");
1130 return;
1131 }
1132 auto engine = reinterpret_cast<NativeEngine*>(env);
1133 for (const auto& info : pendingTaskInfos_) {
1134 engine->DecreaseSubEnvCounter();
1135 if (!IsPeriodicTask()) {
1136 deferreds.push_back(info->deferred);
1137 }
1138 napi_reference_unref(env, taskRef_, nullptr);
1139 delete info;
1140 }
1141 pendingTaskInfos_.clear();
1142 }
1143 std::string error = "taskpool:: task has been canceled";
1144 TaskManager::GetInstance().BatchRejectDeferred(env_, deferreds, error);
1145 }
1146
UpdateTask(uint64_t startTime,void * worker)1147 bool Task::UpdateTask(uint64_t startTime, void* worker)
1148 {
1149 HILOG_DEBUG("taskpool:: task:%{public}s UpdateTask", std::to_string(taskId_).c_str());
1150 UpdateTaskStateToRunning();
1151 startTime_ = startTime;
1152 worker_ = worker;
1153 return true;
1154 }
1155
DeserializeValue(napi_env env,napi_value * func,napi_value * args)1156 napi_value Task::DeserializeValue(napi_env env, napi_value* func, napi_value* args)
1157 {
1158 void* serializationFunction = nullptr;
1159 void* serializationArguments = nullptr;
1160 {
1161 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1162 if (UNLIKELY(currentTaskInfo_ == nullptr)) {
1163 HILOG_ERROR("taskpool:: the currentTaskInfo is nullptr, the task may have been cancelled");
1164 return nullptr;
1165 }
1166 serializationFunction = currentTaskInfo_->serializationFunction;
1167 serializationArguments = currentTaskInfo_->serializationArguments;
1168 }
1169 napi_status status = napi_ok;
1170 std::string errMessage = "";
1171 status = napi_deserialize(env, serializationFunction, func);
1172 if (!IsGroupFunctionTask()) {
1173 napi_delete_serialization_data(env, serializationFunction);
1174 }
1175 if (status != napi_ok || func == nullptr) {
1176 errMessage = "taskpool:: failed to deserialize function.";
1177 HILOG_ERROR("%{public}s", errMessage.c_str());
1178 napi_value err = ErrorHelper::NewError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
1179 success_ = false;
1180 return err;
1181 }
1182
1183 status = napi_deserialize(env, serializationArguments, args);
1184 if (!IsGroupFunctionTask()) {
1185 napi_delete_serialization_data(env, serializationArguments);
1186 }
1187 if (status != napi_ok || args == nullptr) {
1188 errMessage = "taskpool:: failed to deserialize function.";
1189 HILOG_ERROR("%{public}s", errMessage.c_str());
1190 napi_value err = ErrorHelper::NewError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
1191 success_ = false;
1192 return err;
1193 }
1194 return nullptr;
1195 }
1196
StoreTaskDuration()1197 void Task::StoreTaskDuration()
1198 {
1199 HILOG_DEBUG("taskpool:: task:%{public}s StoreTaskDuration", std::to_string(taskId_).c_str());
1200 cpuTime_ = ConcurrentHelper::GetMilliseconds();
1201 uint64_t cpuDuration = cpuTime_ - startTime_;
1202 if (ioTime_ != 0) {
1203 uint64_t ioDuration = ioTime_ - startTime_;
1204 TaskManager::GetInstance().StoreTaskDuration(taskId_, std::max(cpuDuration, ioDuration), cpuDuration);
1205 } else {
1206 TaskManager::GetInstance().StoreTaskDuration(taskId_, 0, cpuDuration);
1207 }
1208 }
1209
CanForSequenceRunner(napi_env env)1210 bool Task::CanForSequenceRunner(napi_env env)
1211 {
1212 std::string errMessage = "";
1213 // task with dependence is not allowed
1214 if (HasDependency()) {
1215 errMessage = "seqRunner:: dependent task not allowed.";
1216 HILOG_ERROR("%{public}s", errMessage.c_str());
1217 ErrorHelper::ThrowError(env, ErrorHelper::ERR_ADD_DEPENDENT_TASK_TO_SEQRUNNER, errMessage.c_str());
1218 return false;
1219 }
1220 if (IsPeriodicTask()) {
1221 errMessage = "taskpool:: SequenceRunner cannot execute the periodicTask";
1222 HILOG_ERROR("%{public}s", errMessage.c_str());
1223 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1224 return false;
1225 }
1226 if (IsCommonTask() || IsSeqRunnerTask()) {
1227 errMessage = "taskpool:: SequenceRunner cannot execute seqRunnerTask or executedTask";
1228 HILOG_ERROR("%{public}s", errMessage.c_str());
1229 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1230 return false;
1231 }
1232 if (IsGroupCommonTask()) {
1233 errMessage = "taskpool:: SequenceRunner cannot execute groupTask";
1234 HILOG_ERROR("%{public}s", errMessage.c_str());
1235 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1236 return false;
1237 }
1238 if (IsAsyncRunnerTask()) {
1239 errMessage = "SequenceRunner cannot execute asyncRunnerTask.";
1240 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1241 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1242 return false;
1243 }
1244 return true;
1245 }
1246
CanForTaskGroup(napi_env env)1247 bool Task::CanForTaskGroup(napi_env env)
1248 {
1249 std::string errMessage = "";
1250 if (HasDependency()) {
1251 errMessage = "taskpool:: dependent task not allowed.";
1252 HILOG_ERROR("%{public}s", errMessage.c_str());
1253 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1254 return false;
1255 }
1256 if (IsPeriodicTask()) {
1257 errMessage = "taskpool:: The interface does not support the periodicTask";
1258 HILOG_ERROR("%{public}s", errMessage.c_str());
1259 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1260 return false;
1261 }
1262 if (IsCommonTask() || IsSeqRunnerTask()) {
1263 errMessage = "taskpool:: taskGroup cannot add seqRunnerTask or executedTask";
1264 HILOG_ERROR("%{public}s", errMessage.c_str());
1265 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1266 return false;
1267 }
1268 if (IsGroupCommonTask()) {
1269 errMessage = "taskpool:: taskGroup cannot add groupTask";
1270 HILOG_ERROR("%{public}s", errMessage.c_str());
1271 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1272 return false;
1273 }
1274 if (IsLongTask()) {
1275 errMessage = "taskpool:: The interface does not support the long task";
1276 HILOG_ERROR("%{public}s", errMessage.c_str());
1277 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1278 return false;
1279 }
1280 if (IsAsyncRunnerTask()) {
1281 errMessage = "TaskGroup cannot execute asyncRunnerTask.";
1282 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1283 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1284 return false;
1285 }
1286 taskType_ = TaskType::GROUP_COMMON_TASK;
1287 return true;
1288 }
1289
CanExecute(napi_env env)1290 bool Task::CanExecute(napi_env env)
1291 {
1292 std::string errMessage = "";
1293 if (IsGroupCommonTask()) {
1294 errMessage = "taskpool:: groupTask cannot execute outside";
1295 HILOG_ERROR("%{public}s", errMessage.c_str());
1296 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1297 return false;
1298 }
1299 if (IsSeqRunnerTask()) {
1300 errMessage = "taskpool:: seqRunnerTask cannot execute outside";
1301 HILOG_ERROR("%{public}s", errMessage.c_str());
1302 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1303 return false;
1304 }
1305 if (IsCommonTask() && HasDependency()) {
1306 errMessage = "taskpool:: executedTask with dependency cannot execute again";
1307 HILOG_ERROR("%{public}s", errMessage.c_str());
1308 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1309 return false;
1310 }
1311 if (IsExecuted() && IsLongTask()) {
1312 errMessage = "taskpool:: The long task can only be executed once";
1313 HILOG_ERROR("%{public}s", errMessage.c_str());
1314 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1315 return false;
1316 }
1317 if (IsPeriodicTask()) {
1318 errMessage = "taskpool:: the periodicTask cannot execute again";
1319 HILOG_ERROR("%{public}s", errMessage.c_str());
1320 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1321 return false;
1322 }
1323 if (IsAsyncRunnerTask()) {
1324 errMessage = "AsyncRunnerTask cannot execute outside.";
1325 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1326 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1327 return false;
1328 }
1329 return true;
1330 }
1331
CanExecuteDelayed(napi_env env)1332 bool Task::CanExecuteDelayed(napi_env env)
1333 {
1334 std::string errMessage = "";
1335 if (IsGroupCommonTask()) {
1336 errMessage = "taskpool:: groupTask cannot executeDelayed outside";
1337 HILOG_ERROR("%{public}s", errMessage.c_str());
1338 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1339 return false;
1340 }
1341 if (IsSeqRunnerTask()) {
1342 errMessage = "taskpool:: seqRunnerTask cannot executeDelayed outside";
1343 HILOG_ERROR("%{public}s", errMessage.c_str());
1344 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1345 return false;
1346 }
1347 if (IsCommonTask() && HasDependency()) {
1348 errMessage = "taskpool:: executedTask with dependency cannot executeDelayed again";
1349 HILOG_ERROR("%{public}s", errMessage.c_str());
1350 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1351 return false;
1352 }
1353 if (IsExecuted() && IsLongTask()) {
1354 errMessage = "taskpool:: Multiple executions of longTask are not supported in the executeDelayed";
1355 HILOG_ERROR("%{public}s", errMessage.c_str());
1356 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1357 return false;
1358 }
1359 if (IsPeriodicTask()) {
1360 errMessage = "taskpool:: the periodicTask cannot executeDelayed";
1361 HILOG_ERROR("%{public}s", errMessage.c_str());
1362 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1363 return false;
1364 }
1365 if (IsAsyncRunnerTask()) {
1366 errMessage = "AsyncRunnerTask cannot executeDelayed.";
1367 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1368 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1369 return false;
1370 }
1371 return true;
1372 }
1373
CanExecutePeriodically(napi_env env)1374 bool Task::CanExecutePeriodically(napi_env env)
1375 {
1376 if (IsAsyncRunnerTask()) {
1377 std::string errMessage = "AsyncRunnerTask cannot executePeriodically.";
1378 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1379 return false;
1380 }
1381 if (IsExecuted() || IsPeriodicTask()) {
1382 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_PERIODICALLY);
1383 return false;
1384 }
1385 if (HasDependency()) {
1386 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1387 "taskpool:: the task with dependency cannot executePeriodically");
1388 return false;
1389 }
1390 return true;
1391 }
1392
SetHasDependency(bool hasDependency)1393 void Task::SetHasDependency(bool hasDependency)
1394 {
1395 hasDependency_ = hasDependency;
1396 }
1397
HasDependency() const1398 bool Task::HasDependency() const
1399 {
1400 return hasDependency_;
1401 }
1402
TryClearHasDependency()1403 void Task::TryClearHasDependency()
1404 {
1405 HILOG_DEBUG("taskpool:: task:%{public}s TryClearHasDependency", std::to_string(taskId_).c_str());
1406 if (IsExecuted()) {
1407 HILOG_DEBUG("taskpool:: task TryClearHasDependency end, task is executed");
1408 return;
1409 }
1410 if ((!TaskManager::GetInstance().IsDependentByTaskId(taskId_)) &&
1411 (!TaskManager::GetInstance().IsDependendByTaskId(taskId_))) {
1412 SetHasDependency(false);
1413 }
1414 }
1415
ThrowNoDependencyError(napi_env env)1416 void Task::ThrowNoDependencyError(napi_env env)
1417 {
1418 std::string errMessage = "taskpool:: task has no dependency";
1419 HILOG_ERROR("%{public}s", errMessage.c_str());
1420 ErrorHelper::ThrowError(env, ErrorHelper::ERR_INEXISTENT_DEPENDENCY, errMessage.c_str());
1421 }
1422
UpdatePeriodicTask()1423 void Task::UpdatePeriodicTask()
1424 {
1425 taskType_ = TaskType::COMMON_TASK;
1426 napi_reference_ref(env_, taskRef_, nullptr);
1427 isPeriodicTask_ = true;
1428 }
1429
InitHandle(napi_env env)1430 void Task::InitHandle(napi_env env)
1431 {
1432 #if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1433 if (OHOS::AppExecFwk::EventRunner::IsAppMainThread()) {
1434 isMainThreadTask_ = true;
1435 return;
1436 }
1437 #endif
1438 uv_loop_t* loop = NapiHelper::GetLibUV(env);
1439 ConcurrentHelper::UvHandleInit(loop, onStartCancelSignal_, Task::Cancel);
1440 ConcurrentHelper::UvHandleInit(loop, onStartDiscardSignal_, Task::DiscardTask);
1441 auto engine = reinterpret_cast<NativeEngine*>(env);
1442 isMainThreadTask_ = engine->IsMainThread();
1443 }
1444
ClearDelayedTimers()1445 void Task::ClearDelayedTimers()
1446 {
1447 HILOG_DEBUG("taskpool:: task ClearDelayedTimers");
1448 std::list<napi_deferred> deferreds {};
1449 {
1450 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1451 TaskMessage* taskMessage = nullptr;
1452 for (auto t: delayedTimers_) {
1453 if (t == nullptr) {
1454 continue;
1455 }
1456 taskMessage = static_cast<TaskMessage*>(t->data);
1457 deferreds.push_back(taskMessage->deferred);
1458 uv_timer_stop(t);
1459 uv_close(reinterpret_cast<uv_handle_t*>(t), [](uv_handle_t* handle) {
1460 delete (uv_timer_t*)handle;
1461 handle = nullptr;
1462 });
1463 delete taskMessage;
1464 taskMessage = nullptr;
1465 }
1466 delayedTimers_.clear();
1467 }
1468 std::string error = "taskpool:: task has been canceled";
1469 TaskManager::GetInstance().BatchRejectDeferred(env_, deferreds, error);
1470 }
1471
VerifyAndPostResult(Task * task,Priority priority)1472 bool Task::VerifyAndPostResult(Task* task, Priority priority)
1473 {
1474 if (!task->IsMainThreadTask() && !task->IsValid()) {
1475 return false;
1476 }
1477
1478 auto taskId = task->GetTaskId();
1479 auto onResultTask = [taskId]([[maybe_unused]] void* data) {
1480 Task* hostTask = TaskManager::GetInstance().GetTask(taskId);
1481 if (hostTask == nullptr) { // LCOV_EXCL_BR_LINE
1482 return;
1483 }
1484 TaskPool::HandleTaskResult(hostTask);
1485 };
1486
1487 auto napiPrio = g_napiPriorityMap.at(priority);
1488 uint64_t handleId = 0;
1489 napi_status status = napi_send_cancelable_event(task->GetEnv(), onResultTask, nullptr, napiPrio,
1490 &handleId, ON_RESULT_STR);
1491 // should nerver access any data of the task when status is napi_ok
1492 if (status != napi_ok) {
1493 HILOG_ERROR("taskpool:: failed to send event for task:%{public}s", std::to_string(taskId).c_str());
1494 return false;
1495 }
1496 return true;
1497 }
1498
IncreaseTaskLifecycleCount()1499 void Task::IncreaseTaskLifecycleCount()
1500 {
1501 lifecycleCount_++; // when tasks are created or executed, lifecycleCount_ will increment
1502 }
1503
DecreaseTaskLifecycleCount()1504 void Task::DecreaseTaskLifecycleCount()
1505 {
1506 lifecycleCount_--; // when tasks finished, lifecycleCount_ will decrement
1507 }
1508
ShouldDeleteTask(bool needUnref)1509 bool Task::ShouldDeleteTask(bool needUnref)
1510 {
1511 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1512 if (!IsValid()) {
1513 HILOG_WARN("taskpool:: task is invalid");
1514 if (IsAsyncRunnerTask()) {
1515 AsyncRunnerManager::GetInstance().DecreaseRunningCount(asyncRunnerId_);
1516 }
1517 TaskManager::GetInstance().RemoveTask(taskId_);
1518 return true;
1519 }
1520 if (needUnref) {
1521 if (IsAsyncRunnerTask()) {
1522 AsyncRunnerManager::GetInstance().DecreaseRunningCount(asyncRunnerId_);
1523 }
1524 DecreaseTaskLifecycleCount();
1525 }
1526 return false;
1527 }
1528
CheckStartExecution(Priority priority)1529 bool Task::CheckStartExecution(Priority priority)
1530 {
1531 #if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1532 if (IsMainThreadTask()) {
1533 if (onStartExecutionCallBackInfo_ == nullptr) {
1534 return true;
1535 }
1536 HITRACE_HELPER_METER_NAME("PerformTask: PostTask");
1537 uint32_t taskId = taskId_;
1538 auto onStartExecutionTask = [taskId]() {
1539 Task* task = TaskManager::GetInstance().GetTask(taskId);
1540 if (task == nullptr || task->onStartExecutionCallBackInfo_ == nullptr) {
1541 return;
1542 }
1543 Task::StartExecutionTask(task->onStartExecutionCallBackInfo_);
1544 };
1545 TaskManager::GetInstance().PostTask(onStartExecutionTask, "TaskPoolOnStartExecutionTask", priority);
1546 } else {
1547 if (onStartExecutionSignal_ == nullptr) {
1548 return true;
1549 }
1550 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1551 if (!IsValid()) {
1552 return false;
1553 }
1554 ConcurrentHelper::UvCheckAndAsyncSend(onStartExecutionSignal_);
1555 }
1556 return true;
1557 #else
1558 if (onStartExecutionSignal_ == nullptr) {
1559 return true;
1560 }
1561 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1562 if (!IsValid()) {
1563 return false;
1564 }
1565 ConcurrentHelper::UvCheckAndAsyncSend(onStartExecutionSignal_);
1566 return true;
1567 #endif
1568 }
1569
SetValid(bool isValid)1570 void Task::SetValid(bool isValid)
1571 {
1572 isValid_.store(isValid);
1573 }
1574
IsValid()1575 bool Task::IsValid()
1576 {
1577 return isValid_.load();
1578 }
1579
CanForAsyncRunner(napi_env env)1580 bool Task::CanForAsyncRunner(napi_env env)
1581 {
1582 std::string errMessage = "";
1583 if (HasDependency()) {
1584 errMessage = "AsyncRunner:: dependent task not allowed.";
1585 HILOG_ERROR("%{public}s", errMessage.c_str());
1586 ErrorHelper::ThrowError(env, ErrorHelper::ERR_ADD_DEPENDENT_TASK_TO_SEQRUNNER, errMessage.c_str());
1587 return false;
1588 }
1589 if (IsPeriodicTask()) {
1590 errMessage = "AsyncRunner cannot execute the periodicTask.";
1591 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1592 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1593 return false;
1594 }
1595 if (IsCommonTask() || IsSeqRunnerTask()) {
1596 errMessage = "AsyncRunner cannot execute seqRunnerTask or executedTask.";
1597 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1598 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1599 return false;
1600 }
1601 if (IsGroupCommonTask()) {
1602 errMessage = "AsyncRunner cannot execute groupTask.";
1603 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1604 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1605 return false;
1606 }
1607 if (IsAsyncRunnerTask()) {
1608 errMessage = "AsyncRunner cannot execute asyncRunnerTask.";
1609 HILOG_ERROR("taskpool:: %{public}s", errMessage.c_str());
1610 ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_CANNOT_EXECUTED, errMessage.c_str());
1611 return false;
1612 }
1613 return true;
1614 }
1615
IsAsyncRunnerTask()1616 bool Task::IsAsyncRunnerTask()
1617 {
1618 return taskType_ == TaskType::ASYNCRUNNER_TASK;
1619 }
1620
SetTaskId(uint32_t taskId)1621 void Task::SetTaskId(uint32_t taskId)
1622 {
1623 taskId_ = taskId;
1624 }
1625
TriggerCancel(CancelTaskMessage * message)1626 void Task::TriggerCancel(CancelTaskMessage* message)
1627 {
1628 #if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1629 if (IsMainThreadTask()) {
1630 HITRACE_HELPER_METER_NAME("TriggerCancel: PostTask");
1631 auto onCancelTask = [message]() {
1632 Task* task = TaskManager::GetInstance().GetTask(message->taskId);
1633 if (task == nullptr) {
1634 CloseHelp::DeletePointer(message, false);
1635 return;
1636 }
1637 napi_status status = napi_ok;
1638 HandleScope scope(task->env_, status);
1639 if (status != napi_ok) {
1640 HILOG_ERROR("taskpool:: napi_open_handle_scope failed");
1641 CloseHelp::DeletePointer(message, false);
1642 return;
1643 }
1644 task->CancelInner(message->state);
1645 CloseHelp::DeletePointer(message, false);
1646 };
1647 TaskManager::GetInstance().PostTask(onCancelTask, "TaskOnCancelTask", Priority::DEFAULT);
1648 } else {
1649 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1650 if (!IsValid() || !ConcurrentHelper::IsUvActive(onStartCancelSignal_)) {
1651 return;
1652 }
1653 onStartCancelSignal_->data = message;
1654 uv_async_send(onStartCancelSignal_);
1655 }
1656 #else
1657 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1658 if (!IsValid() || !ConcurrentHelper::IsUvActive(onStartCancelSignal_)) {
1659 CloseHelp::DeletePointer(message, false);
1660 return;
1661 }
1662 onStartCancelSignal_->data = message;
1663 uv_async_send(onStartCancelSignal_);
1664 #endif
1665 }
1666
CancelInner(ExecuteState state)1667 void Task::CancelInner(ExecuteState state)
1668 {
1669 ClearDelayedTimers();
1670 CancelPendingTask(env_);
1671 if (HasDependency()) {
1672 TaskManager::GetInstance().ClearDependentTask(taskId_);
1673 }
1674 std::list<napi_deferred> deferreds {};
1675 std::string error = "taskpool:: task has been canceled";
1676 {
1677 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1678 if (state == ExecuteState::WAITING && currentTaskInfo_ != nullptr &&
1679 TaskManager::GetInstance().EraseWaitingTaskId(taskId_, currentTaskInfo_->priority)) {
1680 reinterpret_cast<NativeEngine*>(env_)->DecreaseSubEnvCounter();
1681 DecreaseTaskLifecycleCount();
1682 TaskManager::GetInstance().DecreaseSendDataRefCount(env_, taskId_);
1683 deferreds.push_back(currentTaskInfo_->deferred);
1684 napi_reference_unref(env_, taskRef_, nullptr);
1685 delete currentTaskInfo_;
1686 currentTaskInfo_ = nullptr;
1687 isCancelToFinish_ = true;
1688 }
1689 if (IsSeqRunnerTask() && state == ExecuteState::CANCELED) {
1690 if (currentTaskInfo_ != nullptr) {
1691 deferreds.push_back(currentTaskInfo_->deferred);
1692 error = "taskpool:: sequenceRunner task has been canceled";
1693 }
1694 DisposeCanceledTask();
1695 }
1696 if (state == ExecuteState::DELAYED) {
1697 isCancelToFinish_ = true;
1698 }
1699 }
1700
1701 TaskManager::GetInstance().BatchRejectDeferred(env_, deferreds, error);
1702 }
1703
IsSameEnv(napi_env env)1704 bool Task::IsSameEnv(napi_env env)
1705 {
1706 return env_ == env;
1707 }
1708
DiscardAsyncRunnerTask(DiscardTaskMessage * message)1709 void Task::DiscardAsyncRunnerTask(DiscardTaskMessage* message)
1710 {
1711 if (message == nullptr || !IsAsyncRunnerTask() || !IsValid()) {
1712 CloseHelp::DeletePointer(message, false);
1713 return;
1714 }
1715 #if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1716 if (IsMainThreadTask()) {
1717 HITRACE_HELPER_METER_NAME("DiscardAsyncRunnerTask: PostTask");
1718 auto onDiscardTask = [message]() {
1719 Task* task = TaskManager::GetInstance().GetTask(message->taskId);
1720 if (task == nullptr) {
1721 CloseHelp::DeletePointer(message, false);
1722 return;
1723 }
1724 napi_status status = napi_ok;
1725 HandleScope scope(task->env_, status);
1726 if (status != napi_ok) {
1727 CloseHelp::DeletePointer(message, false);
1728 HILOG_ERROR("taskpool:: napi_open_handle_scope failed");
1729 return;
1730 }
1731 task->DiscardInner(message);
1732 };
1733 TaskManager::GetInstance().PostTask(onDiscardTask, "TaskOnDiscardTask", Priority::DEFAULT);
1734 } else {
1735 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1736 if (ConcurrentHelper::IsUvActive(onStartDiscardSignal_)) {
1737 onStartDiscardSignal_->data = message;
1738 uv_async_send(onStartDiscardSignal_);
1739 }
1740 }
1741 #else
1742 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1743 if (ConcurrentHelper::IsUvActive(onStartDiscardSignal_)) {
1744 onStartDiscardSignal_->data = message;
1745 uv_async_send(onStartDiscardSignal_);
1746 }
1747 #endif
1748 }
1749
DiscardInner(DiscardTaskMessage * message)1750 void Task::DiscardInner(DiscardTaskMessage* message)
1751 {
1752 if (message == nullptr) {
1753 CloseHelp::DeletePointer(message, false);
1754 return;
1755 }
1756 auto task = TaskManager::GetInstance().GetTask(message->taskId);
1757 if (task == nullptr || !task->IsValid() || message->env != task->env_) {
1758 CloseHelp::DeletePointer(message, false);
1759 HILOG_DEBUG("taskpool:: discard task is nullptr.");
1760 return;
1761 }
1762 napi_value error = nullptr;
1763 if (message->errCode == ErrorHelper::ERR_ASYNCRUNNER_TASK_CANCELED) {
1764 error = TaskManager::GetInstance().CancelError(task->env_, message->errCode);
1765 } else {
1766 error = ErrorHelper::NewError(task->env_, message->errCode);
1767 }
1768 napi_reject_deferred(task->env_, task->currentTaskInfo_->deferred, error);
1769 DisposeCanceledTask();
1770 TaskManager::GetInstance().RemoveTask(message->taskId);
1771
1772 CloseHelp::DeletePointer(message, false);
1773 }
1774
DiscardTask(const uv_async_t * req)1775 void Task::DiscardTask(const uv_async_t* req)
1776 {
1777 auto message = static_cast<DiscardTaskMessage*>(req->data);
1778 if (message == nullptr) {
1779 return;
1780 }
1781 auto task = TaskManager::GetInstance().GetTask(message->taskId);
1782 if (task == nullptr || task->env_ != message->env) {
1783 CloseHelp::DeletePointer(message, false);
1784 HILOG_DEBUG("taskpool:: task is nullptr.");
1785 return;
1786 }
1787 napi_status status = napi_ok;
1788 HandleScope scope(task->env_, status);
1789 if (status != napi_ok) {
1790 CloseHelp::DeletePointer(message, false);
1791 HILOG_ERROR("taskpool:: napi_open_handle_scope failed");
1792 return;
1793 }
1794
1795 task->DiscardInner(message);
1796 }
1797
ReleaseData()1798 void Task::ReleaseData()
1799 {
1800 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1801 if (onStartCancelSignal_ != nullptr) {
1802 if (!ConcurrentHelper::IsUvClosing(onStartCancelSignal_)) {
1803 ConcurrentHelper::UvHandleClose(onStartCancelSignal_);
1804 } else {
1805 delete onStartCancelSignal_;
1806 onStartCancelSignal_ = nullptr;
1807 }
1808 }
1809
1810 if (onStartDiscardSignal_ != nullptr) {
1811 if (!ConcurrentHelper::IsUvClosing(onStartDiscardSignal_)) {
1812 ConcurrentHelper::UvHandleClose(onStartDiscardSignal_);
1813 } else {
1814 delete onStartDiscardSignal_;
1815 onStartDiscardSignal_ = nullptr;
1816 }
1817 }
1818
1819 if (currentTaskInfo_ != nullptr) {
1820 delete currentTaskInfo_;
1821 currentTaskInfo_ = nullptr;
1822 }
1823 }
1824
DisposeCanceledTask()1825 void Task::DisposeCanceledTask()
1826 {
1827 reinterpret_cast<NativeEngine*>(env_)->DecreaseSubEnvCounter();
1828 napi_reference_unref(env_, taskRef_, nullptr);
1829 delete currentTaskInfo_;
1830 currentTaskInfo_ = nullptr;
1831 }
1832
GetWorker() const1833 Worker* Task::GetWorker() const
1834 {
1835 return static_cast<Worker*>(worker_);
1836 }
1837
GetEnv() const1838 napi_env Task::GetEnv() const
1839 {
1840 return env_;
1841 }
1842
GetTaskId() const1843 uint32_t Task::GetTaskId() const
1844 {
1845 return taskId_;
1846 }
1847
IsRealyCanceled()1848 bool Task::IsRealyCanceled()
1849 {
1850 return taskState_ == ExecuteState::CANCELED && isCancelToFinish_;
1851 }
1852
UpdateTaskStateToWaiting()1853 bool Task::UpdateTaskStateToWaiting()
1854 {
1855 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1856 if (IsAsyncRunnerTask() || IsSeqRunnerTask()) {
1857 if (taskState_ == ExecuteState::NOT_FOUND) {
1858 taskState_ = ExecuteState::WAITING;
1859 return true;
1860 }
1861 return false;
1862 }
1863 if (IsPeriodicTask()) {
1864 if (taskState_ == ExecuteState::NOT_FOUND || taskState_ == ExecuteState::FINISHED) {
1865 taskState_ = ExecuteState::WAITING;
1866 return true;
1867 }
1868 return false;
1869 }
1870 if (taskState_ == ExecuteState::NOT_FOUND || taskState_ == ExecuteState::FINISHED ||
1871 IsRealyCanceled()) {
1872 taskState_ = ExecuteState::WAITING;
1873 return true;
1874 }
1875 return false;
1876 }
1877
UpdateTaskStateToRunning()1878 bool Task::UpdateTaskStateToRunning()
1879 {
1880 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1881 if (taskState_ != ExecuteState::CANCELED) {
1882 taskState_ = ExecuteState::RUNNING;
1883 return true;
1884 }
1885 return false;
1886 }
1887
UpdateTaskStateToCanceled()1888 bool Task::UpdateTaskStateToCanceled()
1889 {
1890 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1891 if (IsPeriodicTask()) {
1892 taskState_ = ExecuteState::CANCELED;
1893 return true;
1894 }
1895 if (taskState_ == ExecuteState::NOT_FOUND || taskState_ == ExecuteState::FINISHED ||
1896 taskState_ == ExecuteState::CANCELED || taskState_ == ExecuteState::ENDING) {
1897 taskState_ = ExecuteState::WAITING;
1898 return false;
1899 }
1900 taskState_ = ExecuteState::CANCELED;
1901 return true;
1902 }
1903
UpdateTaskStateToFinished()1904 bool Task::UpdateTaskStateToFinished()
1905 {
1906 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1907 if (taskState_ == ExecuteState::ENDING) {
1908 taskState_ = ExecuteState::FINISHED;
1909 return true;
1910 }
1911 return false;
1912 }
1913
UpdateTaskStateToDelayed()1914 bool Task::UpdateTaskStateToDelayed()
1915 {
1916 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1917 if (!IsExecuted() || IsRealyCanceled() || taskState_ == ExecuteState::FINISHED) {
1918 taskState_ = ExecuteState::DELAYED;
1919 return true;
1920 }
1921 return false;
1922 }
1923
UpdateTaskStateToEnding()1924 bool Task::UpdateTaskStateToEnding()
1925 {
1926 std::lock_guard<std::recursive_mutex> lock(taskMutex_);
1927 if (taskState_ == ExecuteState::RUNNING ||
1928 (taskState_ == ExecuteState::CANCELED && !IsPeriodicTask())) {
1929 taskState_ = ExecuteState::ENDING;
1930 return true;
1931 }
1932 return false;
1933 }
1934
GetSerializeParams(napi_env env,napi_value napiTask)1935 std::tuple<napi_value, napi_value, napi_value, napi_value> Task::GetSerializeParams(napi_env env, napi_value napiTask)
1936 {
1937 napi_value func = NapiHelper::GetNameProperty(env, napiTask, FUNCTION_STR);
1938 napi_value args = NapiHelper::GetNameProperty(env, napiTask, ARGUMENTS_STR);
1939 if (func == nullptr || args == nullptr) {
1940 std::string errMessage = "taskpool:: task value is error";
1941 HILOG_ERROR("%{public}s", errMessage.c_str());
1942 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1943 return {nullptr, nullptr, nullptr, nullptr};
1944 }
1945 napi_value transferList = NapiHelper::GetUndefinedValue(env);
1946 if (NapiHelper::HasNameProperty(env, napiTask, TRANSFERLIST_STR)) {
1947 transferList = NapiHelper::GetNameProperty(env, napiTask, TRANSFERLIST_STR);
1948 }
1949 napi_value cloneList = NapiHelper::GetUndefinedValue(env);
1950 if (NapiHelper::HasNameProperty(env, napiTask, CLONE_LIST_STR)) {
1951 cloneList = NapiHelper::GetNameProperty(env, napiTask, CLONE_LIST_STR);
1952 }
1953 return {func, args, transferList, cloneList};
1954 }
1955
GetSerializeResult(napi_env env,napi_value func,napi_value args,std::tuple<napi_value,napi_value,bool,bool> transferAndCloneParams)1956 std::tuple<void*, void*> Task::GetSerializeResult(napi_env env, napi_value func, napi_value args,
1957 std::tuple<napi_value, napi_value, bool, bool> transferAndCloneParams)
1958 {
1959 auto [transferList, cloneList, defaultTransfer, defaultCloneSendable] = transferAndCloneParams;
1960 napi_value undefined = NapiHelper::GetUndefinedValue(env);
1961 void* serializationFunction = nullptr;
1962 std::string errString = "";
1963 napi_status status = napi_serialize_inner_with_error(env, func, undefined, undefined, defaultTransfer,
1964 defaultCloneSendable, &serializationFunction, errString);
1965 std::string errMessage = "";
1966 if (status != napi_ok || serializationFunction == nullptr) {
1967 errMessage = "taskpool: failed to serialize function.\nSerialize error: " + errString;
1968 HILOG_ERROR("%{public}s", errMessage.c_str());
1969 ErrorHelper::ThrowError(env, ErrorHelper::ERR_NOT_CONCURRENT_FUNCTION, errMessage.c_str());
1970 return {nullptr, nullptr};
1971 }
1972 void* serializationArguments = nullptr;
1973 errMessage = "";
1974 status = napi_serialize_inner_with_error(env, args, transferList, cloneList, defaultTransfer,
1975 defaultCloneSendable, &serializationArguments, errString);
1976 if (status != napi_ok || serializationArguments == nullptr) { // LOCV_EXCL_BR_LINE
1977 errMessage = "taskpool: failed to serialize arguments.\nSerialize error: " + errString;
1978 HILOG_ERROR("%{public}s", errMessage.c_str());
1979 ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
1980 return {nullptr, nullptr};
1981 }
1982 return {serializationFunction, serializationArguments};
1983 }
1984 } // namespace Commonlibrary::Concurrent::TaskPoolModule