OSDN Git Service

Use ScopedObjectAccess in ThreadList::Dump
authorMathieu Chartier <mathieuc@google.com>
Sat, 11 Jun 2016 00:04:20 +0000 (17:04 -0700)
committerMathieu Chartier <mathieuc@google.com>
Sat, 11 Jun 2016 00:52:36 +0000 (17:52 -0700)
Prevent deadlocks if two different threads are calling Dump at the
same time:

Thread 1: Requests thread 2 to suspend
Thread 2: Requests thread 1 to suspend
Both threads are suspended and blocked on ScopedObjectAccess in
thread dumping.

Added to suspend all stress, reduced thread count to 4 temporarily
since this is the maximum number of simultaneous checkpoints.

Bug: 28988206

Change-Id: I9e4b8391ebad0bca0e42a03819c58c99ddba6b35

runtime/thread_list.cc
test/149-suspend-all-stress/src/Main.java
test/149-suspend-all-stress/suspend_all.cc

index da21479..80b99fc 100644 (file)
@@ -234,7 +234,12 @@ void ThreadList::Dump(std::ostream& os, bool dump_native_stack) {
     os << "DALVIK THREADS (" << list_.size() << "):\n";
   }
   DumpCheckpoint checkpoint(&os, dump_native_stack);
-  size_t threads_running_checkpoint = RunCheckpoint(&checkpoint);
+  size_t threads_running_checkpoint;
+  {
+    // Use SOA to prevent deadlocks if multiple threads are calling Dump() at the same time.
+    ScopedObjectAccess soa(Thread::Current());
+    threads_running_checkpoint = RunCheckpoint(&checkpoint);
+  }
   if (threads_running_checkpoint != 0) {
     checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint);
   }
index 6a27c4b..aa94fc9 100644 (file)
@@ -17,7 +17,7 @@
 import java.util.Map;
 
 public class Main implements Runnable {
-    static final int numberOfThreads = 8;
+    static final int numberOfThreads = 4;
 
     public static void main(String[] args) throws Exception {
         System.loadLibrary(args[0]);
index c22ddad..de479a5 100644 (file)
 namespace art {
 
 extern "C" JNIEXPORT void JNICALL Java_Main_suspendAndResume(JNIEnv*, jclass) {
-  usleep(100 * 1000);  // Leave some time for threads to get in here before we start suspending.
-  for (size_t i = 0; i < 500; ++i) {
-    Runtime::Current()->GetThreadList()->SuspendAll(__FUNCTION__);
-    usleep(500);
-    Runtime::Current()->GetThreadList()->ResumeAll();
+  static constexpr size_t kInitialSleepUS = 100 * 1000;  // 100ms.
+  static constexpr size_t kIterations = 500;
+  usleep(kInitialSleepUS);  // Leave some time for threads to get in here before we start suspending.
+  enum Operation {
+    kOPSuspendAll,
+    kOPDumpStack,
+    kOPSuspendAllDumpStack,
+    // Total number of operations.
+    kOPNumber,
+  };
+  for (size_t i = 0; i < kIterations; ++i) {
+    switch (static_cast<Operation>(i % kOPNumber)) {
+      case kOPSuspendAll: {
+        ScopedSuspendAll ssa(__FUNCTION__);
+        usleep(500);
+        break;
+      }
+      case kOPDumpStack: {
+        Runtime::Current()->GetThreadList()->Dump(LOG(INFO));
+        usleep(500);
+        break;
+      }
+      case kOPSuspendAllDumpStack: {
+        // Not yet supported.
+        // ScopedSuspendAll ssa(__FUNCTION__);
+        // Runtime::Current()->GetThreadList()->Dump(LOG(INFO));
+        break;
+      }
+      case kOPNumber:
+        break;
+    }
   }
 }