1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "taskpool.h"
17
18 #include "helper/error_helper.h"
19 #include "helper/object_helper.h"
20 #include "hitrace_meter.h"
21 #include "task_manager.h"
22 #include "utils/log.h"
23 #include "worker.h"
24
25 namespace Commonlibrary::Concurrent::TaskPoolModule {
26 using namespace Commonlibrary::Concurrent::Common::Helper;
InitTaskPool(napi_env env,napi_value exports)27 napi_value TaskPool::InitTaskPool(napi_env env, napi_value exports)
28 {
29 HITRACE_METER_NAME(HITRACE_TAG_COMMONLIBRARY, __PRETTY_FUNCTION__);
30 const char className[] = "Task";
31 napi_property_descriptor properties[] = {};
32 napi_value taskClass = nullptr;
33 napi_define_class(env, className, sizeof(className), Task::TaskConstructor, nullptr,
34 sizeof(properties) / sizeof(properties[0]), properties, &taskClass);
35 napi_set_named_property(env, exports, "Task", taskClass);
36
37 napi_value executeFunc;
38 napi_create_function(env, "execute", NAPI_AUTO_LENGTH, Execute, NULL, &executeFunc);
39 napi_set_named_property(env, exports, "execute", executeFunc);
40
41 napi_value cancelFunc;
42 napi_create_function(env, "cancel", NAPI_AUTO_LENGTH, Cancel, NULL, &cancelFunc);
43 napi_set_named_property(env, exports, "cancel", cancelFunc);
44
45 napi_value priorityObj = nullptr;
46 napi_create_object(env, &priorityObj);
47 napi_value highPriority = nullptr;
48 napi_value mediumPriority = nullptr;
49 napi_value lowPriority = nullptr;
50 napi_create_int32(env, Priority::HIGH, &highPriority);
51 napi_set_named_property(env, priorityObj, "HIGH", highPriority);
52 napi_create_int32(env, Priority::MEDIUM, &mediumPriority);
53 napi_set_named_property(env, priorityObj, "MEDIUM", mediumPriority);
54 napi_create_int32(env, Priority::LOW, &lowPriority);
55 napi_set_named_property(env, priorityObj, "LOW", lowPriority);
56
57 napi_property_descriptor exportPriority[] = {
58 DECLARE_NAPI_PROPERTY("Priority", priorityObj),
59 };
60 napi_define_properties(env, exports, sizeof(exportPriority) / sizeof(exportPriority[0]), exportPriority);
61
62 // Add a reserved thread for taskpool
63 TaskManager::GetInstance().InitTaskRunner(env);
64 return exports;
65 }
66
Execute(napi_env env,napi_callback_info cbinfo)67 napi_value TaskPool::Execute(napi_env env, napi_callback_info cbinfo)
68 {
69 HITRACE_METER_NAME(HITRACE_TAG_COMMONLIBRARY, __PRETTY_FUNCTION__);
70 StartTrace(HITRACE_TAG_COMMONLIBRARY, "ExecuteToWorkerEnd");
71 // get the taskpool instance
72 TaskManager::GetInstance().InitTaskRunner(env);
73 FinishTrace(HITRACE_TAG_COMMONLIBRARY);
74 // check the argc
75 size_t argc = 0;
76 napi_get_cb_info(env, cbinfo, &argc, nullptr, nullptr, nullptr);
77 if (argc < 1) {
78 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "taskpool:: the number of params must be at least one");
79 return nullptr;
80 }
81
82 // check the first param is object or func
83 napi_value* args = new napi_value[argc];
84 ObjectScope<napi_value> scope(args, true);
85 napi_value thisVar = nullptr;
86 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
87 napi_valuetype type;
88 NAPI_CALL(env, napi_typeof(env, args[0], &type));
89
90 if (type == napi_object) {
91 Task* task = nullptr;
92 NAPI_CALL(env, napi_unwrap(env, args[0], reinterpret_cast<void**>(&task)));
93 return ExecuteTask(env, task);
94 } else if (type == napi_function) {
95 napi_value argsArray;
96 napi_create_array_with_length(env, argc - 1, &argsArray);
97 for (size_t i = 0; i < argc - 1; i++) {
98 napi_set_element(env, argsArray, i, args[i + 1]);
99 }
100 napi_value object;
101 napi_create_object(env, &object);
102 napi_set_named_property(env, object, "func", args[0]);
103 napi_set_named_property(env, object, "args", argsArray);
104 return ExecuteFunction(env, object);
105 }
106 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "taskpool:: first param must be object or function");
107 return nullptr;
108 }
109
HandleTaskResult(const uv_async_t * req)110 void TaskPool::HandleTaskResult(const uv_async_t* req)
111 {
112 HITRACE_METER_NAME(HITRACE_TAG_COMMONLIBRARY, __PRETTY_FUNCTION__);
113 auto taskInfo = static_cast<TaskInfo*>(req->data);
114 if (taskInfo == nullptr) {
115 HILOG_FATAL("taskpool::HandleTaskResult taskInfo is null");
116 return;
117 }
118 napi_value taskData = nullptr;
119 napi_status status = napi_deserialize(taskInfo->env, taskInfo->result, &taskData);
120 if (status != napi_ok || taskData == nullptr || !taskInfo->success) {
121 napi_reject_deferred(taskInfo->env, taskInfo->deferred, taskData);
122 } else {
123 napi_resolve_deferred(taskInfo->env, taskInfo->deferred, taskData);
124 }
125 TaskManager::GetInstance().ReleaseTaskContent(taskInfo);
126 }
127
ExecuteTask(napi_env env,Task * task)128 napi_value TaskPool::ExecuteTask(napi_env env, Task* task)
129 {
130 HITRACE_METER_NAME(HITRACE_TAG_COMMONLIBRARY, __PRETTY_FUNCTION__);
131 napi_value obj = nullptr;
132 napi_get_reference_value(env, task->objRef_, &obj);
133 task->executeId_ = TaskManager::GetInstance().GenerateExecuteId();
134 TaskInfo* taskInfo = TaskManager::GetInstance().GenerateTaskInfo(env, obj, task->taskId_, task->executeId_);
135 if (taskInfo == nullptr) {
136 return nullptr;
137 }
138 TaskManager::GetInstance().StoreStateInfo(taskInfo->executeId, TaskState::WAITING);
139 TaskManager::GetInstance().StoreRunningInfo(taskInfo->taskId, taskInfo->executeId);
140 napi_create_promise(env, &taskInfo->deferred, &taskInfo->promise);
141 Task* currentTask = new Task();
142 *currentTask = *task;
143 std::unique_ptr<Task> pointer(currentTask);
144 TaskManager::GetInstance().EnqueueTask(std::move(pointer));
145 if (taskInfo->promise == nullptr) {
146 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "taskpool:: create promise error");
147 return nullptr;
148 }
149 return taskInfo->promise;
150 }
151
ExecuteFunction(napi_env env,napi_value object)152 napi_value TaskPool::ExecuteFunction(napi_env env, napi_value object)
153 {
154 HITRACE_METER_NAME(HITRACE_TAG_COMMONLIBRARY, __PRETTY_FUNCTION__);
155 std::unique_ptr<Task> task = std::make_unique<Task>();
156 task->executeId_ = TaskManager::GetInstance().GenerateExecuteId();
157 TaskInfo* taskInfo = TaskManager::GetInstance().GenerateTaskInfo(env, object, 0, task->executeId_);
158 if (taskInfo == nullptr) {
159 return nullptr;
160 }
161 napi_create_promise(env, &taskInfo->deferred, &taskInfo->promise);
162 TaskManager::GetInstance().EnqueueTask(std::move(task));
163 if (taskInfo->promise == nullptr) {
164 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "taskpool:: create promise error");
165 return nullptr;
166 }
167 return taskInfo->promise;
168 }
169
Cancel(napi_env env,napi_callback_info cbinfo)170 napi_value TaskPool::Cancel(napi_env env, napi_callback_info cbinfo)
171 {
172 HITRACE_METER_NAME(HITRACE_TAG_COMMONLIBRARY, __PRETTY_FUNCTION__);
173 size_t argc = 0;
174 napi_get_cb_info(env, cbinfo, &argc, nullptr, nullptr, nullptr);
175 if (argc != 1) {
176 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "taskpool:: the number of the params must be one");
177 return nullptr;
178 }
179
180 napi_value* args = new napi_value[argc];
181 ObjectScope<napi_value> scope(args, true);
182 napi_value thisVar = nullptr;
183 napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, nullptr);
184 napi_valuetype type;
185 NAPI_CALL(env, napi_typeof(env, args[0], &type));
186 if (type != napi_object) {
187 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "taskpool:: the type of the params must be object");
188 return nullptr;
189 }
190 Task* task = nullptr;
191 NAPI_CALL(env, napi_unwrap(env, args[0], reinterpret_cast<void**>(&task)));
192 TaskManager::GetInstance().CancelTask(env, task->taskId_);
193 return nullptr;
194 }
195 } // namespace Commonlibrary::Concurrent::TaskPoolModule