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;