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 "helper/error_helper.h"
19#include "helper/napi_helper.h"
20#include "helper/object_helper.h"
21#include "helper/hitrace_helper.h"
22#include "task_manager.h"
23#include "taskpool.h"
24#include "tools/log.h"
25#include "worker.h"
26
27namespace Commonlibrary::Concurrent::TaskPoolModule {
28static constexpr char ONRECEIVEDATA_STR[] = "onReceiveData";
29static constexpr char SETTRANSFERLIST_STR[] = "setTransferList";
30static constexpr char SET_CLONE_LIST_STR[] = "setCloneList";
31static constexpr char ONENQUEUED_STR[] = "onEnqueued";
32static constexpr char ONSTARTEXECUTION_STR[] = "onStartExecution";
33static constexpr char ONEXECUTIONFAILED_STR[] = "onExecutionFailed";
34static constexpr char ONEXECUTIONSUCCEEDED_STR[] = "onExecutionSucceeded";
35static constexpr char ISDONE_STR[] = "isDone";
36
37using namespace Commonlibrary::Concurrent::Common::Helper;
38
39Task::Task(napi_env env, TaskType taskType, std::string name) : env_(env), taskType_(taskType), name_(name) {}
40
41napi_value Task::TaskConstructor(napi_env env, napi_callback_info cbinfo)
42{
43    // check argv count
44    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
45    std::string errMessage = "";
46    if (argc < 1) {
47        errMessage = "taskpool:: create task need more than one param";
48        HILOG_ERROR("%{public}s", errMessage.c_str());
49        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
50        return nullptr;
51    }
52    napi_value* args = new napi_value[argc];
53    ObjectScope<napi_value> scope(args, true);
54    napi_value thisVar = nullptr;
55    napi_value func = nullptr;
56    napi_value name = nullptr;
57    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
58    // if the first is task name, the second might be func
59    if (argc > 1 && NapiHelper::IsString(env, args[0])) {
60        name = args[0];
61        func = args[1];
62        args += 2; // 2: name and func
63        argc -= 2; // 2: name and func
64    } else {
65        func = args[0];
66        args += 1; // 1: func
67        argc -= 1; // 1: func
68    }
69    if (!NapiHelper::IsFunction(env, func)) {
70        errMessage = "taskpool:: the first or second param of task must be function";
71        HILOG_ERROR("%{public}s", errMessage.c_str());
72        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
73            "the type of the first or second param of task must be function.");
74        return nullptr;
75    }
76
77    Task* task = GenerateTask(env, thisVar, func, name, args, argc);
78    TaskManager::GetInstance().StoreTask(task->taskId_, task);
79    napi_wrap(env, thisVar, task, TaskDestructor, nullptr, nullptr);
80    napi_create_reference(env, thisVar, 0, &task->taskRef_);
81    if (!task->IsMainThreadTask()) {
82        napi_add_env_cleanup_hook(env, Task::CleanupHookFunc, task);
83    }
84    return thisVar;
85}
86
87napi_value Task::LongTaskConstructor(napi_env env, napi_callback_info cbinfo)
88{
89    auto thisVar = TaskConstructor(env, cbinfo);
90    Task* task;
91    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
92    task->isLongTask_ = true;
93    return thisVar;
94}
95
96void Task::TaskDestructor(napi_env env, void* data, [[maybe_unused]] void* hint)
97{
98    Task* task = static_cast<Task*>(data);
99    HILOG_INFO("taskpool:: taskId:%{public}s TaskDestructor", std::to_string(task->taskId_).c_str());
100    if (!task->IsMainThreadTask()) {
101        napi_remove_env_cleanup_hook(env, Task::CleanupHookFunc, task);
102    }
103    // for performance, do not lock first
104    if (task->IsMainThreadTask() || task->refCount_ == 0) {
105        TaskManager::GetInstance().ReleaseTaskData(env, task);
106        napi_delete_reference(env, task->taskRef_);
107        delete task;
108        return;
109    }
110    bool shouldDelete = false;
111    {
112        std::lock_guard<RECURSIVE_MUTEX> lock(task->taskMutex_);
113        task->SetValid(false);
114        if (task->refCount_ == 0) {
115            shouldDelete = true;
116        }
117        TaskManager::GetInstance().ReleaseTaskData(env, task, shouldDelete);
118        napi_delete_reference(env, task->taskRef_);
119    }
120    if (shouldDelete) {
121        delete task;
122    }
123}
124
125void Task::CleanupHookFunc(void* arg)
126{
127    if (arg == nullptr) {
128        HILOG_ERROR("taskpool:: cleanupHook arg is nullptr");
129        return;
130    }
131    Task* task = static_cast<Task*>(arg);
132    std::lock_guard<RECURSIVE_MUTEX> lock(task->taskMutex_);
133    if (task->onResultSignal_ != nullptr) {
134        uv_close(reinterpret_cast<uv_handle_t*>(task->onResultSignal_), nullptr);
135    }
136    if (task->onStartExecutionSignal_ != nullptr) {
137        uv_close(reinterpret_cast<uv_handle_t*>(task->onStartExecutionSignal_), nullptr);
138    }
139    if (task->IsFunctionTask()) {
140        task->SetValid(false);
141    }
142}
143
144Task* Task::GenerateTask(napi_env env, napi_value napiTask, napi_value func,
145                         napi_value name, napi_value* args, size_t argc)
146{
147    HILOG_DEBUG("taskpool:: task GenerateTask");
148    napi_value argsArray = NapiHelper::CreateArrayWithLength(env, argc);
149    for (size_t i = 0; i < argc; i++) {
150        napi_set_element(env, argsArray, i, args[i]);
151    }
152    if (name == nullptr) {
153        name = NapiHelper::GetNameProperty(env, func, NAME);
154    }
155    char* nameStr = NapiHelper::GetChars(env, name);
156    Task* task = new Task(env, TaskType::TASK, nameStr);
157    delete[] nameStr;
158    task->taskId_ = reinterpret_cast<uint64_t>(task);
159    task->InitHandle(env);
160
161    napi_value taskId = NapiHelper::CreateUint64(env, task->taskId_);
162    napi_set_named_property(env, napiTask, FUNCTION_STR, func);
163    napi_set_named_property(env, napiTask, TASKID_STR, taskId);
164    napi_set_named_property(env, napiTask, ARGUMENTS_STR, argsArray);
165    napi_property_descriptor properties[] = {
166        DECLARE_NAPI_FUNCTION(SETTRANSFERLIST_STR, SetTransferList),
167        DECLARE_NAPI_FUNCTION(SET_CLONE_LIST_STR, SetCloneList),
168        DECLARE_NAPI_FUNCTION(ONRECEIVEDATA_STR, OnReceiveData),
169        DECLARE_NAPI_FUNCTION(ADD_DEPENDENCY_STR, AddDependency),
170        DECLARE_NAPI_FUNCTION(REMOVE_DEPENDENCY_STR, RemoveDependency),
171        DECLARE_NAPI_FUNCTION(ONENQUEUED_STR, OnEnqueued),
172        DECLARE_NAPI_FUNCTION(ONSTARTEXECUTION_STR, OnStartExecution),
173        DECLARE_NAPI_FUNCTION(ONEXECUTIONFAILED_STR, OnExecutionFailed),
174        DECLARE_NAPI_FUNCTION(ONEXECUTIONSUCCEEDED_STR, OnExecutionSucceeded),
175        DECLARE_NAPI_FUNCTION(ISDONE_STR, IsDone),
176        DECLARE_NAPI_GETTER(TASK_TOTAL_TIME, GetTotalDuration),
177        DECLARE_NAPI_GETTER(TASK_CPU_TIME, GetCPUDuration),
178        DECLARE_NAPI_GETTER(TASK_IO_TIME, GetIODuration),
179        DECLARE_NAPI_GETTER(NAME, GetName)
180    };
181    napi_define_properties(env, napiTask, sizeof(properties) / sizeof(properties[0]), properties);
182    return task;
183}
184
185Task* Task::GenerateFunctionTask(napi_env env, napi_value func, napi_value* args, size_t argc, TaskType type)
186{
187    HILOG_DEBUG("taskpool:: task GenerateFunctionTask");
188    napi_value argsArray;
189    napi_create_array_with_length(env, argc, &argsArray);
190    for (size_t i = 0; i < argc; i++) {
191        napi_set_element(env, argsArray, i, args[i]);
192    }
193    napi_value undefined = NapiHelper::GetUndefinedValue(env);
194    TaskInfo* taskInfo = GenerateTaskInfo(env, func, argsArray, undefined, undefined, Priority::DEFAULT);
195    if (taskInfo == nullptr) {
196        HILOG_ERROR("taskpool:: task GenerateFunctionTask end, taskInfo is nullptr");
197        return nullptr;
198    }
199    napi_value napiFuncName = NapiHelper::GetNameProperty(env, func, NAME);
200    char* nameStr = NapiHelper::GetChars(env, napiFuncName);
201    Task* task = new Task(env, type, nameStr);
202    delete[] nameStr;
203    task->taskId_ = reinterpret_cast<uint64_t>(task);
204    task->currentTaskInfo_ = taskInfo;
205    task->InitHandle(env);
206    if (!task->IsMainThreadTask()) {
207        napi_add_env_cleanup_hook(env, CleanupHookFunc, task);
208    }
209    return task;
210}
211
212napi_value Task::GetTaskInfoPromise(napi_env env, napi_value task, TaskType taskType, Priority priority)
213{
214    TaskInfo* taskInfo = GetTaskInfo(env, task, priority);
215    if (taskInfo == nullptr) {
216        return nullptr;
217    }
218    UpdateTaskType(taskType);
219    return NapiHelper::CreatePromise(env, &taskInfo->deferred);
220}
221
222TaskInfo* Task::GetTaskInfo(napi_env env, napi_value napiTask, Priority priority)
223{
224    napi_value func = NapiHelper::GetNameProperty(env, napiTask, FUNCTION_STR);
225    napi_value args = NapiHelper::GetNameProperty(env, napiTask, ARGUMENTS_STR);
226    if (func == nullptr || args == nullptr) {
227        std::string errMessage = "taskpool:: task value is error";
228        HILOG_ERROR("%{public}s", errMessage.c_str());
229        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
230        return nullptr;
231    }
232    napi_value transferList = NapiHelper::GetUndefinedValue(env);
233    if (NapiHelper::HasNameProperty(env, napiTask, TRANSFERLIST_STR)) {
234        transferList = NapiHelper::GetNameProperty(env, napiTask, TRANSFERLIST_STR);
235    }
236    napi_value cloneList = NapiHelper::GetUndefinedValue(env);
237    if (NapiHelper::HasNameProperty(env, napiTask, CLONE_LIST_STR)) {
238        cloneList = NapiHelper::GetNameProperty(env, napiTask, CLONE_LIST_STR);
239    }
240    TaskInfo* pendingInfo = GenerateTaskInfo(env, func, args, transferList, cloneList, priority,
241                                             defaultTransfer_, defaultCloneSendable_);
242    if (pendingInfo == nullptr) {
243        return nullptr;
244    }
245    {
246        std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
247        if (currentTaskInfo_ == nullptr) {
248            currentTaskInfo_ = pendingInfo;
249        } else {
250            pendingTaskInfos_.push_back(pendingInfo);
251        }
252    }
253    if (name_.empty()) {
254        napi_value funcName = NapiHelper::GetNameProperty(env, func, NAME);
255        name_ = NapiHelper::GetString(env, funcName);
256    }
257    return pendingInfo;
258}
259
260napi_value Task::SetTransferList(napi_env env, napi_callback_info cbinfo)
261{
262    size_t argc = 1;
263    napi_value args[1];
264    napi_value thisVar;
265    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
266    // Check whether clone list has been set
267    if (NapiHelper::HasNameProperty(env, thisVar, CLONE_LIST_STR)) {
268        ErrorHelper::ThrowError(env, ErrorHelper::ERR_IN_BOTH_CLONE_AND_TRANSFER);
269        return nullptr;
270    }
271    if (argc > 1) {
272        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
273            "the number of setTransferList parma must be less than 2.");
274        return nullptr;
275    }
276    Task* task = nullptr;
277    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
278    if (task == nullptr) {
279        HILOG_ERROR("taskpool:: task is nullptr");
280        return nullptr;
281    }
282    napi_value undefined = NapiHelper::GetUndefinedValue(env);
283    napi_value falseVal = NapiHelper::CreateBooleanValue(env, false);
284    if (argc == 0) {
285        HILOG_DEBUG("taskpool:: set task params not transfer");
286        napi_set_named_property(env, thisVar, TRANSFERLIST_STR, undefined);
287        // set task.defaultTransfer false
288        task->defaultTransfer_ = false;
289        return nullptr;
290    }
291    if (!NapiHelper::IsArray(env, args[0])) {
292        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
293            "the type of setTransferList first param must be array.");
294        return nullptr;
295    }
296    // set task.defaultTransfer false
297    task->defaultTransfer_ = false;
298    uint32_t arrayLength = NapiHelper::GetArrayLength(env, args[0]);
299    if (arrayLength == 0) {
300        HILOG_DEBUG("taskpool:: set task params not transfer");
301        napi_set_named_property(env, thisVar, TRANSFERLIST_STR, undefined);
302        return nullptr;
303    }
304    for (size_t i = 0; i < arrayLength; i++) {
305        napi_value transferVal = NapiHelper::GetElement(env, args[0], i);
306        if (!NapiHelper::IsArrayBuffer(env, transferVal)) {
307            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
308                "the type of the element in array must be arraybuffer.");
309            return nullptr;
310        }
311    }
312    HILOG_DEBUG("taskpool:: check setTransferList param success");
313    napi_set_named_property(env, thisVar, TRANSFERLIST_STR, args[0]);
314    return nullptr;
315}
316
317napi_value Task::SetCloneList(napi_env env, napi_callback_info cbinfo)
318{
319    size_t argc = 1;
320    napi_value args[1];
321    napi_value thisVar;
322    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
323    // Check whether transfer list has been set
324    if (NapiHelper::HasNameProperty(env, thisVar, TRANSFERLIST_STR)) {
325        ErrorHelper::ThrowError(env, ErrorHelper::ERR_IN_BOTH_CLONE_AND_TRANSFER);
326        return nullptr;
327    }
328    if (argc != 1) {
329        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of setCloneList parma must be 1.");
330        return nullptr;
331    }
332    if (!NapiHelper::IsArray(env, args[0])) {
333        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of setCloneList first param must be array.");
334        return nullptr;
335    }
336    Task* task = nullptr;
337    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
338    if (task == nullptr) {
339        HILOG_ERROR("taskpool:: task is nullptr");
340        return nullptr;
341    }
342    napi_value undefined = NapiHelper::GetUndefinedValue(env);
343    uint32_t arrayLength = NapiHelper::GetArrayLength(env, args[0]);
344    if (arrayLength == 0) {
345        HILOG_DEBUG("taskpool:: clone list is empty");
346        napi_set_named_property(env, thisVar, CLONE_LIST_STR, undefined);
347        return nullptr;
348    }
349    for (size_t i = 0; i < arrayLength; i++) {
350        napi_value cloneVal = NapiHelper::GetElement(env, args[0], i);
351        if (!NapiHelper::IsArrayBuffer(env, cloneVal) && !NapiHelper::IsSendable(env, cloneVal)) {
352            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
353                "the type of setCloneList elements in array must be arraybuffer or sendable.");
354            return nullptr;
355        }
356    }
357    napi_set_named_property(env, thisVar, CLONE_LIST_STR, args[0]);
358    return nullptr;
359}
360
361napi_value Task::IsCanceled(napi_env env, napi_callback_info cbinfo)
362{
363    bool isCanceled = false;
364    auto engine = reinterpret_cast<NativeEngine*>(env);
365    if (!engine->IsTaskPoolThread()) {
366        HILOG_ERROR("taskpool:: call isCanceled not in taskpool thread");
367        return NapiHelper::CreateBooleanValue(env, isCanceled);
368    }
369    // Get task and query task cancel state
370    void* data = engine->GetCurrentTaskInfo();
371    if (data == nullptr) {
372        HILOG_ERROR("taskpool:: call isCanceled not in Concurrent function");
373    } else {
374        Task* task = static_cast<Task*>(data);
375        isCanceled = task->taskState_ == ExecuteState::CANCELED ? true : false;
376    }
377    return NapiHelper::CreateBooleanValue(env, isCanceled);
378}
379
380napi_value Task::OnReceiveData(napi_env env, napi_callback_info cbinfo)
381{
382    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
383    if (argc >= 2) { // 2: the number of parmas
384        HILOG_ERROR("taskpool:: the number of OnReceiveData parma must be less than 2");
385        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
386            "the number of OnReceiveData parma must be less than 2.");
387        return nullptr;
388    }
389
390    napi_value thisVar;
391    if (argc == 0) {
392        HILOG_INFO("taskpool:: Set taskpool.Task.onReceiveData to undefined");
393        napi_get_cb_info(env, cbinfo, &argc, nullptr, &thisVar, nullptr);
394        napi_value id = NapiHelper::GetNameProperty(env, thisVar, "taskId");
395        uint64_t taskId = NapiHelper::GetUint64Value(env, id);
396        TaskManager::GetInstance().RegisterCallback(env, taskId, nullptr);
397        return nullptr;
398    }
399
400    napi_value args[1];
401    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
402    napi_valuetype type;
403    NAPI_CALL(env, napi_typeof(env, args[0], &type));
404    if (type != napi_function) {
405        HILOG_ERROR("taskpool:: OnReceiveData's parameter should be function");
406        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
407            "the type of onReceiveData's parameter must be function.");
408        return nullptr;
409    }
410    // store callbackInfo
411    napi_value napiTaskId = NapiHelper::GetNameProperty(env, thisVar, "taskId");
412    uint64_t taskId = NapiHelper::GetUint64Value(env, napiTaskId);
413    napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
414    auto task = TaskManager::GetInstance().GetTask(taskId);
415    std::shared_ptr<CallbackInfo> callbackInfo = std::make_shared<CallbackInfo>(env, 1, callbackRef, task);
416#if defined(ENABLE_TASKPOOL_EVENTHANDLER)
417    if (!task->IsMainThreadTask()) {
418        auto loop = NapiHelper::GetLibUV(env);
419        ConcurrentHelper::UvHandleInit(loop, callbackInfo->onCallbackSignal, TaskPool::ExecuteCallback);
420    }
421#else
422    auto loop = NapiHelper::GetLibUV(env);
423    ConcurrentHelper::UvHandleInit(loop, callbackInfo->onCallbackSignal, TaskPool::ExecuteCallback);
424#endif
425    TaskManager::GetInstance().RegisterCallback(env, taskId, callbackInfo);
426    return nullptr;
427}
428
429napi_value Task::SendData(napi_env env, napi_callback_info cbinfo)
430{
431    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
432    napi_value args[argc];
433    napi_get_cb_info(env, cbinfo, &argc, args, nullptr, nullptr);
434
435    napi_value argsArray;
436    napi_create_array_with_length(env, argc, &argsArray);
437    for (size_t i = 0; i < argc; i++) {
438        napi_set_element(env, argsArray, i, args[i]);
439    }
440
441    auto engine = reinterpret_cast<NativeEngine*>(env);
442    if (!engine->IsTaskPoolThread()) {
443        HILOG_ERROR("taskpool:: SendData is not called in the taskpool thread");
444        ErrorHelper::ThrowError(env, ErrorHelper::ERR_NOT_IN_TASKPOOL_THREAD);
445        return nullptr;
446    }
447    Task* task = nullptr;
448    void* data = engine->GetCurrentTaskInfo();
449    if (data == nullptr) {
450        HILOG_ERROR("taskpool:: SendData is not called in the concurrent function");
451        ErrorHelper::ThrowError(env, ErrorHelper::ERR_NOT_IN_CONCURRENT_FUNCTION);
452        return nullptr;
453    } else {
454        task = static_cast<Task*>(data);
455    }
456
457    napi_value undefined = NapiHelper::GetUndefinedValue(env);
458    void* serializationArgs = nullptr;
459    bool defaultClone = false;
460    bool defaultTransfer = true;
461    napi_status status = napi_serialize_inner(env, argsArray, undefined, undefined,
462                                              defaultTransfer, defaultClone, &serializationArgs);
463    if (status != napi_ok || serializationArgs == nullptr) {
464        std::string errMessage = "taskpool:: failed to serialize function";
465        HILOG_ERROR("%{public}s in SendData", errMessage.c_str());
466        ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
467        return nullptr;
468    }
469
470    TaskResultInfo* resultInfo = new TaskResultInfo(task->env_, env, task->taskId_, serializationArgs);
471    return TaskManager::GetInstance().NotifyCallbackExecute(env, resultInfo, task);
472}
473
474napi_value Task::AddDependency(napi_env env, napi_callback_info cbinfo)
475{
476    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
477    if (argc == 0) {
478        std::string errMessage = "taskpool:: addDependency has no params";
479        HILOG_ERROR("%{public}s", errMessage.c_str());
480        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "addDependency has no params.");
481        return nullptr;
482    }
483
484    napi_status status = napi_ok;
485    HandleScope scope(env, status);
486    napi_value args[argc];
487    napi_value napiTask;
488    napi_get_cb_info(env, cbinfo, &argc, args, &napiTask, nullptr);
489    Task* task = nullptr;
490    napi_unwrap(env, napiTask, reinterpret_cast<void**>(&task));
491    if (task == nullptr) {
492        HILOG_ERROR("taskpool:: task is nullptr");
493        return nullptr;
494    }
495    std::string errMessage = "";
496    if (task->IsPeriodicTask()) {
497        HILOG_ERROR("taskpool:: the periodic task cannot have a dependency");
498        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
499        return nullptr;
500    }
501    if (task->IsCommonTask() || task->IsSeqRunnerTask()) {
502        errMessage = "taskpool:: seqRunnerTask or executedTask cannot addDependency";
503        HILOG_ERROR("%{public}s", errMessage.c_str());
504        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
505        return nullptr;
506    }
507    if (task->IsGroupCommonTask()) {
508        errMessage = "taskpool:: groupTask cannot addDependency";
509        HILOG_ERROR("%{public}s", errMessage.c_str());
510        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
511        return nullptr;
512    }
513    task->SetHasDependency(true);
514    std::set<uint64_t> idSet;
515    for (size_t i = 0; i < argc; i++) {
516        if (!NapiHelper::HasNameProperty(env, args[i], TASKID_STR)) {
517            errMessage = "taskpool:: addDependency param is not task";
518            HILOG_ERROR("%{public}s", errMessage.c_str());
519            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the addDependency param must be task.");
520            return nullptr;
521        } else {
522            Task* dependentTask = nullptr;
523            napi_unwrap(env, args[i], reinterpret_cast<void**>(&dependentTask));
524            if (dependentTask == nullptr) {
525                HILOG_ERROR("taskpool:: dependentTask is nullptr");
526                return nullptr;
527            }
528            if (dependentTask->taskId_ == task->taskId_) {
529                HILOG_ERROR("taskpool:: there is a circular dependency");
530                ErrorHelper::ThrowError(env, ErrorHelper::ERR_CIRCULAR_DEPENDENCY);
531                return nullptr;
532            }
533            if (dependentTask->IsPeriodicTask()) {
534                HILOG_ERROR("taskpool:: the periodic task cannot have a dependency");
535                ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
536                return nullptr;
537            }
538            if (dependentTask->IsCommonTask() || dependentTask->IsSeqRunnerTask()) {
539                errMessage = "taskpool:: seqRunnerTask or executedTask cannot be relied on";
540                HILOG_ERROR("%{public}s", errMessage.c_str());
541                ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
542                return nullptr;
543            }
544            if (dependentTask->IsGroupCommonTask()) {
545                errMessage = "taskpool:: groupTask cannot be relied on";
546                HILOG_ERROR("%{public}s", errMessage.c_str());
547                ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
548                return nullptr;
549            }
550            idSet.emplace(dependentTask->taskId_);
551            dependentTask->SetHasDependency(true);
552        }
553    }
554    if (!TaskManager::GetInstance().StoreTaskDependency(task->taskId_, idSet)) {
555        HILOG_ERROR("taskpool:: there is a circular dependency");
556        ErrorHelper::ThrowError(env, ErrorHelper::ERR_CIRCULAR_DEPENDENCY);
557    }
558    std::string strTrace = "Task::AddDependency: ";
559    HITRACE_HELPER_METER_NAME(strTrace + TaskManager::GetInstance().GetTaskDependInfoToString(task->taskId_));
560    return nullptr;
561}
562
563napi_value Task::RemoveDependency(napi_env env, napi_callback_info cbinfo)
564{
565    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
566    if (argc == 0) {
567        std::string errMessage = "taskpool:: removeDependency has no params";
568        HILOG_ERROR("%{public}s", errMessage.c_str());
569        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "removeDependency has no params.");
570        return nullptr;
571    }
572    napi_status status = napi_ok;
573    HandleScope scope(env, status);
574    napi_value args[argc];
575    napi_value napiTask;
576    napi_get_cb_info(env, cbinfo, &argc, args, &napiTask, nullptr);
577    Task* task = nullptr;
578    napi_unwrap(env, napiTask, reinterpret_cast<void**>(&task));
579    if (task == nullptr) {
580        HILOG_ERROR("taskpool:: the task is nullptr");
581        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the task is nullptr");
582        return nullptr;
583    }
584    if (!task->HasDependency()) {
585        ThrowNoDependencyError(env);
586        return nullptr;
587    }
588    if (task->IsPeriodicTask()) {
589        HILOG_ERROR("taskpool:: the periodic task cannot call removeDependency");
590        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
591        return nullptr;
592    }
593    if (task->IsCommonTask()) {
594        std::string errMessage = "taskpool:: executedTask cannot removeDependency";
595        HILOG_ERROR("%{public}s", errMessage.c_str());
596        ErrorHelper::ThrowError(env, ErrorHelper::ERR_INEXISTENT_DEPENDENCY, errMessage.c_str());
597        return nullptr;
598    }
599    for (size_t i = 0; i < argc; i++) {
600        if (!NapiHelper::HasNameProperty(env, args[i], TASKID_STR)) {
601            std::string errMessage = "taskpool:: removeDependency param is not task";
602            HILOG_ERROR("%{public}s", errMessage.c_str());
603            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of removeDependency param must be task.");
604            return nullptr;
605        }
606        Task* dependentTask = nullptr;
607        napi_unwrap(env, args[i], reinterpret_cast<void**>(&dependentTask));
608        if (dependentTask == nullptr) {
609            HILOG_ERROR("taskpool:: the dependent task is nullptr");
610            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,  "the dependent task is nullptr");
611            return nullptr;
612        }
613        if (!dependentTask->HasDependency()) {
614            ThrowNoDependencyError(env);
615            return nullptr;
616        }
617        if (dependentTask->IsPeriodicTask()) {
618            HILOG_ERROR("taskpool:: the periodic task cannot call removeDependency");
619            ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_HAVE_DEPENDENCY);
620            return nullptr;
621        }
622        if (dependentTask->IsCommonTask()) {
623            std::string errMessage = "taskpool:: cannot removeDependency on a dependent and executed task";
624            HILOG_ERROR("%{public}s", errMessage.c_str());
625            ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
626            return nullptr;
627        }
628        if (!TaskManager::GetInstance().RemoveTaskDependency(task->taskId_, dependentTask->taskId_)) {
629            HILOG_ERROR("taskpool:: the dependency does not exist");
630            ErrorHelper::ThrowError(env, ErrorHelper::ERR_INEXISTENT_DEPENDENCY);
631            return nullptr;
632        }
633        dependentTask->TryClearHasDependency();
634    }
635    task->TryClearHasDependency();
636    std::string strTrace = "Task::RemoveDependency: ";
637    HITRACE_HELPER_METER_NAME(strTrace + TaskManager::GetInstance().GetTaskDependInfoToString(task->taskId_));
638    return nullptr;
639}
640
641void Task::StartExecutionCallback(const uv_async_t* req)
642{
643    HILOG_DEBUG("taskpool:: task StartExecutionCallback");
644    auto listenerCallBackInfo = static_cast<ListenerCallBackInfo*>(req->data);
645    if (listenerCallBackInfo == nullptr) { // LCOV_EXCL_BR_LINE
646        HILOG_FATAL("taskpool:: StartExecutionCallBackInfo is null");
647        return;
648    }
649    StartExecutionTask(listenerCallBackInfo);
650}
651
652void Task::StartExecutionTask(ListenerCallBackInfo* listenerCallBackInfo)
653{
654    auto env = listenerCallBackInfo->env_;
655    auto func = NapiHelper::GetReferenceValue(env, listenerCallBackInfo->callbackRef_);
656    if (func == nullptr) {
657        HILOG_INFO("taskpool:: StartExecutionCallback func is null");
658        return;
659    }
660
661    napi_value result;
662    napi_call_function(env, NapiHelper::GetGlobalObject(env), func, 0, nullptr, &result);
663    if (NapiHelper::IsExceptionPending(env)) {
664        napi_value exception = nullptr;
665        napi_get_and_clear_last_exception(env, &exception);
666        std::string funcStr = NapiHelper::GetPrintString(env, func);
667        HILOG_ERROR("taskpool:: an exception has occurred napi_call_function, func is %{public}s", funcStr.c_str());
668    }
669}
670
671void Task::ExecuteListenerCallback(ListenerCallBackInfo* listenerCallBackInfo)
672{
673    HILOG_DEBUG("taskpool:: task ExecuteListenerCallback");
674    if (listenerCallBackInfo == nullptr) { // LCOV_EXCL_BR_LINE
675        HILOG_FATAL("taskpool:: listenerCallBackInfo is null");
676        return;
677    }
678
679    napi_env env = listenerCallBackInfo->env_;
680    napi_value func = NapiHelper::GetReferenceValue(env, listenerCallBackInfo->callbackRef_);
681    if (func == nullptr) {
682        HILOG_INFO("taskpool:: ExecuteListenerCallback func is null");
683        return;
684    }
685
686    napi_value result;
687    napi_value args = listenerCallBackInfo->taskError_;
688    if (args != nullptr) {
689        napi_call_function(env, NapiHelper::GetGlobalObject(env), func, 1, &args, &result);
690    } else {
691        napi_call_function(env, NapiHelper::GetGlobalObject(env), func, 0, nullptr, &result);
692    }
693
694    if (NapiHelper::IsExceptionPending(env)) {
695        napi_value exception = nullptr;
696        napi_get_and_clear_last_exception(env, &exception);
697        std::string funcStr = NapiHelper::GetPrintString(env, func);
698        HILOG_ERROR("taskpool:: an exception has occurred napi_call_function, func is %{public}s", funcStr.c_str());
699    }
700}
701
702napi_value Task::OnEnqueued(napi_env env, napi_callback_info cbinfo)
703{
704    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
705    napi_value thisVar;
706    if (argc == 0) {
707        HILOG_INFO("taskpool:: the number of the params must be one");
708        return nullptr;
709    }
710
711    napi_value args[1];
712    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
713    napi_valuetype type;
714    NAPI_CALL(env, napi_typeof(env, args[0], &type));
715    if (type != napi_function) {
716        HILOG_ERROR("taskpool:: OnEnqueued's parameter should be function");
717        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of OnEnqueued's parameter must be function.");
718        return nullptr;
719    }
720
721    Task* task = nullptr;
722    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
723    if (task == nullptr) {
724        HILOG_ERROR("taskpool:: task is nullptr");
725        return nullptr;
726    }
727
728    if (task->taskState_ != ExecuteState::NOT_FOUND) {
729        HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
730        ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
731        return nullptr;
732    }
733
734    napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
735    task->onEnqueuedCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
736    return nullptr;
737}
738
739napi_value Task::OnStartExecution(napi_env env, napi_callback_info cbinfo)
740{
741    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
742    napi_value thisVar;
743    if (argc == 0) {
744        HILOG_INFO("taskpool:: the number of the params must be one");
745        return nullptr;
746    }
747
748    napi_value args[1];
749    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
750    napi_valuetype type;
751    NAPI_CALL(env, napi_typeof(env, args[0], &type));
752    if (type != napi_function) {
753        HILOG_ERROR("taskpool:: OnStartExecution's parameter should be function");
754        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
755            "the type of OnStartExecution's parameter must be function.");
756        return nullptr;
757    }
758
759    Task* task = nullptr;
760    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
761    if (task == nullptr) {
762        HILOG_ERROR("taskpool:: task is nullptr");
763        return nullptr;
764    }
765
766    if (task->taskState_ != ExecuteState::NOT_FOUND) {
767        HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
768        ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
769        return nullptr;
770    }
771
772    napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
773    task->onStartExecutionCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
774#if defined(ENABLE_TASKPOOL_EVENTHANDLER)
775    if (!task->IsMainThreadTask()) {
776        auto loop = NapiHelper::GetLibUV(env);
777        ConcurrentHelper::UvHandleInit(loop, task->onStartExecutionSignal_,
778            Task::StartExecutionCallback, task->onStartExecutionCallBackInfo_);
779    }
780#else
781    auto loop = NapiHelper::GetLibUV(env);
782    ConcurrentHelper::UvHandleInit(loop, task->onStartExecutionSignal_,
783        Task::StartExecutionCallback, task->onStartExecutionCallBackInfo_);
784#endif
785
786    return nullptr;
787}
788
789napi_value Task::OnExecutionFailed(napi_env env, napi_callback_info cbinfo)
790{
791    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
792    napi_value thisVar;
793    if (argc == 0) {
794        HILOG_INFO("taskpool:: the number of the params must be one");
795        return nullptr;
796    }
797
798    napi_value args[1];
799    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
800    napi_valuetype type;
801    NAPI_CALL(env, napi_typeof(env, args[0], &type));
802    if (type != napi_function) {
803        HILOG_ERROR("taskpool:: OnExecutionFailed's parameter should be function");
804        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
805            "the type of OnExecutionFailed's parameter must be function.");
806        return nullptr;
807    }
808
809    Task* task = nullptr;
810    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
811    if (task == nullptr) {
812        HILOG_ERROR("taskpool:: task is nullptr");
813        return nullptr;
814    }
815
816    if (task->taskState_ != ExecuteState::NOT_FOUND) {
817        HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
818        ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
819        return nullptr;
820    }
821
822    napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
823    task->onExecutionFailedCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
824    return nullptr;
825}
826
827napi_value Task::OnExecutionSucceeded(napi_env env, napi_callback_info cbinfo)
828{
829    size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
830    napi_value thisVar;
831    if (argc == 0) {
832        HILOG_INFO("taskpool:: the number of the params must be one");
833        return nullptr;
834    }
835
836    napi_value args[1];
837    napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
838    napi_valuetype type;
839    NAPI_CALL(env, napi_typeof(env, args[0], &type));
840    if (type != napi_function) {
841        HILOG_ERROR("taskpool:: OnExecutionSucceeded's parameter should be function");
842        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
843            "the type of OnExecutionSucceeded's parameter must be function");
844        return nullptr;
845    }
846
847    Task* task = nullptr;
848    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
849    if (task == nullptr) {
850        HILOG_ERROR("taskpool:: task is nullptr");
851        return nullptr;
852    }
853
854    if (task->taskState_ != ExecuteState::NOT_FOUND) {
855        HILOG_ERROR("taskpool:: The executed task does not support the registration of listeners.");
856        ErrorHelper::ThrowError(env, ErrorHelper::ERR_REGISTRATION_OF_LISTENERS);
857        return nullptr;
858    }
859
860    napi_ref callbackRef = Helper::NapiHelper::CreateReference(env, args[0], 1);
861    task->onExecutionSucceededCallBackInfo_ = new ListenerCallBackInfo(env, callbackRef, nullptr);
862    return nullptr;
863}
864
865napi_value Task::IsDone(napi_env env, napi_callback_info cbinfo)
866{
867    napi_value thisVar = nullptr;
868    napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
869    Task* task = nullptr;
870    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
871    if (task == nullptr) {
872        HILOG_ERROR("taskpool:: task is nullptr");
873        return NapiHelper::CreateBooleanValue(env, false);
874    }
875
876    if (task->taskState_ == ExecuteState::FINISHED || task->taskState_ == ExecuteState::ENDING) {
877        return NapiHelper::CreateBooleanValue(env, true);
878    }
879    return NapiHelper::CreateBooleanValue(env, false);
880}
881
882napi_value Task::GetTaskDuration(napi_env env, napi_callback_info& cbinfo, std::string durationType)
883{
884    napi_value thisVar = nullptr;
885    Task* task = nullptr;
886    napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
887    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
888    if (task == nullptr) {
889        uint64_t totalDuration = 0;
890        return NapiHelper::CreateUint32(env, totalDuration);
891    }
892    uint64_t totalDuration = TaskManager::GetInstance().GetTaskDuration(task->taskId_, durationType);
893    return NapiHelper::CreateUint32(env, totalDuration);
894}
895
896napi_value Task::GetTotalDuration(napi_env env, napi_callback_info cbinfo)
897{
898    return GetTaskDuration(env, cbinfo, TASK_TOTAL_TIME);
899}
900
901napi_value Task::GetCPUDuration(napi_env env, napi_callback_info cbinfo)
902{
903    return GetTaskDuration(env, cbinfo, TASK_CPU_TIME);
904}
905
906napi_value Task::GetIODuration(napi_env env, napi_callback_info cbinfo)
907{
908    return GetTaskDuration(env, cbinfo, TASK_IO_TIME);
909}
910
911napi_value Task::GetName(napi_env env, [[maybe_unused]] napi_callback_info cbinfo)
912{
913    napi_value thisVar = nullptr;
914    Task* task = nullptr;
915    napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
916    napi_unwrap(env, thisVar, reinterpret_cast<void**>(&task));
917    if (task == nullptr) {
918        return NapiHelper::CreateEmptyString(env);
919    }
920    napi_value name = nullptr;
921    napi_create_string_utf8(env, task->name_.c_str(), NAPI_AUTO_LENGTH, &name);
922    return name;
923}
924
925void Task::UpdateTaskType(TaskType taskType)
926{
927    taskType_ = taskType;
928    napi_reference_ref(env_, taskRef_, nullptr);
929}
930
931bool Task::IsRepeatableTask() const
932{
933    return IsCommonTask() || IsGroupCommonTask() || IsGroupFunctionTask();
934}
935
936bool Task::IsGroupTask() const
937{
938    return IsGroupCommonTask() || IsGroupFunctionTask();
939}
940
941bool Task::IsGroupCommonTask() const
942{
943    return taskType_ == TaskType::GROUP_COMMON_TASK;
944}
945
946bool Task::IsGroupFunctionTask() const
947{
948    return taskType_ == TaskType::GROUP_FUNCTION_TASK;
949}
950
951bool Task::IsCommonTask() const
952{
953    return taskType_ == TaskType::COMMON_TASK;
954}
955
956bool Task::IsSeqRunnerTask() const
957{
958    return taskType_ == TaskType::SEQRUNNER_TASK;
959}
960
961bool Task::IsFunctionTask() const
962{
963    return taskType_ == TaskType::FUNCTION_TASK;
964}
965
966bool Task::IsLongTask() const
967{
968    return isLongTask_;
969}
970
971bool Task::IsPeriodicTask() const
972{
973    return isPeriodicTask_;
974}
975
976bool Task::IsMainThreadTask() const
977{
978    return isMainThreadTask_;
979}
980
981// The uninitialized state is Task, and then taskType_ will be updated based on the task type.
982bool Task::IsExecuted() const
983{
984    return taskType_ != TaskType::TASK;
985}
986
987TaskInfo* Task::GenerateTaskInfo(napi_env env, napi_value func, napi_value args,
988                                 napi_value transferList, napi_value cloneList, Priority priority,
989                                 bool defaultTransfer, bool defaultCloneSendable)
990{
991    HILOG_DEBUG("taskpool:: task GenerateTaskInfo");
992    napi_value undefined = NapiHelper::GetUndefinedValue(env);
993    void* serializationFunction = nullptr;
994    napi_status status = napi_serialize_inner(env, func, undefined, undefined,
995                                              defaultTransfer, defaultCloneSendable, &serializationFunction);
996    std::string errMessage = "";
997    if (status != napi_ok || serializationFunction == nullptr) {
998        errMessage = "taskpool: failed to serialize function.";
999        HILOG_ERROR("%{public}s", errMessage.c_str());
1000        ErrorHelper::ThrowError(env, ErrorHelper::ERR_NOT_CONCURRENT_FUNCTION, errMessage.c_str());
1001        return nullptr;
1002    }
1003    void* serializationArguments = nullptr;
1004    status = napi_serialize_inner(env, args, transferList, cloneList,
1005                                  defaultTransfer, defaultCloneSendable, &serializationArguments);
1006    if (status != napi_ok || serializationArguments == nullptr) {
1007        errMessage = "taskpool: failed to serialize arguments.";
1008        HILOG_ERROR("%{public}s", errMessage.c_str());
1009        ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
1010        return nullptr;
1011    }
1012
1013    TaskInfo* taskInfo = new TaskInfo();
1014    taskInfo->serializationFunction = serializationFunction;
1015    taskInfo->serializationArguments = serializationArguments;
1016    taskInfo->priority = priority;
1017    reinterpret_cast<NativeEngine*>(env)->IncreaseSubEnvCounter();
1018    return taskInfo;
1019}
1020
1021void Task::IncreaseRefCount()
1022{
1023    taskRefCount_.fetch_add(2); // 2 : for PerformTask and TaskResultCallback
1024}
1025
1026void Task::DecreaseRefCount()
1027{
1028    taskRefCount_.fetch_sub(1);
1029}
1030
1031bool Task::IsReadyToHandle() const
1032{
1033    return (taskRefCount_ & 1) == 0;
1034}
1035
1036void Task::NotifyPendingTask()
1037{
1038    HILOG_DEBUG("taskpool:: task:%{public}s NotifyPendingTask", std::to_string(taskId_).c_str());
1039    TaskManager::GetInstance().NotifyDependencyTaskInfo(taskId_);
1040    std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1041    delete currentTaskInfo_;
1042    if (pendingTaskInfos_.empty()) {
1043        currentTaskInfo_ = nullptr;
1044        HILOG_DEBUG("taskpool:: task:%{public}s NotifyPendingTask end, currentTaskInfo_ nullptr",
1045                    std::to_string(taskId_).c_str());
1046        return;
1047    }
1048    currentTaskInfo_ = pendingTaskInfos_.front();
1049    pendingTaskInfos_.pop_front();
1050    taskState_ = ExecuteState::WAITING;
1051    TaskManager::GetInstance().EnqueueTaskId(taskId_, currentTaskInfo_->priority);
1052}
1053
1054void Task::CancelPendingTask(napi_env env)
1055{
1056    HILOG_DEBUG("taskpool:: task:%{public}s CancelPendingTask", std::to_string(taskId_).c_str());
1057    if (pendingTaskInfos_.empty()) {
1058        HILOG_DEBUG("taskpool:: task CancelPendingTask end, pendingTaskInfos_ nullptr");
1059        return;
1060    }
1061    napi_value error = nullptr;
1062    if (!IsPeriodicTask()) {
1063        error = ErrorHelper::NewError(env, 0, "taskpool:: task has been canceled");
1064    }
1065    auto engine = reinterpret_cast<NativeEngine*>(env);
1066    for (const auto& info : pendingTaskInfos_) {
1067        engine->DecreaseSubEnvCounter();
1068        if (!IsPeriodicTask()) {
1069            napi_reject_deferred(env, info->deferred, error);
1070        }
1071        napi_reference_unref(env, taskRef_, nullptr);
1072        delete info;
1073    }
1074    pendingTaskInfos_.clear();
1075}
1076
1077bool Task::UpdateTask(uint64_t startTime, void* worker)
1078{
1079    HILOG_DEBUG("taskpool:: task:%{public}s UpdateTask", std::to_string(taskId_).c_str());
1080    if (taskState_ == ExecuteState::CANCELED) { // task may have been canceled
1081        HILOG_INFO("taskpool:: task has been canceled, taskId %{public}s", std::to_string(taskId_).c_str());
1082        return false;
1083    }
1084    taskState_ = ExecuteState::RUNNING;
1085    startTime_ = startTime;
1086    worker_ = worker;
1087    return true;
1088}
1089
1090napi_value Task::DeserializeValue(napi_env env, napi_value* func, napi_value* args)
1091{
1092    std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1093    if (UNLIKELY(currentTaskInfo_ == nullptr)) {
1094        HILOG_ERROR("taskpool:: the currentTaskInfo is nullptr, the task may have been cancelled");
1095        return nullptr;
1096    }
1097
1098    napi_status status = napi_ok;
1099    std::string errMessage = "";
1100    status = napi_deserialize(env, currentTaskInfo_->serializationFunction, func);
1101    if (!IsGroupFunctionTask()) {
1102        napi_delete_serialization_data(env, currentTaskInfo_->serializationFunction);
1103    }
1104    if (status != napi_ok || func == nullptr) {
1105        errMessage = "taskpool:: failed to deserialize function.";
1106        HILOG_ERROR("%{public}s", errMessage.c_str());
1107        napi_value err = ErrorHelper::NewError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
1108        success_ = false;
1109        return err;
1110    }
1111
1112    status = napi_deserialize(env, currentTaskInfo_->serializationArguments, args);
1113    if (!IsGroupFunctionTask()) {
1114        napi_delete_serialization_data(env, currentTaskInfo_->serializationArguments);
1115    }
1116    if (status != napi_ok || args == nullptr) {
1117        errMessage = "taskpool:: failed to deserialize function.";
1118        HILOG_ERROR("%{public}s", errMessage.c_str());
1119        napi_value err = ErrorHelper::NewError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, errMessage.c_str());
1120        success_ = false;
1121        return err;
1122    }
1123    return nullptr;
1124}
1125
1126void Task::StoreTaskDuration()
1127{
1128    HILOG_DEBUG("taskpool:: task:%{public}s StoreTaskDuration", std::to_string(taskId_).c_str());
1129    cpuTime_ = ConcurrentHelper::GetMilliseconds();
1130    uint64_t cpuDuration = cpuTime_ - startTime_;
1131    if (ioTime_ != 0) {
1132        uint64_t ioDuration = ioTime_ - startTime_;
1133        TaskManager::GetInstance().StoreTaskDuration(taskId_, std::max(cpuDuration, ioDuration), cpuDuration);
1134    } else {
1135        TaskManager::GetInstance().StoreTaskDuration(taskId_, 0, cpuDuration);
1136    }
1137}
1138
1139bool Task::CanForSequenceRunner(napi_env env)
1140{
1141    std::string errMessage = "";
1142    // task with dependence is not allowed
1143    if (HasDependency()) {
1144        errMessage = "seqRunner:: dependent task not allowed.";
1145        HILOG_ERROR("%{public}s", errMessage.c_str());
1146        ErrorHelper::ThrowError(env, ErrorHelper::ERR_ADD_DEPENDENT_TASK_TO_SEQRUNNER, errMessage.c_str());
1147        return false;
1148    }
1149    if (IsPeriodicTask()) {
1150        errMessage = "taskpool:: SequenceRunner cannot execute the periodicTask";
1151        HILOG_ERROR("%{public}s", errMessage.c_str());
1152        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1153        return false;
1154    }
1155    if (IsCommonTask() || IsSeqRunnerTask()) {
1156        errMessage = "taskpool:: SequenceRunner cannot execute seqRunnerTask or executedTask";
1157        HILOG_ERROR("%{public}s", errMessage.c_str());
1158        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1159        return false;
1160    }
1161    if (IsGroupCommonTask()) {
1162        errMessage = "taskpool:: SequenceRunner cannot execute groupTask";
1163        HILOG_ERROR("%{public}s", errMessage.c_str());
1164        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1165        return false;
1166    }
1167    return true;
1168}
1169
1170bool Task::CanForTaskGroup(napi_env env)
1171{
1172    std::string errMessage = "";
1173    if (HasDependency()) {
1174        errMessage = "taskpool:: dependent task not allowed.";
1175        HILOG_ERROR("%{public}s", errMessage.c_str());
1176        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1177        return false;
1178    }
1179    if (IsPeriodicTask()) {
1180        errMessage = "taskpool:: The interface does not support the periodicTask";
1181        HILOG_ERROR("%{public}s", errMessage.c_str());
1182        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1183        return false;
1184    }
1185    if (IsCommonTask() || IsSeqRunnerTask()) {
1186        errMessage = "taskpool:: taskGroup cannot add seqRunnerTask or executedTask";
1187        HILOG_ERROR("%{public}s", errMessage.c_str());
1188        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1189        return false;
1190    }
1191    if (IsGroupCommonTask()) {
1192        errMessage = "taskpool:: taskGroup cannot add groupTask";
1193        HILOG_ERROR("%{public}s", errMessage.c_str());
1194        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1195        return false;
1196    }
1197    if (IsLongTask()) {
1198        errMessage = "taskpool:: The interface does not support the long task";
1199        HILOG_ERROR("%{public}s", errMessage.c_str());
1200        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1201        return false;
1202    }
1203    taskType_ = TaskType::GROUP_COMMON_TASK;
1204    return true;
1205}
1206
1207bool Task::CanExecute(napi_env env)
1208{
1209    std::string errMessage = "";
1210    if (IsGroupCommonTask()) {
1211        errMessage = "taskpool:: groupTask cannot execute outside";
1212        HILOG_ERROR("%{public}s", errMessage.c_str());
1213        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1214        return false;
1215    }
1216    if (IsSeqRunnerTask()) {
1217        errMessage = "taskpool:: seqRunnerTask cannot execute outside";
1218        HILOG_ERROR("%{public}s", errMessage.c_str());
1219        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1220        return false;
1221    }
1222    if (IsCommonTask() && HasDependency()) {
1223        errMessage = "taskpool:: executedTask with dependency cannot execute again";
1224        HILOG_ERROR("%{public}s", errMessage.c_str());
1225        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1226        return false;
1227    }
1228    if (IsExecuted() && IsLongTask()) {
1229        errMessage = "taskpool:: The long task can only be executed once";
1230        HILOG_ERROR("%{public}s", errMessage.c_str());
1231        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1232        return false;
1233    }
1234    if (IsPeriodicTask()) {
1235        errMessage = "taskpool:: the periodicTask cannot execute again";
1236        HILOG_ERROR("%{public}s", errMessage.c_str());
1237        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1238        return false;
1239    }
1240    return true;
1241}
1242
1243bool Task::CanExecuteDelayed(napi_env env)
1244{
1245    std::string errMessage = "";
1246    if (IsGroupCommonTask()) {
1247        errMessage = "taskpool:: groupTask cannot executeDelayed outside";
1248        HILOG_ERROR("%{public}s", errMessage.c_str());
1249        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1250        return false;
1251    }
1252    if (IsSeqRunnerTask()) {
1253        errMessage = "taskpool:: seqRunnerTask cannot executeDelayed outside";
1254        HILOG_ERROR("%{public}s", errMessage.c_str());
1255        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1256        return false;
1257    }
1258    if (IsCommonTask() && HasDependency()) {
1259        errMessage = "taskpool:: executedTask with dependency cannot executeDelayed again";
1260        HILOG_ERROR("%{public}s", errMessage.c_str());
1261        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1262        return false;
1263    }
1264    if (IsExecuted() && IsLongTask()) {
1265        errMessage = "taskpool:: Multiple executions of longTask are not supported in the executeDelayed";
1266        HILOG_ERROR("%{public}s", errMessage.c_str());
1267        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str());
1268        return false;
1269    }
1270    if (IsPeriodicTask()) {
1271        errMessage = "taskpool:: the periodicTask cannot executeDelayed";
1272        HILOG_ERROR("%{public}s", errMessage.c_str());
1273        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_AGAIN, errMessage.c_str());
1274        return false;
1275    }
1276    return true;
1277}
1278
1279bool Task::CanExecutePeriodically(napi_env env)
1280{
1281    if (IsExecuted() || IsPeriodicTask()) {
1282        ErrorHelper::ThrowError(env, ErrorHelper::ERR_TASK_EXECUTE_PERIODICALLY);
1283        return false;
1284    }
1285    if (HasDependency()) {
1286        ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
1287            "taskpool:: the task with dependency cannot executePeriodically");
1288        return false;
1289    }
1290    return true;
1291}
1292
1293void Task::SetHasDependency(bool hasDependency)
1294{
1295    hasDependency_ = hasDependency;
1296}
1297
1298bool Task::HasDependency() const
1299{
1300    return hasDependency_;
1301}
1302
1303void Task::TryClearHasDependency()
1304{
1305    HILOG_DEBUG("taskpool:: task:%{public}s TryClearHasDependency", std::to_string(taskId_).c_str());
1306    if (IsExecuted()) {
1307        HILOG_DEBUG("taskpool:: task TryClearHasDependency end, task is executed");
1308        return;
1309    }
1310    if ((!TaskManager::GetInstance().IsDependentByTaskId(taskId_)) &&
1311        (!TaskManager::GetInstance().IsDependendByTaskId(taskId_))) {
1312        SetHasDependency(false);
1313    }
1314}
1315
1316void Task::ThrowNoDependencyError(napi_env env)
1317{
1318    std::string errMessage = "taskpool:: task has no dependency";
1319    HILOG_ERROR("%{public}s", errMessage.c_str());
1320    ErrorHelper::ThrowError(env, ErrorHelper::ERR_INEXISTENT_DEPENDENCY, errMessage.c_str());
1321}
1322
1323void Task::UpdatePeriodicTask()
1324{
1325    taskType_ = TaskType::COMMON_TASK;
1326    napi_reference_ref(env_, taskRef_, nullptr);
1327    isPeriodicTask_ = true;
1328}
1329
1330void Task::InitHandle(napi_env env)
1331{
1332#if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1333    if (!OHOS::AppExecFwk::EventRunner::IsAppMainThread()) {
1334        uv_loop_t* loop = NapiHelper::GetLibUV(env);
1335        ConcurrentHelper::UvHandleInit(loop, onResultSignal_, TaskPool::HandleTaskResult, this);
1336    } else {
1337        isMainThreadTask_ = true;
1338        HILOG_DEBUG("taskpool:: eventrunner should be nullptr if the current thread is not the main thread");
1339    }
1340#else
1341    uv_loop_t* loop = NapiHelper::GetLibUV(env);
1342    ConcurrentHelper::UvHandleInit(loop, onResultSignal_, TaskPool::HandleTaskResult, this);
1343    auto engine = reinterpret_cast<NativeEngine*>(env);
1344    isMainThreadTask_ = engine->IsMainThread();
1345#endif
1346}
1347
1348void Task::ClearDelayedTimers()
1349{
1350    HILOG_DEBUG("taskpool:: task ClearDelayedTimers");
1351    std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1352    TaskMessage *taskMessage = nullptr;
1353    for (auto t: delayedTimers_) {
1354        if (t == nullptr) {
1355            continue;
1356        }
1357        taskMessage = static_cast<TaskMessage *>(t->data);
1358        napi_value error = ErrorHelper::NewError(env_, 0, "taskpool:: task has been canceled");
1359        napi_reject_deferred(env_, taskMessage->deferred, error);
1360        uv_timer_stop(t);
1361        uv_close(reinterpret_cast<uv_handle_t*>(t), [](uv_handle_t* handle) {
1362            delete (uv_timer_t*)handle;
1363            handle = nullptr;
1364        });
1365        delete taskMessage;
1366        taskMessage = nullptr;
1367    }
1368    delayedTimers_.clear();
1369}
1370
1371bool Task::VerifyAndPostResult(Priority priority)
1372{
1373#if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1374    if (IsMainThreadTask()) {
1375        HITRACE_HELPER_METER_NAME("VerifyAndPostResult: PostTask");
1376        uint64_t taskId = taskId_;
1377        auto onResultTask = [taskId]() {
1378            Task* task = TaskManager::GetInstance().GetTask(taskId);
1379            if (task == nullptr) {
1380                return;
1381            }
1382            TaskPool::HandleTaskResultCallback(task);
1383        };
1384        TaskManager::GetInstance().PostTask(onResultTask, "TaskPoolOnResultTask", priority);
1385        return true;
1386    } else {
1387        std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1388        if (!IsValid() || onResultSignal_ == nullptr || uv_is_closing((uv_handle_t*)onResultSignal_)) {
1389            return false;
1390        }
1391        uv_async_send(onResultSignal_);
1392        return true;
1393    }
1394#else
1395    std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1396    if (!IsValid() || onResultSignal_ == nullptr || uv_is_closing((uv_handle_t*)onResultSignal_)) {
1397        return false;
1398    }
1399    uv_async_send(onResultSignal_);
1400    return true;
1401#endif
1402}
1403
1404void Task::IncreaseTaskRefCount()
1405{
1406    refCount_++; // when tasks are created or executed, refCount_ will increment
1407}
1408
1409void Task::DecreaseTaskRefCount()
1410{
1411    refCount_--; // when tasks finished, refCount_ will decrement
1412}
1413
1414bool Task::ShouldDeleteTask(bool needUnref)
1415{
1416    std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1417    if (!IsValid()) {
1418        HILOG_WARN("taskpool:: task is invalid");
1419        TaskManager::GetInstance().RemoveTask(taskId_);
1420        return true;
1421    }
1422    if (needUnref) {
1423        DecreaseTaskRefCount();
1424    }
1425    return false;
1426}
1427
1428bool Task::CheckStartExecution(Priority priority)
1429{
1430#if defined(ENABLE_TASKPOOL_EVENTHANDLER)
1431    if (IsMainThreadTask()) {
1432        if (onStartExecutionCallBackInfo_ == nullptr) {
1433            return true;
1434        }
1435        HITRACE_HELPER_METER_NAME("PerformTask: PostTask");
1436        uint64_t taskId = taskId_;
1437        auto onStartExecutionTask = [taskId]() {
1438            Task* task = TaskManager::GetInstance().GetTask(taskId);
1439            if (task == nullptr || task->onStartExecutionCallBackInfo_ == nullptr) {
1440                return;
1441            }
1442            Task::StartExecutionTask(task->onStartExecutionCallBackInfo_);
1443        };
1444        TaskManager::GetInstance().PostTask(onStartExecutionTask, "TaskPoolOnStartExecutionTask", priority);
1445    } else {
1446        if (onStartExecutionSignal_ == nullptr) {
1447            return true;
1448        }
1449        std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1450        if (!IsValid()) {
1451            return false;
1452        }
1453        if (onStartExecutionSignal_ != nullptr && !uv_is_closing((uv_handle_t*)onStartExecutionSignal_)) {
1454            uv_async_send(onStartExecutionSignal_);
1455        }
1456    }
1457    return true;
1458#else
1459    if (onStartExecutionSignal_ == nullptr) {
1460        return true;
1461    }
1462    std::lock_guard<RECURSIVE_MUTEX> lock(taskMutex_);
1463    if (!IsValid()) {
1464        return false;
1465    }
1466    if (onStartExecutionSignal_ != nullptr && !uv_is_closing((uv_handle_t*)onStartExecutionSignal_)) {
1467        uv_async_send(onStartExecutionSignal_);
1468    }
1469    return true;
1470#endif
1471}
1472
1473void Task::SetValid(bool isValid)
1474{
1475    isValid_.store(isValid);
1476}
1477
1478bool Task::IsValid()
1479{
1480    return isValid_.load();
1481}
1482} // namespace Commonlibrary::Concurrent::TaskPoolModule