| /* |
| * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license |
| * that can be found in the LICENSE file. |
| */ |
| |
| #ifndef RUNTIME_MM_THREAD_SUSPENSION_H |
| #define RUNTIME_MM_THREAD_SUSPENSION_H |
| |
| #include <atomic> |
| |
| #include "Memory.h" |
| #include "Utils.hpp" |
| |
| namespace kotlin { |
| namespace mm { |
| |
| class ThreadData; |
| |
| namespace internal { |
| |
| using SuspensionReason = const char*; |
| extern std::atomic<SuspensionReason> gSuspensionRequestReason; |
| |
| } // namespace internal |
| |
| inline bool IsThreadSuspensionRequested() noexcept { |
| // Must use seq_cst ordering for synchronization with GC |
| // in native->runnable transition. |
| return internal::gSuspensionRequestReason.load(); |
| } |
| |
| class ThreadSuspensionData : private Pinned { |
| private: |
| class MutatorPauseHandle : private Pinned { |
| public: |
| explicit MutatorPauseHandle(const char* reason, ThreadData& threadData) noexcept; |
| ~MutatorPauseHandle() noexcept; |
| void resume() noexcept; |
| private: |
| const char* reason_; |
| ThreadData& threadData_; |
| uint64_t pauseStartTimeMicros_; |
| bool resumed = false; |
| }; |
| |
| public: |
| explicit ThreadSuspensionData(ThreadState initialState, mm::ThreadData& threadData) noexcept : state_(initialState), threadData_(threadData) {} |
| |
| ~ThreadSuspensionData() = default; |
| |
| ThreadState state() noexcept { return state_; } |
| |
| ThreadState setState(ThreadState newState) noexcept; |
| ThreadState setStateNoSafePoint(ThreadState newState) noexcept { return state_.exchange(newState, std::memory_order_acq_rel); } |
| |
| bool suspendedOrNative() noexcept { return state() == kotlin::ThreadState::kNative; } |
| |
| void suspendIfRequested() noexcept; |
| |
| void requestThreadsSuspension(const char* reason) noexcept; |
| |
| /** |
| * Signals that the thread would not mutate a heap during a relatively long time. |
| * For example while waiting for or participating in the GC. |
| * Effectively sets the thread's state to `kNative`. |
| * |
| * The pause is considered completed upon destruction of a returned pause-handle object. |
| * |
| * NOTE: the safe point actions will NOT be automatically executed after the pause. |
| */ |
| [[nodiscard]] MutatorPauseHandle pauseMutationInScope(const char* reason) noexcept; |
| |
| private: |
| std::atomic<ThreadState> state_; |
| mm::ThreadData& threadData_; |
| }; |
| |
| /** |
| * Sends a request to suspend all threads registered in ThreadRegistry except threads that are in the Native state. |
| * Blocks until all such threads are suspended. Threads that are in the Native state on the moment |
| * of this call will be suspended on exit from the Native state. |
| * |
| * Returns false if some other thread tries to suspended the threads at the moment. |
| */ |
| bool TryRequestThreadsSuspension(const char* reason) noexcept; |
| void RequestThreadsSuspension(const char* reason) noexcept; |
| |
| void WaitForThreadsSuspension() noexcept; |
| |
| /** |
| * Resumes all threads registered in ThreadRegistry that were suspended by the SuspendThreads call. |
| * Does not wait until all such threads are actually resumed. |
| */ |
| void ResumeThreads() noexcept; |
| |
| } // namespace mm |
| } // namespace kotlin |
| |
| #endif // RUNTIME_MM_THREAD_SUSPENSION_H |