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 #ifndef ECMASCRIPT_DAEMON_THREAD_H
17 #define ECMASCRIPT_DAEMON_THREAD_H
18 
19 #include <atomic>
20 #include <deque>
21 #include <thread>
22 
23 #include "ecmascript/daemon/daemon_task.h"
24 #include "ecmascript/js_thread.h"
25 #include "ecmascript/mutator_lock.h"
26 #include "ecmascript/platform/mutex.h"
27 
28 namespace panda::ecmascript {
29 
30 static constexpr uint32_t DAEMON_THREAD_INDEX = 0;
31 
32 class DaemonThread : public JSThread {
33 public:
34     static void CreateNewInstance();
35     static DaemonThread *GetInstance();
36     static void DestroyInstance();
37 
38     using ThreadId = uint32_t;
39 
40     void StartRunning();
41 
42     bool IsRunning() const;
43 
44     void MarkTerminate();       // In daemon thread
45 
46     // Wait daemon thread finished, and then call TaskPool.Destroy
47     void WaitFinished();
48 
49     bool CheckAndPostTask(DaemonTask task);
50 
51     /**
52      * Called in daemon thread, and manually call this in DaemonTask at the appropriate time,
53      * e.g. for GC task, call this before ResumeAll instead of the task complete ended, to prevent in some
54      * time sequence, all js_thread is resumed and one of these post another GC task, but the PostedGroup
55      * have not been cleaned, leading the task lost.
56     */
57     void FinishRunningTask();
58 
GetSharedMarkStatus() const59     SharedMarkStatus GetSharedMarkStatus() const
60     {
61         return markStatus_.load(std::memory_order_acquire);
62     }
63 
64     void SetSharedMarkStatus(SharedMarkStatus markStatus);
65 
IsReadyToConcurrentMark() const66     bool IsReadyToConcurrentMark() const
67     {
68         return GetSharedMarkStatus() == SharedMarkStatus::READY_TO_CONCURRENT_MARK;
69     }
70 
IsConcurrentMarkingOrFinished() const71     bool IsConcurrentMarkingOrFinished() const
72     {
73         return GetSharedMarkStatus() == SharedMarkStatus::CONCURRENT_MARKING_OR_FINISHED;
74     }
75 
76 #ifndef NDEBUG
77     MutatorLock::MutatorLockState GetMutatorLockState() const;
78     void SetMutatorLockState(MutatorLock::MutatorLockState newState);
79 #endif
80 
81 private:
DaemonThread()82     DaemonThread() : JSThread(ThreadType::DAEMON_THREAD) {}
83     ~DaemonThread() = default;
84 
85     void Run();
86 
87     bool AddTaskGroup(DaemonTaskGroup taskGroup);
88 
89     DaemonTask PopTask();
90 
91     static DaemonThread *instance_;
92 
93     // In js thread, load the running need atomic, but in daemon do not need, since only daemon thread
94     // will set running_ to false
95     std::atomic<bool> running_ {false};
96 
97     std::atomic<SharedMarkStatus> markStatus_ {SharedMarkStatus::READY_TO_CONCURRENT_MARK};
98 
99     std::unique_ptr<std::thread> thread_;
100 
101     std::deque<DaemonTask> tasks_;
102     DaemonTaskGroup runningGroup_ {DaemonTaskGroup::NONE};
103     uint32_t postedGroups_ {0};
104     Mutex mtx_;
105     ConditionVariable cv_;
106 #ifndef NDEBUG
107     MutatorLock::MutatorLockState mutatorLockState_ = MutatorLock::MutatorLockState::UNLOCKED;
108 #endif
109 };
110 }  // namespace panda::ecmascript
111 #endif  // ECMASCRIPT_DAEMON_THREAD_H