• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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