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 #include "helper/concurrent_helper.h" 22 #include "helper/error_helper.h" 23 #include "helper/napi_helper.h" 24 #include "helper/object_helper.h" 25 #include "napi/native_api.h" 26 #include "napi/native_node_api.h" 27 #include "native_engine/native_engine.h" 28 #include "qos_helper.h" 29 #include "task.h" 30 #include "task_runner.h" 31 #include "utils/log.h" 32 33 namespace Commonlibrary::Concurrent::TaskPoolModule { 34 using namespace Commonlibrary::Concurrent::Common; 35 using namespace Commonlibrary::Concurrent::Common::Helper; 36 using namespace Commonlibrary::Platform; 37 38 enum class WorkerState { IDLE, RUNNING, BLOCKED }; 39 40 class Worker { 41 public: 42 static Worker* WorkerConstructor(napi_env env); 43 44 void NotifyExecuteTask(); 45 46 private: Worker(napi_env env)47 explicit Worker(napi_env env) : hostEnv_(env) {}; 48 49 ~Worker() = default; 50 51 Worker(const Worker &) = delete; 52 Worker& operator=(const Worker &) = delete; 53 Worker(Worker &&) = delete; 54 Worker& operator=(Worker &&) = delete; 55 56 void NotifyIdle(); 57 void NotifyWorkerCreated(); NotifyTaskRunning()58 void NotifyTaskRunning() 59 { 60 state_ = WorkerState::RUNNING; 61 startTime_ = ConcurrentHelper::GetMilliseconds(); 62 runningCount_++; 63 } 64 65 // the function will only be called when the task is finished or 66 // exits abnormally, so we can not put it in the scope directly 67 void NotifyTaskFinished(); 68 69 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) 70 static void HandleDebuggerTask(const uv_async_t* req); 71 void DebuggerOnPostTask(std::function<void()>&& task); 72 #endif 73 GetWorkerLoop()74 uv_loop_t* GetWorkerLoop() const 75 { 76 if (workerEnv_ != nullptr) { 77 return NapiHelper::GetLibUV(workerEnv_); 78 } 79 return nullptr; 80 } 81 RunLoop()82 void RunLoop() const 83 { 84 uv_loop_t* loop = GetWorkerLoop(); 85 if (loop != nullptr) { 86 uv_run(loop, UV_RUN_DEFAULT); 87 } else { 88 HILOG_ERROR("taskpool:: Worker loop is nullptr when start worker loop"); 89 return; 90 } 91 } 92 93 // we will use the scope to manage resources automatically, 94 // including the HandleScope and NotifyRunning/NotifyIdle 95 class RunningScope { 96 public: RunningScope(Worker * worker,napi_status & status)97 RunningScope(Worker* worker, napi_status& status) : worker_(worker) 98 { 99 status = napi_open_handle_scope(worker_->workerEnv_, &scope_); 100 worker_->NotifyTaskRunning(); 101 } 102 103 ~RunningScope(); 104 105 private: 106 Worker* worker_ = nullptr; 107 napi_handle_scope scope_ = nullptr; 108 }; 109 110 // use PriorityScope to manage the priority setting of workers 111 // reset qos_user_initiated when exit PriorityScope 112 class PriorityScope { 113 public: PriorityScope(Worker * worker,Priority taskPriority)114 PriorityScope(Worker* worker, Priority taskPriority) : worker_(worker) 115 { 116 if (taskPriority != worker->priority_) { 117 HILOG_DEBUG("taskpool:: reset worker priority to match task priority"); 118 SetWorkerPriority(taskPriority); 119 worker->priority_ = taskPriority; 120 } 121 } ~PriorityScope()122 ~PriorityScope() 123 { 124 worker_->ResetWorkerPriority(); 125 } 126 127 private: 128 Worker* worker_ = nullptr; 129 }; 130 131 void StartExecuteInThread(); 132 static void ExecuteInThread(const void* data); 133 bool PrepareForWorkerInstance(); 134 void ReleaseWorkerThreadContent(); 135 void ResetWorkerPriority(); 136 static void PerformTask(const uv_async_t* req); 137 static void TaskResultCallback(NativeEngine* engine, NativeValue* result, bool success, void* data); 138 static void NotifyTaskResult(napi_env env, TaskInfo* taskInfo, napi_value result); 139 static void ReleaseWorkerHandles(const uv_async_t* req); 140 141 napi_env hostEnv_ {nullptr}; 142 napi_env workerEnv_ {nullptr}; 143 uv_async_t* performTaskSignal_ {nullptr}; 144 uv_async_t* clearWorkerSignal_ {nullptr}; 145 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) 146 uv_async_t* debuggerOnPostTaskSignal_ {nullptr}; 147 std::function<void()> debuggerTask_; 148 #endif 149 std::unique_ptr<TaskRunner> runner_ {nullptr}; 150 151 std::atomic<uint64_t> startTime_ = 0; 152 std::atomic<int32_t> runningCount_ = 0; 153 std::atomic<uint64_t> idlePoint_ = ConcurrentHelper::GetMilliseconds(); 154 WorkerState state_ {WorkerState::IDLE}; 155 std::mutex stateMutex_; 156 Priority priority_ {Priority::DEFAULT}; 157 pid_t tid_ = 0; 158 std::vector<uint32_t> currentTaskId_ {}; 159 std::mutex currentTaskIdMutex_; 160 161 friend class TaskManager; 162 }; 163 } // namespace Commonlibrary::Concurrent::TaskPoolModule 164 #endif // JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H 165