Add ScopedThreadSuspension
Fixes the TransitionFromRunnableToSuspended and
TransitionFromSuspendedToRunnable pattern that was prone to errors.
Change-Id: Ie6ae9c0357c83b4fc4899d05dfa0975553170267
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 95fcb67..fa58418 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -454,15 +454,13 @@
uintptr_t saved_dex_pc = locking_dex_pc_;
locking_dex_pc_ = 0;
- /*
- * Update thread state. If the GC wakes up, it'll ignore us, knowing
- * that we won't touch any references in this state, and we'll check
- * our suspend mode before we transition out.
- */
- self->TransitionFromRunnableToSuspended(why);
-
bool was_interrupted = false;
{
+ // Update thread state. If the GC wakes up, it'll ignore us, knowing
+ // that we won't touch any references in this state, and we'll check
+ // our suspend mode before we transition out.
+ ScopedThreadSuspension sts(self, why);
+
// Pseudo-atomically wait on self's wait_cond_ and release the monitor lock.
MutexLock mu(self, *self->GetWaitMutex());
@@ -494,9 +492,6 @@
}
}
- // Set self->status back to kRunnable, and self-suspend if needed.
- self->TransitionFromSuspendedToRunnable();
-
{
// We reset the thread's wait_monitor_ field after transitioning back to runnable so
// that a thread in a waiting/sleeping state has a non-null wait_monitor_ for debugging
@@ -667,9 +662,11 @@
// Suspend the owner, inflate. First change to blocked and give up mutator_lock_.
self->SetMonitorEnterObject(obj.Get());
bool timed_out;
- self->TransitionFromRunnableToSuspended(kBlocked);
- Thread* owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
- self->TransitionFromSuspendedToRunnable();
+ Thread* owner;
+ {
+ ScopedThreadSuspension sts(self, kBlocked);
+ owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
+ }
if (owner != nullptr) {
// We succeeded in suspending the thread, check the lock's status didn't change.
lock_word = obj->GetLockWord(true);