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