14d6c458bSopenharmony_ci/* 24d6c458bSopenharmony_ci * Copyright (c) 2022 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#ifndef JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H 174d6c458bSopenharmony_ci#define JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H 184d6c458bSopenharmony_ci 194d6c458bSopenharmony_ci#include <mutex> 204d6c458bSopenharmony_ci 214d6c458bSopenharmony_ci#if defined(ENABLE_TASKPOOL_FFRT) 224d6c458bSopenharmony_ci#include "cpp/task.h" 234d6c458bSopenharmony_ci#endif 244d6c458bSopenharmony_ci#include "helper/concurrent_helper.h" 254d6c458bSopenharmony_ci#include "helper/error_helper.h" 264d6c458bSopenharmony_ci#include "helper/napi_helper.h" 274d6c458bSopenharmony_ci#include "helper/object_helper.h" 284d6c458bSopenharmony_ci#include "message_queue.h" 294d6c458bSopenharmony_ci#include "napi/native_api.h" 304d6c458bSopenharmony_ci#include "napi/native_node_api.h" 314d6c458bSopenharmony_ci#include "native_engine/native_engine.h" 324d6c458bSopenharmony_ci#include "qos_helper.h" 334d6c458bSopenharmony_ci#include "task.h" 344d6c458bSopenharmony_ci#include "task_runner.h" 354d6c458bSopenharmony_ci#include "tools/log.h" 364d6c458bSopenharmony_ci 374d6c458bSopenharmony_cinamespace Commonlibrary::Concurrent::TaskPoolModule { 384d6c458bSopenharmony_ciusing namespace Commonlibrary::Concurrent::Common; 394d6c458bSopenharmony_ciusing namespace Commonlibrary::Concurrent::Common::Helper; 404d6c458bSopenharmony_ciusing namespace Commonlibrary::Platform; 414d6c458bSopenharmony_ciusing MsgQueue = MessageQueue<TaskResultInfo*>; 424d6c458bSopenharmony_ci 434d6c458bSopenharmony_cienum class WorkerState { IDLE, RUNNING, BLOCKED }; 444d6c458bSopenharmony_ci 454d6c458bSopenharmony_ci#if defined(ENABLE_TASKPOOL_FFRT) 464d6c458bSopenharmony_cistatic const std::map<Priority, int> WORKERPRIORITY_FFRTQOS_MAP = { 474d6c458bSopenharmony_ci {Priority::IDLE, ffrt::qos_background}, 484d6c458bSopenharmony_ci {Priority::LOW, ffrt::qos_utility}, 494d6c458bSopenharmony_ci {Priority::MEDIUM, ffrt::qos_default}, 504d6c458bSopenharmony_ci {Priority::HIGH, ffrt::qos_user_initiated}, 514d6c458bSopenharmony_ci}; 524d6c458bSopenharmony_ci#endif 534d6c458bSopenharmony_ci 544d6c458bSopenharmony_ciclass Worker { 554d6c458bSopenharmony_cipublic: 564d6c458bSopenharmony_ci using DebuggerPostTask = std::function<void()>; 574d6c458bSopenharmony_ci 584d6c458bSopenharmony_ci static Worker* WorkerConstructor(napi_env env); 594d6c458bSopenharmony_ci 604d6c458bSopenharmony_ci void NotifyExecuteTask(); 614d6c458bSopenharmony_ci 624d6c458bSopenharmony_ci void Enqueue(napi_env env, TaskResultInfo* resultInfo) 634d6c458bSopenharmony_ci { 644d6c458bSopenharmony_ci std::lock_guard<std::mutex> lock(queueMutex_); 654d6c458bSopenharmony_ci msgQueueMap_[env].EnQueue(resultInfo); 664d6c458bSopenharmony_ci } 674d6c458bSopenharmony_ci 684d6c458bSopenharmony_ci void Dequeue(napi_env env, MsgQueue*& queue) 694d6c458bSopenharmony_ci { 704d6c458bSopenharmony_ci std::lock_guard<std::mutex> lock(queueMutex_); 714d6c458bSopenharmony_ci auto item = msgQueueMap_.find(env); 724d6c458bSopenharmony_ci if (item != msgQueueMap_.end()) { 734d6c458bSopenharmony_ci queue = &(item->second); 744d6c458bSopenharmony_ci } 754d6c458bSopenharmony_ci } 764d6c458bSopenharmony_ci 774d6c458bSopenharmony_ci void NotifyTaskBegin(); 784d6c458bSopenharmony_ci // the function will only be called when the task is finished or 794d6c458bSopenharmony_ci // exits abnormally, so we can not put it in the scope directly 804d6c458bSopenharmony_ci void NotifyTaskFinished(); 814d6c458bSopenharmony_ci static void NotifyTaskResult(napi_env env, Task* task, napi_value result); 824d6c458bSopenharmony_ci static void NotifyHandleTaskResult(Task* task); 834d6c458bSopenharmony_ci 844d6c458bSopenharmony_ci#if defined(ENABLE_TASKPOOL_FFRT) 854d6c458bSopenharmony_ci bool IsLoopActive(); 864d6c458bSopenharmony_ci uint64_t GetWaitTime(); 874d6c458bSopenharmony_ci#endif 884d6c458bSopenharmony_ci 894d6c458bSopenharmony_ciprivate: 904d6c458bSopenharmony_ci explicit Worker(napi_env env) : hostEnv_(env) {}; 914d6c458bSopenharmony_ci 924d6c458bSopenharmony_ci ~Worker() = default; 934d6c458bSopenharmony_ci 944d6c458bSopenharmony_ci Worker(const Worker &) = delete; 954d6c458bSopenharmony_ci Worker& operator=(const Worker &) = delete; 964d6c458bSopenharmony_ci Worker(Worker &&) = delete; 974d6c458bSopenharmony_ci Worker& operator=(Worker &&) = delete; 984d6c458bSopenharmony_ci 994d6c458bSopenharmony_ci void NotifyIdle(); 1004d6c458bSopenharmony_ci void NotifyWorkerCreated(); 1014d6c458bSopenharmony_ci void NotifyTaskRunning() 1024d6c458bSopenharmony_ci { 1034d6c458bSopenharmony_ci state_ = WorkerState::RUNNING; 1044d6c458bSopenharmony_ci startTime_ = ConcurrentHelper::GetMilliseconds(); 1054d6c458bSopenharmony_ci runningCount_++; 1064d6c458bSopenharmony_ci } 1074d6c458bSopenharmony_ci 1084d6c458bSopenharmony_ci bool HasRunningTasks() const 1094d6c458bSopenharmony_ci { 1104d6c458bSopenharmony_ci return runningCount_ != 0; 1114d6c458bSopenharmony_ci } 1124d6c458bSopenharmony_ci 1134d6c458bSopenharmony_ci#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) 1144d6c458bSopenharmony_ci static void HandleDebuggerTask(const uv_async_t* req); 1154d6c458bSopenharmony_ci void DebuggerOnPostTask(std::function<void()>&& task); 1164d6c458bSopenharmony_ci#endif 1174d6c458bSopenharmony_ci 1184d6c458bSopenharmony_ci uv_loop_t* GetWorkerLoop() const 1194d6c458bSopenharmony_ci { 1204d6c458bSopenharmony_ci if (workerEnv_ != nullptr) { 1214d6c458bSopenharmony_ci return NapiHelper::GetLibUV(workerEnv_); 1224d6c458bSopenharmony_ci } 1234d6c458bSopenharmony_ci return nullptr; 1244d6c458bSopenharmony_ci } 1254d6c458bSopenharmony_ci 1264d6c458bSopenharmony_ci void RunLoop() const 1274d6c458bSopenharmony_ci { 1284d6c458bSopenharmony_ci uv_loop_t* loop = GetWorkerLoop(); 1294d6c458bSopenharmony_ci if (loop != nullptr) { 1304d6c458bSopenharmony_ci uv_run(loop, UV_RUN_DEFAULT); 1314d6c458bSopenharmony_ci } else { 1324d6c458bSopenharmony_ci HILOG_ERROR("taskpool:: Worker loop is nullptr when start worker loop"); 1334d6c458bSopenharmony_ci return; 1344d6c458bSopenharmony_ci } 1354d6c458bSopenharmony_ci } 1364d6c458bSopenharmony_ci 1374d6c458bSopenharmony_ci // we will use the scope to manage resources automatically, 1384d6c458bSopenharmony_ci // including the HandleScope and NotifyRunning/NotifyIdle 1394d6c458bSopenharmony_ci class RunningScope { 1404d6c458bSopenharmony_ci public: 1414d6c458bSopenharmony_ci explicit RunningScope(Worker* worker) : worker_(worker) 1424d6c458bSopenharmony_ci { 1434d6c458bSopenharmony_ci napi_open_handle_scope(worker_->workerEnv_, &scope_); 1444d6c458bSopenharmony_ci worker_->idleState_ = false; 1454d6c458bSopenharmony_ci worker->isExecutingLongTask_ = false; 1464d6c458bSopenharmony_ci worker_->NotifyTaskRunning(); 1474d6c458bSopenharmony_ci } 1484d6c458bSopenharmony_ci 1494d6c458bSopenharmony_ci ~RunningScope(); 1504d6c458bSopenharmony_ci 1514d6c458bSopenharmony_ci private: 1524d6c458bSopenharmony_ci Worker* worker_ = nullptr; 1534d6c458bSopenharmony_ci napi_handle_scope scope_ = nullptr; 1544d6c458bSopenharmony_ci }; 1554d6c458bSopenharmony_ci 1564d6c458bSopenharmony_ci // use PriorityScope to manage the priority setting of workers 1574d6c458bSopenharmony_ci // reset qos_user_initiated when exit PriorityScope 1584d6c458bSopenharmony_ci class PriorityScope { 1594d6c458bSopenharmony_ci public: 1604d6c458bSopenharmony_ci PriorityScope(Worker* worker, Priority taskPriority); 1614d6c458bSopenharmony_ci ~PriorityScope() 1624d6c458bSopenharmony_ci { 1634d6c458bSopenharmony_ci worker_->ResetWorkerPriority(); 1644d6c458bSopenharmony_ci } 1654d6c458bSopenharmony_ci 1664d6c458bSopenharmony_ci private: 1674d6c458bSopenharmony_ci Worker* worker_ = nullptr; 1684d6c458bSopenharmony_ci }; 1694d6c458bSopenharmony_ci 1704d6c458bSopenharmony_ci void StartExecuteInThread(); 1714d6c458bSopenharmony_ci static void ExecuteInThread(const void* data); 1724d6c458bSopenharmony_ci bool PrepareForWorkerInstance(); 1734d6c458bSopenharmony_ci void ReleaseWorkerThreadContent(); 1744d6c458bSopenharmony_ci void ResetWorkerPriority(); 1754d6c458bSopenharmony_ci bool CheckFreeConditions(); 1764d6c458bSopenharmony_ci bool UpdateWorkerState(WorkerState expect, WorkerState desired); 1774d6c458bSopenharmony_ci void StoreTaskId(uint64_t taskId); 1784d6c458bSopenharmony_ci bool InitTaskPoolFunc(napi_env env, napi_value func, Task* task); 1794d6c458bSopenharmony_ci void UpdateExecutedInfo(); 1804d6c458bSopenharmony_ci void UpdateLongTaskInfo(Task* task); 1814d6c458bSopenharmony_ci bool IsExecutingLongTask(); 1824d6c458bSopenharmony_ci bool HasLongTask(); 1834d6c458bSopenharmony_ci void TerminateTask(uint64_t taskId); 1844d6c458bSopenharmony_ci void CloseHandles(); 1854d6c458bSopenharmony_ci void PostReleaseSignal(); 1864d6c458bSopenharmony_ci 1874d6c458bSopenharmony_ci static void HandleFunctionException(napi_env env, Task* task); 1884d6c458bSopenharmony_ci static void PerformTask(const uv_async_t* req); 1894d6c458bSopenharmony_ci static void TaskResultCallback(napi_env env, napi_value result, bool success, void* data); 1904d6c458bSopenharmony_ci static void ReleaseWorkerHandles(const uv_async_t* req); 1914d6c458bSopenharmony_ci static void TriggerGCCheck(const uv_async_t* req); 1924d6c458bSopenharmony_ci 1934d6c458bSopenharmony_ci#if defined(ENABLE_TASKPOOL_FFRT) 1944d6c458bSopenharmony_ci void InitFfrtInfo(); 1954d6c458bSopenharmony_ci void InitLoopHandleNum(); 1964d6c458bSopenharmony_ci#endif 1974d6c458bSopenharmony_ci 1984d6c458bSopenharmony_ci napi_env hostEnv_ {nullptr}; 1994d6c458bSopenharmony_ci napi_env workerEnv_ {nullptr}; 2004d6c458bSopenharmony_ci uv_async_t* performTaskSignal_ {nullptr}; 2014d6c458bSopenharmony_ci uv_async_t* clearWorkerSignal_ {nullptr}; 2024d6c458bSopenharmony_ci uv_async_t* triggerGCCheckSignal_ {nullptr}; 2034d6c458bSopenharmony_ci#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) 2044d6c458bSopenharmony_ci uv_async_t* debuggerOnPostTaskSignal_ {nullptr}; 2054d6c458bSopenharmony_ci std::mutex debuggerMutex_; 2064d6c458bSopenharmony_ci std::queue<DebuggerPostTask> debuggerQueue_ {}; 2074d6c458bSopenharmony_ci#endif 2084d6c458bSopenharmony_ci std::unique_ptr<TaskRunner> runner_ {nullptr}; 2094d6c458bSopenharmony_ci 2104d6c458bSopenharmony_ci std::atomic<int32_t> runningCount_ = 0; 2114d6c458bSopenharmony_ci std::atomic<bool> idleState_ = true; // true means the worker is idle 2124d6c458bSopenharmony_ci std::atomic<uint64_t> idlePoint_ = ConcurrentHelper::GetMilliseconds(); 2134d6c458bSopenharmony_ci std::atomic<uint64_t> startTime_ = ConcurrentHelper::GetMilliseconds(); 2144d6c458bSopenharmony_ci std::atomic<WorkerState> state_ {WorkerState::IDLE}; 2154d6c458bSopenharmony_ci std::atomic<bool> hasExecuted_ = false; // false means this worker hasn't execute any tasks 2164d6c458bSopenharmony_ci Priority priority_ {Priority::DEFAULT}; 2174d6c458bSopenharmony_ci pid_t tid_ = 0; 2184d6c458bSopenharmony_ci std::vector<uint64_t> currentTaskId_ {}; 2194d6c458bSopenharmony_ci std::mutex currentTaskIdMutex_; 2204d6c458bSopenharmony_ci MessageQueue<TaskResultInfo*> hostMessageQueue_ {}; 2214d6c458bSopenharmony_ci uint64_t lastCpuTime_ = 0; 2224d6c458bSopenharmony_ci uint32_t idleCount_ = 0; 2234d6c458bSopenharmony_ci std::atomic<bool> hasLongTask_ = false; 2244d6c458bSopenharmony_ci std::atomic<bool> isExecutingLongTask_ = false; 2254d6c458bSopenharmony_ci std::mutex longMutex_; 2264d6c458bSopenharmony_ci std::unordered_set<uint64_t> longTasksSet_ {}; 2274d6c458bSopenharmony_ci std::mutex queueMutex_; // for sendData 2284d6c458bSopenharmony_ci std::unordered_map<napi_env, MsgQueue> msgQueueMap_ {}; 2294d6c458bSopenharmony_ci friend class TaskManager; 2304d6c458bSopenharmony_ci friend class NativeEngineTest; 2314d6c458bSopenharmony_ci 2324d6c458bSopenharmony_ci#if defined(ENABLE_TASKPOOL_FFRT) 2334d6c458bSopenharmony_ci void* ffrtTaskHandle_ = nullptr; 2344d6c458bSopenharmony_ci uint32_t initActiveHandleNum_ = 0; 2354d6c458bSopenharmony_ci#endif 2364d6c458bSopenharmony_ci}; 2374d6c458bSopenharmony_ci} // namespace Commonlibrary::Concurrent::TaskPoolModule 2384d6c458bSopenharmony_ci#endif // JS_CONCURRENT_MODULE_TASKPOOL_WORKER_H