diff options
author | Mathieu Chartier <mathieuc@google.com> | 2015-06-02 11:42:18 -0700 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2015-06-02 11:42:18 -0700 |
commit | 77be6635f9b07a8a794924c5fb9b071949776a6d (patch) | |
tree | a15297dc180b530a6885774311f756aef00f66d8 | |
parent | 2791d5e66f6c802147e2f9275b94b5ca995c396f (diff) | |
download | art-77be6635f9b07a8a794924c5fb9b071949776a6d.zip art-77be6635f9b07a8a794924c5fb9b071949776a6d.tar.gz art-77be6635f9b07a8a794924c5fb9b071949776a6d.tar.bz2 |
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.
Bug: 21063989
Change-Id: Ic6304620afd1489719a7e0e4299f829c90fe27cc
-rw-r--r-- | runtime/hprof/hprof.cc | 2 | ||||
-rw-r--r-- | runtime/thread_list.cc | 24 | ||||
-rw-r--r-- | runtime/thread_list.h | 7 |
3 files changed, 24 insertions, 9 deletions
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 88a72ec..917fe43 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -1214,7 +1214,7 @@ void DumpHeap(const char* filename, int fd, bool direct_to_ddms) { // comment in Heap::VisitObjects(). heap->IncrementDisableMovingGC(self); } - Runtime::Current()->GetThreadList()->SuspendAll(__FUNCTION__); + Runtime::Current()->GetThreadList()->SuspendAll(__FUNCTION__, true /* long suspend */); Hprof hprof(filename, fd, direct_to_ddms); hprof.Dump(); Runtime::Current()->GetThreadList()->ResumeAll(); 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 @@ static constexpr useconds_t kThreadSuspendMaxSleepUs = 5000; 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 @@ size_t ThreadList::FlipThreadRoots(Closure* thread_flip_visitor, Closure* flip_c 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 @@ void ThreadList::SuspendAll(const char* cause) { // 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 @@ void ThreadList::ResumeAll() { AssertThreadsAreSuspended(self, self); } + long_suspend_ = false; + Locks::mutator_lock_->ExclusiveUnlock(self); { MutexLock mu(self, *Locks::thread_list_lock_); @@ -599,8 +609,8 @@ static void ThreadSuspendByPeerWarning(Thread* self, LogSeverity severity, const 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; diff --git a/runtime/thread_list.h b/runtime/thread_list.h index 0f094cc..2c1f813 100644 --- a/runtime/thread_list.h +++ b/runtime/thread_list.h @@ -61,7 +61,9 @@ class ThreadList { LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_); // Suspends all threads and gets exclusive access to the mutator_lock_. - void SuspendAll(const char* cause) + // If long suspend is true, then other people who try to suspend will never timeout. Long suspend + // is currenly used for hprof since large heaps take a long time. + void SuspendAll(const char* cause, bool long_suspend = false) EXCLUSIVE_LOCK_FUNCTION(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_); @@ -184,6 +186,9 @@ class ThreadList { // by mutator lock ensures no thread can read when another thread is modifying it. Histogram<uint64_t> suspend_all_historam_ GUARDED_BY(Locks::mutator_lock_); + // Whether or not the current thread suspension is long. + bool long_suspend_; + friend class Thread; DISALLOW_COPY_AND_ASSIGN(ThreadList); |