• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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/daemon/daemon_task-inl.h"
17 #include "ecmascript/daemon/daemon_thread.h"
18 #include "ecmascript/runtime.h"
19 
20 #ifdef ENABLE_QOS
21 #include "qos.h"
22 #endif
23 
24 namespace panda::ecmascript {
25 
26 DaemonThread *DaemonThread::instance_ = nullptr;
27 
CreateNewInstance()28 void DaemonThread::CreateNewInstance()
29 {
30     ASSERT(instance_ == nullptr);
31     instance_ = new DaemonThread();
32     instance_->StartRunning();
33 }
34 
GetInstance()35 DaemonThread *DaemonThread::GetInstance()
36 {
37     ASSERT(instance_ != nullptr);
38     return instance_;
39 }
40 
DestroyInstance()41 void DaemonThread::DestroyInstance()
42 {
43     ASSERT(instance_ != nullptr);
44     instance_->WaitFinished();
45     delete instance_;
46     instance_ = nullptr;
47 }
48 
StartRunning()49 void DaemonThread::StartRunning()
50 {
51     ASSERT(thread_ == nullptr);
52     ASSERT(!IsRunning());
53     ASSERT(tasks_.empty());
54     Taskpool::GetCurrentTaskpool()->Initialize();
55     ASSERT(GetThreadId() == 0);
56     thread_ = std::make_unique<std::thread>([this] {this->Run();});
57     // Wait until daemon thread is running.
58     while (!IsRunning());
59 #ifdef ENABLE_QOS
60     OHOS::QOS::SetQosForOtherThread(OHOS::QOS::QosLevel::QOS_USER_INITIATED, GetThreadId());
61 #endif
62     ASSERT(GetThreadId() != 0);
63 }
64 
IsRunning() const65 bool DaemonThread::IsRunning() const
66 {
67     return running_.load(std::memory_order_acquire);
68 }
69 
MarkTerminate()70 void DaemonThread::MarkTerminate()
71 {
72     running_.store(false, std::memory_order_release);
73 }
74 
WaitFinished()75 void DaemonThread::WaitFinished()
76 {
77     if (IsRunning()) {
78         CheckAndPostTask(TerminateDaemonTask(nullptr));
79         thread_->join();
80         thread_.reset();
81         Taskpool::GetCurrentTaskpool()->Destroy(GetThreadId());
82     }
83     ASSERT(!IsInRunningState());
84     ASSERT(!IsRunning());
85     ASSERT(thread_ == nullptr);
86     ASSERT(tasks_.empty());
87     ResetThreadId();
88 }
89 
CheckAndPostTask(DaemonTask task)90 bool DaemonThread::CheckAndPostTask(DaemonTask task)
91 {
92     if (UNLIKELY(!IsRunning())) {
93         LOG_GC(FATAL) << "Try to post task to terminated daemon thread, taskType = "
94                       << static_cast<uint32_t>(task.GetTaskType());
95         UNREACHABLE();
96     }
97     LockHolder holder(mtx_);
98     if (AddTaskGroup(task.GetTaskGroup())) {
99         tasks_.emplace_back(task);
100         cv_.Signal();
101         return true;
102     }
103     return false;
104 }
105 
Run()106 void DaemonThread::Run()
107 {
108     ASSERT(!IsRunning());
109     os::thread::native_handle_type thread = os::thread::GetNativeHandle();
110     os::thread::SetThreadName(thread, "OS_GC_Thread");
111     ASSERT(JSThread::GetCurrent() == nullptr);
112     RegisterThread(this);
113     SetThreadId();
114     running_.store(true, std::memory_order_release);
115     ASSERT(JSThread::GetCurrent() == this);
116     // Load running_ here do not need atomic, because only daemon thread will set it to false
117     while (running_.load(std::memory_order_acquire)) {
118         ASSERT(!IsInRunningState());
119         DaemonTask task = PopTask();
120         runningGroup_ = task.GetTaskGroup();
121         task.Run();
122         ASSERT(runningGroup_ == DaemonTaskGroup::NONE);
123     }
124     ASSERT(postedGroups_ == 0);
125     ASSERT(tasks_.empty());
126     UnregisterThread(this);
127 }
128 
AddTaskGroup(DaemonTaskGroup taskGroup)129 bool DaemonThread::AddTaskGroup(DaemonTaskGroup taskGroup)
130 {
131     if ((postedGroups_ & static_cast<uint32_t>(taskGroup)) != 0) {
132         return false;
133     }
134     postedGroups_ |= static_cast<uint32_t>(taskGroup);
135     return true;
136 }
137 
FinishRunningTask()138 void DaemonThread::FinishRunningTask()
139 {
140     ASSERT(runningGroup_ != DaemonTaskGroup::NONE);
141     ASSERT((postedGroups_ & static_cast<uint32_t>(runningGroup_)) != 0);
142     // Update to postedGroups_ is in DaemeanSuspendAll, and protected by the Runtime::mutatorLock_,
143     // so do not need lock; the runningGroup_ is only used in daemon thread, so do not need lock too.
144     postedGroups_ &= ~static_cast<uint32_t>(runningGroup_);
145     runningGroup_ = DaemonTaskGroup::NONE;
146 }
147 
PopTask()148 DaemonTask DaemonThread::PopTask()
149 {
150     LockHolder holder(mtx_);
151     while (true) {
152         if (!tasks_.empty()) {
153             DaemonTask task = tasks_.front();
154             tasks_.pop_front();
155             return task;
156         }
157         cv_.Wait(&mtx_);
158     }
159 }
160 
SetSharedMarkStatus(SharedMarkStatus markStatus)161 void DaemonThread::SetSharedMarkStatus(SharedMarkStatus markStatus)
162 {
163     ASSERT(os::thread::GetCurrentThreadId() == GetThreadId());
164     markStatus_.store(markStatus, std::memory_order_release);
165     Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
166         ASSERT(!thread->IsInRunningState());
167         thread->SetSharedMarkStatus(markStatus);
168     });
169 }
170 
171 #ifndef NDEBUG
GetMutatorLockState() const172 MutatorLock::MutatorLockState DaemonThread::GetMutatorLockState() const
173 {
174     return mutatorLockState_;
175 }
176 
SetMutatorLockState(MutatorLock::MutatorLockState newState)177 void DaemonThread::SetMutatorLockState(MutatorLock::MutatorLockState newState)
178 {
179     mutatorLockState_ = newState;
180 }
181 #endif
182 }  // namespace panda::ecmascript