• 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 #ifndef JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H
17 #define JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H
18 
19 #include <mutex>
20 
21 #if defined(ENABLE_TASKPOOL_FFRT)
22 #include "cpp/task.h"
23 #endif
24 #include "helper/concurrent_helper.h"
25 #include "helper/error_helper.h"
26 #include "helper/napi_helper.h"
27 #include "helper/object_helper.h"
28 #include "napi/native_api.h"
29 #include "napi/native_node_api.h"
30 #include "native_engine/native_engine.h"
31 #include "qos_helper.h"
32 #include "task.h"
33 #include "task_runner.h"
34 #include "tools/log.h"
35 
36 namespace Commonlibrary::Concurrent::TaskPoolModule {
37 using namespace Commonlibrary::Concurrent::Common;
38 using namespace Commonlibrary::Concurrent::Common::Helper;
39 using namespace Commonlibrary::Platform;
40 
41 enum class WorkerState { IDLE, RUNNING, BLOCKED };
42 
43 #if defined(ENABLE_TASKPOOL_FFRT)
44 static const std::map<Priority, int> WORKERPRIORITY_FFRTQOS_MAP = {
45     {Priority::IDLE, ffrt::qos_background},
46     {Priority::LOW, ffrt::qos_utility},
47     {Priority::MEDIUM, ffrt::qos_default},
48     {Priority::HIGH, ffrt::qos_user_initiated},
49 };
50 #endif
51 
52 struct ThreadInfo {
53     Priority priority {Priority::DEFAULT};
54     pid_t tid = 0;
55     std::vector<uint32_t> currentTaskId {};
56 };
57 
58 class Worker {
59 public:
60     using DebuggerPostTask = std::function<void()>;
61 
62     static Worker* WorkerConstructor(napi_env env);
63 
64     void NotifyExecuteTask();
65 
66     void NotifyTaskBegin();
67     // the function will only be called when the task is finished or
68     // exits abnormally, so we can not put it in the scope directly
69     void NotifyTaskFinished();
70 
71     Priority GetPriority() const;
72 
73     static void NotifyTaskResult(napi_env env, Task* task, napi_value result);
74     static void NotifyHandleTaskResult(Task* task);
75 
76 #if defined(ENABLE_TASKPOOL_FFRT)
77     bool IsLoopActive();
78     uint64_t GetWaitTime();
79 #endif
80 #if defined(ENABLE_TASKPOOL_HISYSEVENT)
81     bool IsNeedReport(uint64_t intervalTime);
82     void IncreaseReportCount();
83 #endif
84 
85 private:
Worker(napi_env env)86     explicit Worker(napi_env env) : hostEnv_(env) {};
87 
88     ~Worker() = default;
89 
90     Worker(const Worker &) = delete;
91     Worker& operator=(const Worker &) = delete;
92     Worker(Worker &&) = delete;
93     Worker& operator=(Worker &&) = delete;
94 
95     void NotifyIdle();
96     void NotifyWorkerCreated();
NotifyTaskRunning()97     void NotifyTaskRunning()
98     {
99         state_ = WorkerState::RUNNING;
100         startTime_ = ConcurrentHelper::GetMilliseconds();
101         runningCount_++;
102     }
103 
HasRunningTasks()104     bool HasRunningTasks() const
105     {
106         return runningCount_ != 0;
107     }
108 
109 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
110     static void HandleDebuggerTask(const uv_async_t* req);
111     void DebuggerOnPostTask(std::function<void()>&& task);
112 #endif
113 
GetWorkerLoop()114     uv_loop_t* GetWorkerLoop() const
115     {
116         if (workerEnv_ != nullptr) {
117             return NapiHelper::GetLibUV(workerEnv_);
118         }
119         return nullptr;
120     }
121 
RunLoop()122     void RunLoop() const
123     {
124         uv_loop_t* loop = GetWorkerLoop();
125         if (loop != nullptr) {
126             uv_run(loop, UV_RUN_DEFAULT);
127         } else {
128             HILOG_ERROR("taskpool:: Worker loop is nullptr when start worker loop");
129         }
130     }
131 
132     // we will use the scope to manage resources automatically,
133     // including the HandleScope and NotifyRunning/NotifyIdle
134     class RunningScope {
135     public:
RunningScope(Worker * worker)136         explicit RunningScope(Worker* worker) : worker_(worker)
137         {
138             napi_open_handle_scope(worker_->workerEnv_, &scope_);
139             worker_->idleState_ = false;
140             worker->isExecutingLongTask_ = false;
141             worker_->NotifyTaskRunning();
142         }
143 
144         ~RunningScope();
145 
146     private:
147         Worker* worker_ = nullptr;
148         napi_handle_scope scope_ = nullptr;
149     };
150 
151     // use PriorityScope to manage the priority setting of workers
152     // reset qos_user_initiated when exit PriorityScope
153     class PriorityScope {
154     public:
155         PriorityScope(Worker* worker, Priority taskPriority);
~PriorityScope()156         ~PriorityScope()
157         {
158             worker_->ResetPerformIdleState();
159             worker_->ResetWorkerPriority();
160         }
161 
162     private:
163         Worker* worker_ = nullptr;
164     };
165 
166     void StartExecuteInThread();
167     static void ExecuteInThread(const void* data);
168     bool PrepareForWorkerInstance();
169     void ReleaseWorkerThreadContent();
170     void ResetWorkerPriority();
171     bool CheckFreeConditions();
172     bool UpdateWorkerState(WorkerState expect, WorkerState desired);
173     void StoreTaskId(uint32_t taskId);
174     bool InitTaskPoolFunc(napi_env env, napi_value func, Task* task);
175     void UpdateExecutedInfo();
176     void UpdateLongTaskInfo(Task* task);
177     bool IsExecutingLongTask();
178     bool HasLongTask();
179     void TerminateTask(uint32_t taskId);
180     void CloseHandles();
181     void PostReleaseSignal();
182     bool IsRunnable(uint64_t currTime) const;
183     void UpdateWorkerWakeUpTime();
184     void EraseRunningTaskId(uint32_t taskId);
185 
186     static void HandleFunctionResult(napi_env env, Task* task);
187     static void PerformTask(const uv_async_t* req);
188     static void TaskResultCallback(napi_env env, napi_value result, bool success, void* data);
189     static void ReleaseWorkerHandles(const uv_async_t* req);
190     static void TriggerGCCheck(const uv_async_t* req);
191 
192 #if defined(ENABLE_TASKPOOL_FFRT)
193     void InitFfrtInfo();
194     void InitLoopHandleNum();
195 #endif
196     void ResetPerformIdleState();
197 
198     napi_env hostEnv_ {nullptr};
199     napi_env workerEnv_ {nullptr};
200     uv_async_t* performTaskSignal_ {nullptr};
201     uv_async_t* clearWorkerSignal_ {nullptr};
202     uv_async_t* triggerGCCheckSignal_ {nullptr};
203 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
204     uv_async_t* debuggerOnPostTaskSignal_ {nullptr};
205     std::mutex debuggerMutex_;
206     std::queue<DebuggerPostTask> debuggerQueue_ {};
207 #endif
208     std::unique_ptr<TaskRunner> runner_ {nullptr};
209 
210     std::atomic<int32_t> runningCount_ = 0;
211     std::atomic<bool> idleState_ = true; // true means the worker is idle
212     std::atomic<uint64_t> idlePoint_ = ConcurrentHelper::GetMilliseconds();
213     std::atomic<uint64_t> startTime_ = ConcurrentHelper::GetMilliseconds();
214     std::atomic<uint64_t> wakeUpTime_ = ConcurrentHelper::GetMilliseconds();
215     std::atomic<WorkerState> state_ {WorkerState::IDLE};
216     std::atomic<bool> hasExecuted_ = false; // false means this worker hasn't execute any tasks
217     Priority priority_ {Priority::DEFAULT};
218     pid_t tid_ = 0;
219     std::vector<uint32_t> currentTaskId_ {};
220     std::mutex currentTaskIdMutex_;
221     uint64_t lastCpuTime_ = 0;
222     uint32_t idleCount_ = 0;
223     std::atomic<bool> hasLongTask_ = false;
224     std::atomic<bool> isExecutingLongTask_ = false;
225     std::mutex longMutex_;
226     std::unordered_set<uint32_t> longTasksSet_ {};
227     friend class TaskManager;
228     friend class NativeEngineTest;
229 
230 #if defined(ENABLE_TASKPOOL_FFRT)
231     void* ffrtTaskHandle_ = nullptr;
232     uint32_t initActiveHandleNum_ = 0;
233 #endif
234 #if defined(ENABLE_TASKPOOL_HISYSEVENT)
235     std::atomic<int32_t> reportCount_ = 0;
236 #endif
237 };
238 } // namespace Commonlibrary::Concurrent::TaskPoolModule
239 #endif // JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H