Add ScopedThreadSuspension

Fixes the TransitionFromRunnableToSuspended and
TransitionFromSuspendedToRunnable pattern that was prone to errors.

Change-Id: Ie6ae9c0357c83b4fc4899d05dfa0975553170267
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 961b80f..9292c7a 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -887,13 +887,14 @@
     // easily broken. Visit objects while GC isn't running by using
     // IncrementDisableMovingGC() and threads are suspended.
     IncrementDisableMovingGC(self);
-    self->TransitionFromRunnableToSuspended(kWaitingForVisitObjects);
-    ThreadList* tl = Runtime::Current()->GetThreadList();
-    tl->SuspendAll(__FUNCTION__);
-    VisitObjectsInternalRegionSpace(callback, arg);
-    VisitObjectsInternal(callback, arg);
-    tl->ResumeAll();
-    self->TransitionFromSuspendedToRunnable();
+    {
+      ScopedThreadSuspension sts(self, kWaitingForVisitObjects);
+      ThreadList* tl = Runtime::Current()->GetThreadList();
+      tl->SuspendAll(__FUNCTION__);
+      VisitObjectsInternalRegionSpace(callback, arg);
+      VisitObjectsInternal(callback, arg);
+      tl->ResumeAll();
+    }
     DecrementDisableMovingGC(self);
   } else {
     // GCs can move objects, so don't allow this.
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index e1c5b64..77f606d 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -298,18 +298,16 @@
   }
 }
 
-void DlMallocSpace::LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) {
-  UNUSED(failed_alloc_bytes);
-  Thread* self = Thread::Current();
+void DlMallocSpace::LogFragmentationAllocFailure(std::ostream& os,
+                                                 size_t failed_alloc_bytes ATTRIBUTE_UNUSED) {
+  Thread* const self = Thread::Current();
   size_t max_contiguous_allocation = 0;
   // To allow the Walk/InspectAll() to exclusively-lock the mutator
   // lock, temporarily release the shared access to the mutator
   // lock here by transitioning to the suspended state.
   Locks::mutator_lock_->AssertSharedHeld(self);
-  self->TransitionFromRunnableToSuspended(kSuspended);
+  ScopedThreadSuspension sts(self, kSuspended);
   Walk(MSpaceChunkCallback, &max_contiguous_allocation);
-  self->TransitionFromSuspendedToRunnable();
-  Locks::mutator_lock_->AssertSharedHeld(self);
   os << "; failed due to fragmentation (largest possible contiguous allocation "
      <<  max_contiguous_allocation << " bytes)";
 }
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index 1a193c3..d8072ea 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -331,10 +331,8 @@
     // The mutators are not suspended yet and we have a shared access
     // to the mutator lock. Temporarily release the shared access by
     // transitioning to the suspend state, and suspend the mutators.
-    self->TransitionFromRunnableToSuspended(kSuspended);
+    ScopedThreadSuspension sts(self, kSuspended);
     InspectAllRosAllocWithSuspendAll(callback, arg, do_null_callback_at_end);
-    self->TransitionFromSuspendedToRunnable();
-    Locks::mutator_lock_->AssertSharedHeld(self);
   } else {
     // The mutators are not suspended yet. Suspend the mutators.
     InspectAllRosAllocWithSuspendAll(callback, arg, do_null_callback_at_end);