Fix CC collector thread flip and JNI critical section deadlocks.
There's a bug in the synchronization between the CC collector's thread
flip and JNI critical sections where it incorrectly attempts to make
the synchronization scheme to be writer (GC) preference to avoid
starvation of GC in the presence of frequent JNI critical section
enter/exit. This could cause a deadlock between them if a thread
enters a nested JNI critical section after a thread flip occurs. This
is reproduced in the added test.
The fix is to use a thread local disable counter in addition to the
global counter to detect a nested enter by the same thread and avoid
waiting if nested.
Bug: 19235243
Bug: 12687968
Change-Id: Idf7720a6906c9ea508219935af3727f76680d2d8
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c02e2d3..a181e23 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -1113,6 +1113,8 @@
// Used to synchronize between JNI critical calls and the thread flip of the CC collector.
Mutex* thread_flip_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::unique_ptr<ConditionVariable> thread_flip_cond_ GUARDED_BY(thread_flip_lock_);
+ // This counter keeps track of how many threads are currently in a JNI critical section. This is
+ // incremented once per thread even with nested enters.
size_t disable_thread_flip_count_ GUARDED_BY(thread_flip_lock_);
bool thread_flip_running_ GUARDED_BY(thread_flip_lock_);