1/*
2 * Copyright (c) 2021 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 "ecmascript/taskpool/runner.h"
17
18#ifdef ENABLE_QOS
19#include "qos.h"
20#endif
21
22namespace panda::ecmascript {
23Runner::Runner(uint32_t threadNum, const std::function<void(os::thread::native_handle_type)> prologueHook,
24    const std::function<void(os::thread::native_handle_type)> epilogueHook)
25    : totalThreadNum_(threadNum),
26    prologueHook_(prologueHook),
27    epilogueHook_(epilogueHook)
28{
29    for (uint32_t i = 0; i < threadNum; i++) {
30        // main thread is 0;
31        std::unique_ptr<std::thread> thread = std::make_unique<std::thread>([this, i] {this->Run(i + 1);});
32        threadPool_.emplace_back(std::move(thread));
33    }
34
35    for (uint32_t i = 0; i < runningTask_.size(); i++) {
36        runningTask_[i] = nullptr;
37    }
38}
39
40void Runner::TerminateTask(int32_t id, TaskType type)
41{
42    taskQueue_.TerminateTask(id, type);
43    LockHolder holder(mtx_);
44    for (uint32_t i = 0; i < runningTask_.size(); i++) {
45        if (runningTask_[i] != nullptr) {
46            if (id != ALL_TASK_ID && id != runningTask_[i]->GetId()) {
47                continue;
48            }
49            if (type != TaskType::ALL && type != runningTask_[i]->GetTaskType()) {
50                continue;
51            }
52            runningTask_[i]->Terminated();
53        }
54    }
55}
56
57void Runner::TerminateThread()
58{
59    TerminateTask(ALL_TASK_ID, TaskType::ALL);
60    taskQueue_.Terminate();
61
62    LockHolder holder(mtxPool_);
63    uint32_t threadNum = threadPool_.size();
64    for (uint32_t i = 0; i < threadNum; i++) {
65        threadPool_.at(i)->join();
66    }
67    threadPool_.clear();
68}
69
70void Runner::ForEachTask(const std::function<void(Task*)> &f)
71{
72    taskQueue_.ForEachTask(f);
73    LockHolder holder(mtx_);
74    for (uint32_t i = 0; i < runningTask_.size(); i++) {
75        if (runningTask_[i] != nullptr) {
76            f(runningTask_[i]);
77        }
78    }
79}
80
81void Runner::SetQosPriority([[maybe_unused]] PriorityMode mode)
82{
83#ifdef ENABLE_QOS
84    switch (mode) {
85        case PriorityMode::STW: {
86            for (uint32_t threadId : gcThreadId_) {
87                OHOS::QOS::SetQosForOtherThread(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE, threadId);
88            }
89            return;
90        }
91        case PriorityMode::FOREGROUND: {
92            for (uint32_t threadId : gcThreadId_) {
93                OHOS::QOS::SetQosForOtherThread(OHOS::QOS::QosLevel::QOS_USER_INITIATED, threadId);
94            }
95            return;
96        }
97        case PriorityMode::BACKGROUND: {
98            for (uint32_t threadId : gcThreadId_) {
99                OHOS::QOS::ResetQosForOtherThread(threadId);
100            }
101            return;
102        }
103        default:
104            UNREACHABLE();
105            break;
106    }
107#endif
108}
109
110void Runner::RecordThreadId()
111{
112    LockHolder holder(mtx_);
113    gcThreadId_.emplace_back(os::thread::GetCurrentThreadId());
114}
115
116void Runner::SetRunTask(uint32_t threadId, Task *task)
117{
118    LockHolder holder(mtx_);
119    runningTask_[threadId] = task;
120}
121
122void Runner::Run(uint32_t threadId)
123{
124    os::thread::native_handle_type thread = os::thread::GetNativeHandle();
125    os::thread::SetThreadName(thread, "OS_GC_Thread");
126    PrologueHook(thread);
127    RecordThreadId();
128    while (std::unique_ptr<Task> task = taskQueue_.PopTask()) {
129        SetRunTask(threadId, task.get());
130        task->Run(threadId);
131        SetRunTask(threadId, nullptr);
132    }
133    EpilogueHook(thread);
134}
135}  // namespace panda::ecmascript
136