14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/daemon/daemon_task-inl.h"
174514f5e3Sopenharmony_ci#include "ecmascript/daemon/daemon_thread.h"
184514f5e3Sopenharmony_ci#include "ecmascript/runtime.h"
194514f5e3Sopenharmony_ci
204514f5e3Sopenharmony_ci#ifdef ENABLE_QOS
214514f5e3Sopenharmony_ci#include "qos.h"
224514f5e3Sopenharmony_ci#endif
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_cinamespace panda::ecmascript {
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_ciDaemonThread *DaemonThread::instance_ = nullptr;
274514f5e3Sopenharmony_ci
284514f5e3Sopenharmony_civoid DaemonThread::CreateNewInstance()
294514f5e3Sopenharmony_ci{
304514f5e3Sopenharmony_ci    ASSERT(instance_ == nullptr);
314514f5e3Sopenharmony_ci    instance_ = new DaemonThread();
324514f5e3Sopenharmony_ci    instance_->StartRunning();
334514f5e3Sopenharmony_ci}
344514f5e3Sopenharmony_ci
354514f5e3Sopenharmony_ciDaemonThread *DaemonThread::GetInstance()
364514f5e3Sopenharmony_ci{
374514f5e3Sopenharmony_ci    ASSERT(instance_ != nullptr);
384514f5e3Sopenharmony_ci    return instance_;
394514f5e3Sopenharmony_ci}
404514f5e3Sopenharmony_ci
414514f5e3Sopenharmony_civoid DaemonThread::DestroyInstance()
424514f5e3Sopenharmony_ci{
434514f5e3Sopenharmony_ci    ASSERT(instance_ != nullptr);
444514f5e3Sopenharmony_ci    instance_->WaitFinished();
454514f5e3Sopenharmony_ci    delete instance_;
464514f5e3Sopenharmony_ci    instance_ = nullptr;
474514f5e3Sopenharmony_ci}
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_civoid DaemonThread::StartRunning()
504514f5e3Sopenharmony_ci{
514514f5e3Sopenharmony_ci    ASSERT(thread_ == nullptr);
524514f5e3Sopenharmony_ci    ASSERT(!IsRunning());
534514f5e3Sopenharmony_ci    ASSERT(tasks_.empty());
544514f5e3Sopenharmony_ci    Taskpool::GetCurrentTaskpool()->Initialize();
554514f5e3Sopenharmony_ci    ASSERT(GetThreadId() == 0);
564514f5e3Sopenharmony_ci    thread_ = std::make_unique<std::thread>([this] {this->Run();});
574514f5e3Sopenharmony_ci    // Wait until daemon thread is running.
584514f5e3Sopenharmony_ci    while (!IsRunning());
594514f5e3Sopenharmony_ci#ifdef ENABLE_QOS
604514f5e3Sopenharmony_ci    OHOS::QOS::SetQosForOtherThread(OHOS::QOS::QosLevel::QOS_USER_INITIATED, GetThreadId());
614514f5e3Sopenharmony_ci#endif
624514f5e3Sopenharmony_ci    ASSERT(GetThreadId() != 0);
634514f5e3Sopenharmony_ci}
644514f5e3Sopenharmony_ci
654514f5e3Sopenharmony_cibool DaemonThread::IsRunning() const
664514f5e3Sopenharmony_ci{
674514f5e3Sopenharmony_ci    return running_.load(std::memory_order_acquire);
684514f5e3Sopenharmony_ci}
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_civoid DaemonThread::MarkTerminate()
714514f5e3Sopenharmony_ci{
724514f5e3Sopenharmony_ci    running_.store(false, std::memory_order_release);
734514f5e3Sopenharmony_ci}
744514f5e3Sopenharmony_ci
754514f5e3Sopenharmony_civoid DaemonThread::WaitFinished()
764514f5e3Sopenharmony_ci{
774514f5e3Sopenharmony_ci    if (IsRunning()) {
784514f5e3Sopenharmony_ci        CheckAndPostTask(TerminateDaemonTask(nullptr));
794514f5e3Sopenharmony_ci        thread_->join();
804514f5e3Sopenharmony_ci        thread_.reset();
814514f5e3Sopenharmony_ci        Taskpool::GetCurrentTaskpool()->Destroy(GetThreadId());
824514f5e3Sopenharmony_ci    }
834514f5e3Sopenharmony_ci    ASSERT(!IsInRunningState());
844514f5e3Sopenharmony_ci    ASSERT(!IsRunning());
854514f5e3Sopenharmony_ci    ASSERT(thread_ == nullptr);
864514f5e3Sopenharmony_ci    ASSERT(tasks_.empty());
874514f5e3Sopenharmony_ci    ResetThreadId();
884514f5e3Sopenharmony_ci}
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_cibool DaemonThread::CheckAndPostTask(DaemonTask task)
914514f5e3Sopenharmony_ci{
924514f5e3Sopenharmony_ci    if (UNLIKELY(!IsRunning())) {
934514f5e3Sopenharmony_ci        LOG_GC(FATAL) << "Try to post task to terminated daemon thread, taskType = "
944514f5e3Sopenharmony_ci                      << static_cast<uint32_t>(task.GetTaskType());
954514f5e3Sopenharmony_ci        UNREACHABLE();
964514f5e3Sopenharmony_ci    }
974514f5e3Sopenharmony_ci    LockHolder holder(mtx_);
984514f5e3Sopenharmony_ci    if (AddTaskGroup(task.GetTaskGroup())) {
994514f5e3Sopenharmony_ci        tasks_.emplace_back(task);
1004514f5e3Sopenharmony_ci        cv_.Signal();
1014514f5e3Sopenharmony_ci        return true;
1024514f5e3Sopenharmony_ci    }
1034514f5e3Sopenharmony_ci    return false;
1044514f5e3Sopenharmony_ci}
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_civoid DaemonThread::Run()
1074514f5e3Sopenharmony_ci{
1084514f5e3Sopenharmony_ci    ASSERT(!IsRunning());
1094514f5e3Sopenharmony_ci    os::thread::native_handle_type thread = os::thread::GetNativeHandle();
1104514f5e3Sopenharmony_ci    os::thread::SetThreadName(thread, "OS_GC_Thread");
1114514f5e3Sopenharmony_ci    ASSERT(JSThread::GetCurrent() == nullptr);
1124514f5e3Sopenharmony_ci    RegisterThread(this);
1134514f5e3Sopenharmony_ci    SetThreadId();
1144514f5e3Sopenharmony_ci    running_.store(true, std::memory_order_release);
1154514f5e3Sopenharmony_ci    ASSERT(JSThread::GetCurrent() == this);
1164514f5e3Sopenharmony_ci    // Load running_ here do not need atomic, because only daemon thread will set it to false
1174514f5e3Sopenharmony_ci    while (running_.load(std::memory_order_acquire)) {
1184514f5e3Sopenharmony_ci        ASSERT(!IsInRunningState());
1194514f5e3Sopenharmony_ci        DaemonTask task = PopTask();
1204514f5e3Sopenharmony_ci        runningGroup_ = task.GetTaskGroup();
1214514f5e3Sopenharmony_ci        task.Run();
1224514f5e3Sopenharmony_ci        ASSERT(runningGroup_ == DaemonTaskGroup::NONE);
1234514f5e3Sopenharmony_ci    }
1244514f5e3Sopenharmony_ci    ASSERT(postedGroups_ == 0);
1254514f5e3Sopenharmony_ci    ASSERT(tasks_.empty());
1264514f5e3Sopenharmony_ci    UnregisterThread(this);
1274514f5e3Sopenharmony_ci}
1284514f5e3Sopenharmony_ci
1294514f5e3Sopenharmony_cibool DaemonThread::AddTaskGroup(DaemonTaskGroup taskGroup)
1304514f5e3Sopenharmony_ci{
1314514f5e3Sopenharmony_ci    if ((postedGroups_ & static_cast<uint32_t>(taskGroup)) != 0) {
1324514f5e3Sopenharmony_ci        return false;
1334514f5e3Sopenharmony_ci    }
1344514f5e3Sopenharmony_ci    postedGroups_ |= static_cast<uint32_t>(taskGroup);
1354514f5e3Sopenharmony_ci    return true;
1364514f5e3Sopenharmony_ci}
1374514f5e3Sopenharmony_ci
1384514f5e3Sopenharmony_civoid DaemonThread::FinishRunningTask()
1394514f5e3Sopenharmony_ci{
1404514f5e3Sopenharmony_ci    ASSERT(runningGroup_ != DaemonTaskGroup::NONE);
1414514f5e3Sopenharmony_ci    ASSERT((postedGroups_ & static_cast<uint32_t>(runningGroup_)) != 0);
1424514f5e3Sopenharmony_ci    // Update to postedGroups_ is in DaemeanSuspendAll, and protected by the Runtime::mutatorLock_,
1434514f5e3Sopenharmony_ci    // so do not need lock; the runningGroup_ is only used in daemon thread, so do not need lock too.
1444514f5e3Sopenharmony_ci    postedGroups_ &= ~static_cast<uint32_t>(runningGroup_);
1454514f5e3Sopenharmony_ci    runningGroup_ = DaemonTaskGroup::NONE;
1464514f5e3Sopenharmony_ci}
1474514f5e3Sopenharmony_ci
1484514f5e3Sopenharmony_ciDaemonTask DaemonThread::PopTask()
1494514f5e3Sopenharmony_ci{
1504514f5e3Sopenharmony_ci    LockHolder holder(mtx_);
1514514f5e3Sopenharmony_ci    while (true) {
1524514f5e3Sopenharmony_ci        if (!tasks_.empty()) {
1534514f5e3Sopenharmony_ci            DaemonTask task = tasks_.front();
1544514f5e3Sopenharmony_ci            tasks_.pop_front();
1554514f5e3Sopenharmony_ci            return task;
1564514f5e3Sopenharmony_ci        }
1574514f5e3Sopenharmony_ci        cv_.Wait(&mtx_);
1584514f5e3Sopenharmony_ci    }
1594514f5e3Sopenharmony_ci}
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_civoid DaemonThread::SetSharedMarkStatus(SharedMarkStatus markStatus)
1624514f5e3Sopenharmony_ci{
1634514f5e3Sopenharmony_ci    ASSERT(os::thread::GetCurrentThreadId() == GetThreadId());
1644514f5e3Sopenharmony_ci    markStatus_.store(markStatus, std::memory_order_release);
1654514f5e3Sopenharmony_ci    Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
1664514f5e3Sopenharmony_ci        ASSERT(!thread->IsInRunningState());
1674514f5e3Sopenharmony_ci        thread->SetSharedMarkStatus(markStatus);
1684514f5e3Sopenharmony_ci    });
1694514f5e3Sopenharmony_ci}
1704514f5e3Sopenharmony_ci
1714514f5e3Sopenharmony_ci#ifndef NDEBUG
1724514f5e3Sopenharmony_ciMutatorLock::MutatorLockState DaemonThread::GetMutatorLockState() const
1734514f5e3Sopenharmony_ci{
1744514f5e3Sopenharmony_ci    return mutatorLockState_;
1754514f5e3Sopenharmony_ci}
1764514f5e3Sopenharmony_ci
1774514f5e3Sopenharmony_civoid DaemonThread::SetMutatorLockState(MutatorLock::MutatorLockState newState)
1784514f5e3Sopenharmony_ci{
1794514f5e3Sopenharmony_ci    mutatorLockState_ = newState;
1804514f5e3Sopenharmony_ci}
1814514f5e3Sopenharmony_ci#endif
1824514f5e3Sopenharmony_ci}  // namespace panda::ecmascript