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