14d6c458bSopenharmony_ci/* 24d6c458bSopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 34d6c458bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44d6c458bSopenharmony_ci * you may not use this file except in compliance with the License. 54d6c458bSopenharmony_ci * You may obtain a copy of the License at 64d6c458bSopenharmony_ci * 74d6c458bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84d6c458bSopenharmony_ci * 94d6c458bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104d6c458bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114d6c458bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124d6c458bSopenharmony_ci * See the License for the specific language governing permissions and 134d6c458bSopenharmony_ci * limitations under the License. 144d6c458bSopenharmony_ci */ 154d6c458bSopenharmony_ci 164d6c458bSopenharmony_ci#include "task_group.h" 174d6c458bSopenharmony_ci 184d6c458bSopenharmony_ci#include "helper/error_helper.h" 194d6c458bSopenharmony_ci#include "helper/napi_helper.h" 204d6c458bSopenharmony_ci#include "helper/object_helper.h" 214d6c458bSopenharmony_ci#include "napi/native_api.h" 224d6c458bSopenharmony_ci#include "tools/log.h" 234d6c458bSopenharmony_ci 244d6c458bSopenharmony_cinamespace Commonlibrary::Concurrent::TaskPoolModule { 254d6c458bSopenharmony_ciusing namespace Commonlibrary::Concurrent::Common::Helper; 264d6c458bSopenharmony_ci 274d6c458bSopenharmony_cinapi_value TaskGroup::TaskGroupConstructor(napi_env env, napi_callback_info cbinfo) 284d6c458bSopenharmony_ci{ 294d6c458bSopenharmony_ci size_t argc = 1; 304d6c458bSopenharmony_ci napi_value args[1]; 314d6c458bSopenharmony_ci napi_value thisVar; 324d6c458bSopenharmony_ci napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr); 334d6c458bSopenharmony_ci if (argc > 1) { 344d6c458bSopenharmony_ci ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of params must be zero or one."); 354d6c458bSopenharmony_ci return nullptr; 364d6c458bSopenharmony_ci } 374d6c458bSopenharmony_ci napi_value name; 384d6c458bSopenharmony_ci if (argc == 1) { 394d6c458bSopenharmony_ci // check 1st param is taskGroupName 404d6c458bSopenharmony_ci if (!NapiHelper::IsString(env, args[0])) { 414d6c458bSopenharmony_ci ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the first param must be string."); 424d6c458bSopenharmony_ci return nullptr; 434d6c458bSopenharmony_ci } 444d6c458bSopenharmony_ci name = args[0]; 454d6c458bSopenharmony_ci } else { 464d6c458bSopenharmony_ci name = NapiHelper::CreateEmptyString(env); 474d6c458bSopenharmony_ci } 484d6c458bSopenharmony_ci TaskGroup* group = new TaskGroup(); 494d6c458bSopenharmony_ci uint64_t groupId = reinterpret_cast<uint64_t>(group); 504d6c458bSopenharmony_ci group->groupId_ = groupId; 514d6c458bSopenharmony_ci TaskGroupManager::GetInstance().StoreTaskGroup(groupId, group); 524d6c458bSopenharmony_ci napi_value napiGroupId = NapiHelper::CreateUint64(env, groupId); 534d6c458bSopenharmony_ci napi_property_descriptor properties[] = { 544d6c458bSopenharmony_ci DECLARE_NAPI_PROPERTY(GROUP_ID_STR, napiGroupId), 554d6c458bSopenharmony_ci DECLARE_NAPI_FUNCTION_WITH_DATA("addTask", AddTask, thisVar), 564d6c458bSopenharmony_ci }; 574d6c458bSopenharmony_ci napi_set_named_property(env, thisVar, NAME, name); 584d6c458bSopenharmony_ci napi_define_properties(env, thisVar, sizeof(properties) / sizeof(properties[0]), properties); 594d6c458bSopenharmony_ci napi_wrap(env, thisVar, group, TaskGroupDestructor, nullptr, nullptr); 604d6c458bSopenharmony_ci napi_create_reference(env, thisVar, 0, &group->groupRef_); 614d6c458bSopenharmony_ci return thisVar; 624d6c458bSopenharmony_ci} 634d6c458bSopenharmony_ci 644d6c458bSopenharmony_civoid TaskGroup::TaskGroupDestructor(napi_env env, void* data, [[maybe_unused]] void* hint) 654d6c458bSopenharmony_ci{ 664d6c458bSopenharmony_ci HILOG_DEBUG("taskpool::TaskGroupDestructor"); 674d6c458bSopenharmony_ci TaskGroup* group = static_cast<TaskGroup*>(data); 684d6c458bSopenharmony_ci TaskGroupManager::GetInstance().ReleaseTaskGroupData(env, group); 694d6c458bSopenharmony_ci napi_delete_reference(env, group->groupRef_); 704d6c458bSopenharmony_ci delete group; 714d6c458bSopenharmony_ci} 724d6c458bSopenharmony_ci 734d6c458bSopenharmony_cinapi_value TaskGroup::AddTask(napi_env env, napi_callback_info cbinfo) 744d6c458bSopenharmony_ci{ 754d6c458bSopenharmony_ci size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo); 764d6c458bSopenharmony_ci std::string errMessage = ""; 774d6c458bSopenharmony_ci if (argc < 1) { 784d6c458bSopenharmony_ci errMessage = "taskGroup:: the number of params must be at least one"; 794d6c458bSopenharmony_ci HILOG_ERROR("%{public}s", errMessage.c_str()); 804d6c458bSopenharmony_ci ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the number of params must be at least one."); 814d6c458bSopenharmony_ci return nullptr; 824d6c458bSopenharmony_ci } 834d6c458bSopenharmony_ci napi_value* args = new napi_value[argc]; 844d6c458bSopenharmony_ci ObjectScope<napi_value> scope(args, true); 854d6c458bSopenharmony_ci napi_value thisVar; 864d6c458bSopenharmony_ci napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr); 874d6c458bSopenharmony_ci napi_value napiGroupId = NapiHelper::GetNameProperty(env, thisVar, GROUP_ID_STR); 884d6c458bSopenharmony_ci uint64_t groupId = NapiHelper::GetUint64Value(env, napiGroupId); 894d6c458bSopenharmony_ci TaskGroup* group = TaskGroupManager::GetInstance().GetTaskGroup(groupId); 904d6c458bSopenharmony_ci if (group->groupState_ != ExecuteState::NOT_FOUND) { 914d6c458bSopenharmony_ci errMessage = "taskpool:: executed taskGroup cannot addTask"; 924d6c458bSopenharmony_ci HILOG_ERROR("%{public}s", errMessage.c_str()); 934d6c458bSopenharmony_ci ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, errMessage.c_str()); 944d6c458bSopenharmony_ci return nullptr; 954d6c458bSopenharmony_ci } 964d6c458bSopenharmony_ci napi_valuetype type = napi_undefined; 974d6c458bSopenharmony_ci napi_typeof(env, args[0], &type); 984d6c458bSopenharmony_ci if (type == napi_object) { 994d6c458bSopenharmony_ci Task* task = nullptr; 1004d6c458bSopenharmony_ci napi_unwrap(env, args[0], reinterpret_cast<void**>(&task)); 1014d6c458bSopenharmony_ci if (task == nullptr) { 1024d6c458bSopenharmony_ci ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the params must be task."); 1034d6c458bSopenharmony_ci return nullptr; 1044d6c458bSopenharmony_ci } 1054d6c458bSopenharmony_ci if (!task->CanForTaskGroup(env)) { 1064d6c458bSopenharmony_ci return nullptr; 1074d6c458bSopenharmony_ci } 1084d6c458bSopenharmony_ci task->taskType_ = TaskType::GROUP_COMMON_TASK; 1094d6c458bSopenharmony_ci task->groupId_ = groupId; 1104d6c458bSopenharmony_ci napi_reference_ref(env, task->taskRef_, nullptr); 1114d6c458bSopenharmony_ci TaskGroupManager::GetInstance().AddTask(groupId, task->taskRef_, task->taskId_); 1124d6c458bSopenharmony_ci return nullptr; 1134d6c458bSopenharmony_ci } else if (type == napi_function) { 1144d6c458bSopenharmony_ci napi_value napiTask = NapiHelper::CreateObject(env); 1154d6c458bSopenharmony_ci Task* task = Task::GenerateFunctionTask(env, args[0], args + 1, argc - 1, TaskType::GROUP_FUNCTION_TASK); 1164d6c458bSopenharmony_ci if (task == nullptr) { 1174d6c458bSopenharmony_ci return nullptr; 1184d6c458bSopenharmony_ci } 1194d6c458bSopenharmony_ci task->groupId_ = groupId; 1204d6c458bSopenharmony_ci TaskManager::GetInstance().StoreTask(task->taskId_, task); 1214d6c458bSopenharmony_ci napi_wrap(env, napiTask, task, Task::TaskDestructor, nullptr, nullptr); 1224d6c458bSopenharmony_ci napi_create_reference(env, napiTask, 1, &task->taskRef_); 1234d6c458bSopenharmony_ci TaskGroupManager::GetInstance().AddTask(groupId, task->taskRef_, task->taskId_); 1244d6c458bSopenharmony_ci return nullptr; 1254d6c458bSopenharmony_ci } 1264d6c458bSopenharmony_ci ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of the first param must be object or function."); 1274d6c458bSopenharmony_ci return nullptr; 1284d6c458bSopenharmony_ci} 1294d6c458bSopenharmony_ci 1304d6c458bSopenharmony_ciuint32_t TaskGroup::GetTaskIndex(uint32_t taskId) 1314d6c458bSopenharmony_ci{ 1324d6c458bSopenharmony_ci uint32_t index = 0; 1334d6c458bSopenharmony_ci for (uint32_t id : taskIds_) { 1344d6c458bSopenharmony_ci if (taskId == id) { 1354d6c458bSopenharmony_ci break; 1364d6c458bSopenharmony_ci } 1374d6c458bSopenharmony_ci index++; 1384d6c458bSopenharmony_ci } 1394d6c458bSopenharmony_ci return index; 1404d6c458bSopenharmony_ci} 1414d6c458bSopenharmony_ci 1424d6c458bSopenharmony_civoid TaskGroup::NotifyGroupTask(napi_env env) 1434d6c458bSopenharmony_ci{ 1444d6c458bSopenharmony_ci HILOG_DEBUG("taskpool:: NotifyGroupTask"); 1454d6c458bSopenharmony_ci std::lock_guard<RECURSIVE_MUTEX> lock(taskGroupMutex_); 1464d6c458bSopenharmony_ci if (pendingGroupInfos_.empty()) { 1474d6c458bSopenharmony_ci return; 1484d6c458bSopenharmony_ci } 1494d6c458bSopenharmony_ci groupState_ = ExecuteState::WAITING; 1504d6c458bSopenharmony_ci currentGroupInfo_ = pendingGroupInfos_.front(); 1514d6c458bSopenharmony_ci pendingGroupInfos_.pop_front(); 1524d6c458bSopenharmony_ci for (auto iter = taskRefs_.begin(); iter != taskRefs_.end(); iter++) { 1534d6c458bSopenharmony_ci napi_value napiTask = NapiHelper::GetReferenceValue(env, *iter); 1544d6c458bSopenharmony_ci Task* task = nullptr; 1554d6c458bSopenharmony_ci napi_unwrap(env, napiTask, reinterpret_cast<void**>(&task)); 1564d6c458bSopenharmony_ci if (task == nullptr) { 1574d6c458bSopenharmony_ci HILOG_ERROR("taskpool::ExecuteGroup task is nullptr"); 1584d6c458bSopenharmony_ci return; 1594d6c458bSopenharmony_ci } 1604d6c458bSopenharmony_ci napi_reference_ref(env, task->taskRef_, nullptr); 1614d6c458bSopenharmony_ci Priority priority = currentGroupInfo_->priority; 1624d6c458bSopenharmony_ci if (task->IsGroupCommonTask()) { 1634d6c458bSopenharmony_ci task->GetTaskInfo(env, napiTask, priority); 1644d6c458bSopenharmony_ci } else { 1654d6c458bSopenharmony_ci reinterpret_cast<NativeEngine*>(env)->IncreaseSubEnvCounter(); 1664d6c458bSopenharmony_ci } 1674d6c458bSopenharmony_ci task->IncreaseRefCount(); 1684d6c458bSopenharmony_ci TaskManager::GetInstance().IncreaseRefCount(task->taskId_); 1694d6c458bSopenharmony_ci task->taskState_ = ExecuteState::WAITING; 1704d6c458bSopenharmony_ci TaskManager::GetInstance().EnqueueTaskId(task->taskId_, priority); 1714d6c458bSopenharmony_ci } 1724d6c458bSopenharmony_ci} 1734d6c458bSopenharmony_ci 1744d6c458bSopenharmony_civoid TaskGroup::CancelPendingGroup(napi_env env) 1754d6c458bSopenharmony_ci{ 1764d6c458bSopenharmony_ci HILOG_DEBUG("taskpool:: CancelPendingGroup"); 1774d6c458bSopenharmony_ci if (pendingGroupInfos_.empty()) { 1784d6c458bSopenharmony_ci return; 1794d6c458bSopenharmony_ci } 1804d6c458bSopenharmony_ci napi_value error = ErrorHelper::NewError(env, 0, "taskpool:: taskGroup has been canceled"); 1814d6c458bSopenharmony_ci auto pendingIter = pendingGroupInfos_.begin(); 1824d6c458bSopenharmony_ci auto engine = reinterpret_cast<NativeEngine*>(env); 1834d6c458bSopenharmony_ci for (; pendingIter != pendingGroupInfos_.end(); ++pendingIter) { 1844d6c458bSopenharmony_ci for (size_t i = 0; i < taskIds_.size(); i++) { 1854d6c458bSopenharmony_ci engine->DecreaseSubEnvCounter(); 1864d6c458bSopenharmony_ci } 1874d6c458bSopenharmony_ci GroupInfo* info = *pendingIter; 1884d6c458bSopenharmony_ci napi_reject_deferred(env, info->deferred, error); 1894d6c458bSopenharmony_ci napi_reference_unref(env, groupRef_, nullptr); 1904d6c458bSopenharmony_ci delete info; 1914d6c458bSopenharmony_ci } 1924d6c458bSopenharmony_ci pendingIter = pendingGroupInfos_.begin(); 1934d6c458bSopenharmony_ci pendingGroupInfos_.erase(pendingIter, pendingGroupInfos_.end()); 1944d6c458bSopenharmony_ci} 1954d6c458bSopenharmony_ci} // namespace Commonlibrary::Concurrent::TaskPoolModule