blob: fe2c8af93d051fd2880a5601be1b71864daf047e [file]
/*
* 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"
namespace kotlin {
namespace mm {
class ThreadData;
namespace internal {
extern std::atomic<bool> gSuspensionRequested;
} // namespace internal
inline bool IsThreadSuspensionRequested() noexcept {
// TODO: Consider using a more relaxed memory order.
return internal::gSuspensionRequested.load();
}
class ThreadSuspensionData : private Pinned {
public:
explicit ThreadSuspensionData(ThreadState initialState, mm::ThreadData& threadData) noexcept : state_(initialState), threadData_(threadData), suspended_(false) {}
~ThreadSuspensionData() = default;
ThreadState state() noexcept { return state_; }
ThreadState setState(ThreadState newState) noexcept {
ThreadState oldState = state_.exchange(newState);
if (oldState == ThreadState::kNative && newState == ThreadState::kRunnable) {
suspendIfRequested();
}
return oldState;
}
bool suspended() noexcept { return suspended_; }
NO_EXTERNAL_CALLS_CHECK void suspendIfRequested() noexcept {
if (IsThreadSuspensionRequested()) {
suspendIfRequestedSlowPath();
}
}
private:
friend void SuspendIfRequestedSlowPath() noexcept;
std::atomic<ThreadState> state_;
mm::ThreadData& threadData_;
std::atomic<bool> suspended_;
void suspendIfRequestedSlowPath() noexcept;
};
bool RequestThreadsSuspension() noexcept;
void WaitForThreadsSuspension() noexcept;
void SuspendIfRequestedSlowPath() noexcept;
void SuspendIfRequested() noexcept;
/**
* Suspends 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 has suspended the threads.
*/
inline bool SuspendThreads() noexcept {
if (!RequestThreadsSuspension()) {
return false;
}
WaitForThreadsSuspension();
return true;
}
/**
* 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