summaryrefslogtreecommitdiff
path: root/runtime/thread-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/thread-inl.h')
-rw-r--r--runtime/thread-inl.h121
1 files changed, 32 insertions, 89 deletions
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 5d45c599fe..4110ed2851 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -27,6 +27,7 @@
#include "jni/jni_env_ext.h"
#include "managed_stack-inl.h"
#include "obj_ptr.h"
+#include "suspend_reason.h"
#include "thread-current-inl.h"
#include "thread_pool.h"
@@ -221,7 +222,7 @@ inline void Thread::TransitionToSuspendedAndRunCheckpoints(ThreadState new_state
}
}
-inline void Thread::CheckActiveSuspendBarriers() {
+inline void Thread::PassActiveSuspendBarriers() {
while (true) {
StateAndFlags state_and_flags = GetStateAndFlags(std::memory_order_relaxed);
if (LIKELY(!state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest) &&
@@ -229,7 +230,7 @@ inline void Thread::CheckActiveSuspendBarriers() {
!state_and_flags.IsFlagSet(ThreadFlag::kActiveSuspendBarrier))) {
break;
} else if (state_and_flags.IsFlagSet(ThreadFlag::kActiveSuspendBarrier)) {
- PassActiveSuspendBarriers();
+ PassActiveSuspendBarriers(this);
} else {
// Impossible
LOG(FATAL) << "Fatal, thread transitioned into suspended without running the checkpoint";
@@ -237,19 +238,6 @@ inline void Thread::CheckActiveSuspendBarriers() {
}
}
-inline void Thread::AddSuspend1Barrier(WrappedSuspend1Barrier* suspend1_barrier) {
- suspend1_barrier->next_ = tlsPtr_.active_suspend1_barriers;
- tlsPtr_.active_suspend1_barriers = suspend1_barrier;
-}
-
-inline void Thread::RemoveFirstSuspend1Barrier() {
- tlsPtr_.active_suspend1_barriers = tlsPtr_.active_suspend1_barriers->next_;
-}
-
-inline bool Thread::HasActiveSuspendBarrier() {
- return tlsPtr_.active_suspend1_barriers != nullptr || tlsPtr_.active_suspendall_barrier != nullptr;
-}
-
inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
// Note: JNI stubs inline a fast path of this method that transitions to suspended if
// there are no flags set and then clears the `held_mutexes[kMutatorLock]` (this comes
@@ -265,7 +253,7 @@ inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
// Mark the release of the share of the mutator lock.
GetMutatorLock()->TransitionFromRunnableToSuspended(this);
// Once suspended - check the active suspend barrier flag
- CheckActiveSuspendBarriers();
+ PassActiveSuspendBarriers();
}
inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
@@ -296,7 +284,7 @@ inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
break;
}
} else if (old_state_and_flags.IsFlagSet(ThreadFlag::kActiveSuspendBarrier)) {
- PassActiveSuspendBarriers();
+ PassActiveSuspendBarriers(this);
} else if (UNLIKELY(old_state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest) ||
old_state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest))) {
// Checkpoint flags should not be set while in suspended state.
@@ -436,80 +424,35 @@ inline void Thread::PoisonObjectPointersIfDebug() {
}
}
-inline void Thread::IncrementSuspendCount(Thread* self,
- AtomicInteger* suspendall_barrier,
- WrappedSuspend1Barrier* suspend1_barrier,
- SuspendReason reason) {
- if (kIsDebugBuild) {
- Locks::thread_suspend_count_lock_->AssertHeld(self);
- if (this != self && !IsSuspended()) {
- Locks::thread_list_lock_->AssertHeld(self);
- }
- }
- if (UNLIKELY(reason == SuspendReason::kForUserCode)) {
- Locks::user_code_suspension_lock_->AssertHeld(self);
- }
-
- // Avoid deadlocks during a thread flip. b/31683379. This condition is not necessary for
- // RunCheckpoint, but it does not use a suspend barrier.
- DCHECK(!gUseReadBarrier
- || this == self
- || (suspendall_barrier == nullptr && suspend1_barrier == nullptr)
- || GetFlipFunction() == nullptr);
-
- uint32_t flags = enum_cast<uint32_t>(ThreadFlag::kSuspendRequest);
- if (suspendall_barrier != nullptr) {
- DCHECK(suspend1_barrier == nullptr);
- DCHECK(tlsPtr_.active_suspendall_barrier == nullptr);
- tlsPtr_.active_suspendall_barrier = suspendall_barrier;
- flags |= enum_cast<uint32_t>(ThreadFlag::kActiveSuspendBarrier);
- } else if (suspend1_barrier != nullptr) {
- AddSuspend1Barrier(suspend1_barrier);
- flags |= enum_cast<uint32_t>(ThreadFlag::kActiveSuspendBarrier);
- }
-
- ++tls32_.suspend_count;
- if (reason == SuspendReason::kForUserCode) {
- ++tls32_.user_code_suspend_count;
- }
-
- // Two bits might be set simultaneously.
- tls32_.state_and_flags.fetch_or(flags, std::memory_order_seq_cst);
- TriggerSuspend();
-}
-
-inline void Thread::DecrementSuspendCount(Thread* self, SuspendReason reason) {
- if (kIsDebugBuild) {
- Locks::thread_suspend_count_lock_->AssertHeld(self);
- if (this != self && !IsSuspended()) {
- Locks::thread_list_lock_->AssertHeld(self);
- }
- }
- if (UNLIKELY(tls32_.suspend_count <= 0)) {
- UnsafeLogFatalForSuspendCount(self, this);
- UNREACHABLE();
- }
- if (UNLIKELY(reason == SuspendReason::kForUserCode)) {
- Locks::user_code_suspension_lock_->AssertHeld(self);
- if (UNLIKELY(tls32_.user_code_suspend_count <= 0)) {
- LOG(ERROR) << "user_code_suspend_count incorrect";
- UnsafeLogFatalForSuspendCount(self, this);
- UNREACHABLE();
+inline bool Thread::ModifySuspendCount(Thread* self,
+ int delta,
+ AtomicInteger* suspend_barrier,
+ SuspendReason reason) {
+ if (delta > 0 && ((gUseReadBarrier && this != self) || suspend_barrier != nullptr)) {
+ // When delta > 0 (requesting a suspend), ModifySuspendCountInternal() may fail either if
+ // active_suspend_barriers is full or we are in the middle of a thread flip. Retry in a loop.
+ while (true) {
+ if (LIKELY(ModifySuspendCountInternal(self, delta, suspend_barrier, reason))) {
+ return true;
+ } else {
+ // Failure means the list of active_suspend_barriers is full or we are in the middle of a
+ // thread flip, we should release the thread_suspend_count_lock_ (to avoid deadlock) and
+ // wait till the target thread has executed or Thread::PassActiveSuspendBarriers() or the
+ // flip function. Note that we could not simply wait for the thread to change to a suspended
+ // state, because it might need to run checkpoint function before the state change or
+ // resumes from the resume_cond_, which also needs thread_suspend_count_lock_.
+ //
+ // The list of active_suspend_barriers is very unlikely to be full since more than
+ // kMaxSuspendBarriers threads need to execute SuspendAllInternal() simultaneously, and
+ // target thread stays in kRunnable in the mean time.
+ Locks::thread_suspend_count_lock_->ExclusiveUnlock(self);
+ NanoSleep(100000);
+ Locks::thread_suspend_count_lock_->ExclusiveLock(self);
+ }
}
+ } else {
+ return ModifySuspendCountInternal(self, delta, suspend_barrier, reason);
}
-
- --tls32_.suspend_count;
- if (reason == SuspendReason::kForUserCode) {
- --tls32_.user_code_suspend_count;
- }
-
- if (tls32_.suspend_count == 0) {
- AtomicClearFlag(ThreadFlag::kSuspendRequest);
- }
-}
-
-inline void Thread::IncrementSuspendCount(Thread* self) {
- IncrementSuspendCount(self, nullptr, nullptr, SuspendReason::kInternal);
}
inline ShadowFrame* Thread::PushShadowFrame(ShadowFrame* new_top_frame) {