diff options
author | 2019-03-05 12:22:57 +0900 | |
---|---|---|
committer | 2019-03-18 17:19:04 +0000 | |
commit | 97b964960123d5f215a1cebbce548c8a5322c307 (patch) | |
tree | 04239f8bc25ce6f22bda774bbae37755ed8acb27 | |
parent | 26a5dd6fd1d65de29ba85e4bb61d9267dd428238 (diff) |
Change state to waiting during aborting the VM
Symptom:
Process freeze when multiple runtime error happen on runnable threads.
Root cause:
When multiple runtime error happen, only one thread locks abort_lock_
and other threads are blocked even if they are runnable state.
If an other thread tries to suspend blocked threads at the same time,
blocked threads can't be suspended until abort_lock_ is unlocked from
owner thread. But owner thread can be suspended even if it locks
abort_lock_. Thus, these threads causes dead lock.
Solution:
Change state to waiting when locking abort_lock_.
Bug: 127875380
Change-Id: I7e914924690bb30d6d0490cf5f8afdb1c3cd4e4a
-rw-r--r-- | openjdkjvmti/ti_monitor.cc | 1 | ||||
-rw-r--r-- | openjdkjvmti/ti_thread.cc | 2 | ||||
-rw-r--r-- | runtime/debugger.cc | 1 | ||||
-rw-r--r-- | runtime/native/java_lang_Thread.cc | 1 | ||||
-rw-r--r-- | runtime/runtime.cc | 9 | ||||
-rw-r--r-- | runtime/thread_state.h | 1 |
6 files changed, 12 insertions, 3 deletions
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc index aac7233303..2ca5057f85 100644 --- a/openjdkjvmti/ti_monitor.cc +++ b/openjdkjvmti/ti_monitor.cc @@ -403,6 +403,7 @@ jvmtiError MonitorUtil::GetCurrentContendedMonitor(jvmtiEnv* env ATTRIBUTE_UNUSE case art::kWaitingForGetObjectsAllocated: case art::kWaitingWeakGcRootRead: case art::kWaitingForGcThreadFlip: + case art::kNativeForAbort: case art::kStarting: case art::kNative: case art::kSuspended: { diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc index c6798bb1c9..01cc8c7699 100644 --- a/openjdkjvmti/ti_thread.cc +++ b/openjdkjvmti/ti_thread.cc @@ -453,6 +453,7 @@ static jint GetJvmtiThreadStateFromInternal(const InternalThreadState& state) { case art::ThreadState::kWaitingForVisitObjects: case art::ThreadState::kWaitingForGetObjectsAllocated: case art::ThreadState::kWaitingForGcThreadFlip: + case art::ThreadState::kNativeForAbort: // All of these are causing the thread to wait for an indeterminate amount of time but isn't // caused by sleep, park, or object#wait. jvmti_state |= (JVMTI_THREAD_STATE_WAITING | @@ -508,6 +509,7 @@ static jint GetJavaStateFromInternal(const InternalThreadState& state) { case art::ThreadState::kWaitingForMethodTracingStart: case art::ThreadState::kWaitingForVisitObjects: case art::ThreadState::kWaitingForGcThreadFlip: + case art::ThreadState::kNativeForAbort: return JVMTI_JAVA_LANG_THREAD_STATE_WAITING; } LOG(FATAL) << "Unreachable"; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 663af814cd..d3a3eeae49 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -2261,6 +2261,7 @@ JDWP::JdwpThreadStatus Dbg::ToJdwpThreadStatus(ThreadState state) { case kWaitingPerformingGc: case kWaitingWeakGcRootRead: case kWaitingForGcThreadFlip: + case kNativeForAbort: case kWaiting: return JDWP::TS_WAIT; // Don't add a 'default' here so the compiler can spot incompatible enum changes. diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc index 67ad0a47b8..37b3fe642e 100644 --- a/runtime/native/java_lang_Thread.cc +++ b/runtime/native/java_lang_Thread.cc @@ -104,6 +104,7 @@ static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean ha case kWaitingForVisitObjects: return kJavaWaiting; case kWaitingWeakGcRootRead: return kJavaRunnable; case kWaitingForGcThreadFlip: return kJavaWaiting; + case kNativeForAbort: return kJavaWaiting; case kSuspended: return kJavaRunnable; // Don't add a 'default' here so the compiler can spot incompatible enum changes. } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index d698d4817b..4565939965 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -584,9 +584,12 @@ void Runtime::Abort(const char* msg) { #endif } - // Ensure that we don't have multiple threads trying to abort at once, - // which would result in significantly worse diagnostics. - MutexLock mu(Thread::Current(), *Locks::abort_lock_); + { + // Ensure that we don't have multiple threads trying to abort at once, + // which would result in significantly worse diagnostics. + ScopedThreadStateChange tsc(Thread::Current(), kNativeForAbort); + Locks::abort_lock_->ExclusiveLock(Thread::Current()); + } // Get any pending output out of the way. fflush(nullptr); diff --git a/runtime/thread_state.h b/runtime/thread_state.h index e57a040cb1..c8f382693e 100644 --- a/runtime/thread_state.h +++ b/runtime/thread_state.h @@ -47,6 +47,7 @@ enum ThreadState { kWaitingForGetObjectsAllocated, // WAITING TS_WAIT waiting for getting the number of allocated objects kWaitingWeakGcRootRead, // WAITING TS_WAIT waiting on the GC to read a weak root kWaitingForGcThreadFlip, // WAITING TS_WAIT waiting on the GC thread flip (CC collector) to finish + kNativeForAbort, // WAITING TS_WAIT checking other threads are not run on abort. kStarting, // NEW TS_WAIT native thread started, not yet ready to run managed code kNative, // RUNNABLE TS_RUNNING running in a JNI native method kSuspended, // RUNNABLE TS_RUNNING suspended by GC or debugger |