summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2015-06-02 11:42:18 -0700
committerMathieu Chartier <mathieuc@google.com>2015-06-02 11:42:18 -0700
commit77be6635f9b07a8a794924c5fb9b071949776a6d (patch)
treea15297dc180b530a6885774311f756aef00f66d8
parent2791d5e66f6c802147e2f9275b94b5ca995c396f (diff)
downloadart-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.cc2
-rw-r--r--runtime/thread_list.cc24
-rw-r--r--runtime/thread_list.h7
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);