Fix race condition in TransitionCollector.
There was a minor race condition that could happen if multiple
threads called TransitionCollector at the same time. Starting out
in CMS:
Thread 1: TransitionCollector(SS).
Thread 2: TransitionCollector(CMS) sees that it is already CMS so
has copying_transition == false. But then thread 2 changes to SS.
Thread 1 resumes but incorrectly doesn't check the
disable_moving_gc_count_ possibly resulting in errors if
disable_moving_gc_count_ != 0 due to JNI since we are going from
SS -> CMS and are goign to move objects.
(cherry picked from commit de2233bbf64c7dde96513a729f6a97aebc2f0424)
Change-Id: I2fdda85f7cb7cbb0df3d1466a3c74853c5304c1b
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 42c7cca..4d1845b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -512,7 +512,7 @@
ScopedThreadStateChange tsc(self, kSuspended);
tl->SuspendAll();
// Something may have caused the transition to fail.
- if (!IsMovingGc(foreground_collector_type_) && non_moving_space_ != main_space_) {
+ if (!IsMovingGc(collector_type_) && non_moving_space_ != main_space_) {
CHECK(main_space_ != nullptr);
// The allocation stack may have non movable objects in it. We need to flush it since the GC
// can't only handle marking allocation stack objects of one non moving space and one main
@@ -1597,9 +1597,6 @@
Thread* const self = Thread::Current();
ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
Locks::mutator_lock_->AssertNotHeld(self);
- // Currently we only need a heap transition if we switch from a moving collector to a non moving
- // one, or visa versa.
- const bool copying_transition = IsMovingGc(collector_type_) != IsMovingGc(collector_type);
// Busy wait until we can GC (StartGC can fail if we have a non-zero
// compacting_gc_disable_count_, this should rarely occurs).
for (;;) {
@@ -1608,6 +1605,9 @@
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
WaitForGcToCompleteLocked(kGcCauseCollectorTransition, self);
+ // Currently we only need a heap transition if we switch from a moving collector to a
+ // non-moving one, or visa versa.
+ const bool copying_transition = IsMovingGc(collector_type_) != IsMovingGc(collector_type);
// If someone else beat us to it and changed the collector before we could, exit.
// This is safe to do before the suspend all since we set the collector_type_running_ before
// we exit the loop. If another thread attempts to do the heap transition before we exit,