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#ifndef ECMASCRIPT_DAEMON_THREAD_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_DAEMON_THREAD_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <atomic>
204514f5e3Sopenharmony_ci#include <deque>
214514f5e3Sopenharmony_ci#include <thread>
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_ci#include "ecmascript/daemon/daemon_task.h"
244514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h"
254514f5e3Sopenharmony_ci#include "ecmascript/mutator_lock.h"
264514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h"
274514f5e3Sopenharmony_ci
284514f5e3Sopenharmony_cinamespace panda::ecmascript {
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_cistatic constexpr uint32_t DAEMON_THREAD_INDEX = 0;
314514f5e3Sopenharmony_ci
324514f5e3Sopenharmony_ciclass DaemonThread : public JSThread {
334514f5e3Sopenharmony_cipublic:
344514f5e3Sopenharmony_ci    static void CreateNewInstance();
354514f5e3Sopenharmony_ci    static DaemonThread *GetInstance();
364514f5e3Sopenharmony_ci    static void DestroyInstance();
374514f5e3Sopenharmony_ci
384514f5e3Sopenharmony_ci    using ThreadId = uint32_t;
394514f5e3Sopenharmony_ci
404514f5e3Sopenharmony_ci    void StartRunning();
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ci    bool IsRunning() const;
434514f5e3Sopenharmony_ci
444514f5e3Sopenharmony_ci    void MarkTerminate();       // In daemon thread
454514f5e3Sopenharmony_ci
464514f5e3Sopenharmony_ci    // Wait daemon thread finished, and then call TaskPool.Destroy
474514f5e3Sopenharmony_ci    void WaitFinished();
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_ci    bool CheckAndPostTask(DaemonTask task);
504514f5e3Sopenharmony_ci
514514f5e3Sopenharmony_ci    /**
524514f5e3Sopenharmony_ci     * Called in daemon thread, and manually call this in DaemonTask at the appropriate time,
534514f5e3Sopenharmony_ci     * e.g. for GC task, call this before ResumeAll instead of the task complete ended, to prevent in some
544514f5e3Sopenharmony_ci     * time sequence, all js_thread is resumed and one of these post another GC task, but the PostedGroup
554514f5e3Sopenharmony_ci     * have not been cleaned, leading the task lost.
564514f5e3Sopenharmony_ci    */
574514f5e3Sopenharmony_ci    void FinishRunningTask();
584514f5e3Sopenharmony_ci
594514f5e3Sopenharmony_ci    SharedMarkStatus GetSharedMarkStatus() const
604514f5e3Sopenharmony_ci    {
614514f5e3Sopenharmony_ci        return markStatus_.load(std::memory_order_acquire);
624514f5e3Sopenharmony_ci    }
634514f5e3Sopenharmony_ci
644514f5e3Sopenharmony_ci    void SetSharedMarkStatus(SharedMarkStatus markStatus);
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_ci    bool IsReadyToConcurrentMark() const
674514f5e3Sopenharmony_ci    {
684514f5e3Sopenharmony_ci        return GetSharedMarkStatus() == SharedMarkStatus::READY_TO_CONCURRENT_MARK;
694514f5e3Sopenharmony_ci    }
704514f5e3Sopenharmony_ci
714514f5e3Sopenharmony_ci    bool IsConcurrentMarkingOrFinished() const
724514f5e3Sopenharmony_ci    {
734514f5e3Sopenharmony_ci        return GetSharedMarkStatus() == SharedMarkStatus::CONCURRENT_MARKING_OR_FINISHED;
744514f5e3Sopenharmony_ci    }
754514f5e3Sopenharmony_ci
764514f5e3Sopenharmony_ci#ifndef NDEBUG
774514f5e3Sopenharmony_ci    MutatorLock::MutatorLockState GetMutatorLockState() const;
784514f5e3Sopenharmony_ci    void SetMutatorLockState(MutatorLock::MutatorLockState newState);
794514f5e3Sopenharmony_ci#endif
804514f5e3Sopenharmony_ci
814514f5e3Sopenharmony_ciprivate:
824514f5e3Sopenharmony_ci    DaemonThread() : JSThread(ThreadType::DAEMON_THREAD) {}
834514f5e3Sopenharmony_ci    ~DaemonThread() = default;
844514f5e3Sopenharmony_ci
854514f5e3Sopenharmony_ci    void Run();
864514f5e3Sopenharmony_ci
874514f5e3Sopenharmony_ci    bool AddTaskGroup(DaemonTaskGroup taskGroup);
884514f5e3Sopenharmony_ci
894514f5e3Sopenharmony_ci    DaemonTask PopTask();
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_ci    static DaemonThread *instance_;
924514f5e3Sopenharmony_ci
934514f5e3Sopenharmony_ci    // In js thread, load the running need atomic, but in daemon do not need, since only daemon thread
944514f5e3Sopenharmony_ci    // will set running_ to false
954514f5e3Sopenharmony_ci    std::atomic<bool> running_ {false};
964514f5e3Sopenharmony_ci
974514f5e3Sopenharmony_ci    std::atomic<SharedMarkStatus> markStatus_ {SharedMarkStatus::READY_TO_CONCURRENT_MARK};
984514f5e3Sopenharmony_ci
994514f5e3Sopenharmony_ci    std::unique_ptr<std::thread> thread_;
1004514f5e3Sopenharmony_ci
1014514f5e3Sopenharmony_ci    std::deque<DaemonTask> tasks_;
1024514f5e3Sopenharmony_ci    DaemonTaskGroup runningGroup_ {DaemonTaskGroup::NONE};
1034514f5e3Sopenharmony_ci    uint32_t postedGroups_ {0};
1044514f5e3Sopenharmony_ci    Mutex mtx_;
1054514f5e3Sopenharmony_ci    ConditionVariable cv_;
1064514f5e3Sopenharmony_ci#ifndef NDEBUG
1074514f5e3Sopenharmony_ci    MutatorLock::MutatorLockState mutatorLockState_ = MutatorLock::MutatorLockState::UNLOCKED;
1084514f5e3Sopenharmony_ci#endif
1094514f5e3Sopenharmony_ci};
1104514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
1114514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_DAEMON_THREAD_H