Add a way to SuspendAll for a long duration
Hprof uses this mode to not cause thread suspend timeouts if GC tries
while the hprof dump is running.
(cherry picked from commit 77be6635f9b07a8a794924c5fb9b071949776a6d)
Bug: 21063989
Change-Id: Ic6304620afd1489719a7e0e4299f829c90fe27cc
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 7719bb8..af9ba68 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -52,7 +52,7 @@
ThreadList::ThreadList()
: suspend_all_count_(0), debug_suspend_all_count_(0), unregistering_count_(0),
- suspend_all_historam_("suspend all histogram", 16, 64) {
+ suspend_all_historam_("suspend all histogram", 16, 64), long_suspend_(false) {
CHECK(Monitor::IsValidLockWord(LockWord::FromThinLockId(kMaxThreadId, 1, 0U)));
}
@@ -448,7 +448,7 @@
return runnable_threads.size() + other_threads.size() + 1; // +1 for self.
}
-void ThreadList::SuspendAll(const char* cause) {
+void ThreadList::SuspendAll(const char* cause, bool long_suspend) {
Thread* self = Thread::Current();
if (self != nullptr) {
@@ -482,14 +482,22 @@
// Block on the mutator lock until all Runnable threads release their share of access.
#if HAVE_TIMED_RWLOCK
- // Timeout if we wait more than 30 seconds.
- if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, kThreadSuspendTimeoutMs, 0)) {
- UnsafeLogFatalForThreadSuspendAllTimeout();
+ while (true) {
+ if (Locks::mutator_lock_->ExclusiveLockWithTimeout(self, kThreadSuspendTimeoutMs, 0)) {
+ break;
+ } else if (!long_suspend_) {
+ // Reading long_suspend without the mutator lock is slightly racy, in some rare cases, this
+ // could result in a thread suspend timeout.
+ // Timeout if we wait more than kThreadSuspendTimeoutMs seconds.
+ UnsafeLogFatalForThreadSuspendAllTimeout();
+ }
}
#else
Locks::mutator_lock_->ExclusiveLock(self);
#endif
+ long_suspend_ = long_suspend;
+
const uint64_t end_time = NanoTime();
const uint64_t suspend_time = end_time - start_time;
suspend_all_historam_.AdjustAndAddValue(suspend_time);
@@ -529,6 +537,8 @@
AssertThreadsAreSuspended(self, self);
}
+ long_suspend_ = false;
+
Locks::mutator_lock_->ExclusiveUnlock(self);
{
MutexLock mu(self, *Locks::thread_list_lock_);
@@ -599,8 +609,8 @@
jobject peer) {
JNIEnvExt* env = self->GetJniEnv();
ScopedLocalRef<jstring>
- scoped_name_string(env, (jstring)env->GetObjectField(peer,
- WellKnownClasses::java_lang_Thread_name));
+ scoped_name_string(env, (jstring)env->GetObjectField(
+ peer, WellKnownClasses::java_lang_Thread_name));
ScopedUtfChars scoped_name_chars(env, scoped_name_string.get());
if (scoped_name_chars.c_str() == nullptr) {
LOG(severity) << message << ": " << peer;