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