Fix a deadlock between thread flip and suspend request.
See 31683379#9 for the deadlock scenario.
Make ModifySuspendCount(+1) retry if the thread flip function is set.
Bug: 31683379
Bug: 12687968
Test: test-art, N9 libartd boot, Ritz EAAC with CC.
Test: 129-GetThreadId with gcstress and CC.
Change-Id: Id5cdfcd90a08a2ff497f9f0e2842fa4c613549bc
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d0ea2d7..268699b 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -987,8 +987,10 @@
LOG(FATAL) << ss.str();
}
-bool Thread::ModifySuspendCount(Thread* self, int delta, AtomicInteger* suspend_barrier,
- bool for_debugger) {
+bool Thread::ModifySuspendCountInternal(Thread* self,
+ int delta,
+ AtomicInteger* suspend_barrier,
+ bool for_debugger) {
if (kIsDebugBuild) {
DCHECK(delta == -1 || delta == +1 || delta == -tls32_.debug_suspend_count)
<< delta << " " << tls32_.debug_suspend_count << " " << this;
@@ -1003,6 +1005,12 @@
return false;
}
+ if (kUseReadBarrier && delta > 0 && this != self && tlsPtr_.flip_function != nullptr) {
+ // Force retry of a suspend request if it's in the middle of a thread flip to avoid a
+ // deadlock. b/31683379.
+ return false;
+ }
+
uint16_t flags = kSuspendRequest;
if (delta > 0 && suspend_barrier != nullptr) {
uint32_t available_barrier = kMaxSuspendBarriers;