OSDN Git Service

ART: Fix potential deadlock in class-load events
authorAndreas Gampe <agampe@google.com>
Fri, 10 Feb 2017 19:49:12 +0000 (11:49 -0800)
committerAndreas Gampe <agampe@google.com>
Fri, 10 Feb 2017 19:52:22 +0000 (11:52 -0800)
When a temporary class is given out in a ClassLoad event, all stored
references need to be fixed up before publishing a ClassPrepare event.

This CL fixes a potential deadlock when multiple classes are loaded
at the same time.

Bug: 31684920
Test: m test-art-host-run-test-912-classes
Change-Id: Iccabd8c17838f686a81a825badc7c2b1a1589708

runtime/openjdkjvmti/ti_class.cc

index 66381c2..cf3cfa4 100644 (file)
@@ -292,6 +292,10 @@ struct ClassCallback : public art::ClassLoadCallback {
     }
   }
 
+  // To support parallel class-loading, we need to perform some locking dances here. Namely,
+  // the fixup stage must not be holding the temp_classes lock when it fixes up the system
+  // (as that requires suspending all mutators).
+
   void AddTempClass(art::Thread* self, jclass klass) {
     std::unique_lock<std::mutex> mu(temp_classes_lock);
     jclass global_klass = reinterpret_cast<jclass>(self->GetJniEnv()->NewGlobalRef(klass));
@@ -302,19 +306,25 @@ struct ClassCallback : public art::ClassLoadCallback {
                        art::Handle<art::mirror::Class> temp_klass,
                        art::Handle<art::mirror::Class> klass)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
-    std::unique_lock<std::mutex> mu(temp_classes_lock);
-    if (temp_classes.empty()) {
-      return;
-    }
+    bool requires_fixup = false;
+    {
+      std::unique_lock<std::mutex> mu(temp_classes_lock);
+      if (temp_classes.empty()) {
+        return;
+      }
 
-    for (auto it = temp_classes.begin(); it != temp_classes.end(); ++it) {
-      if (temp_klass.Get() == art::ObjPtr<art::mirror::Class>::DownCast(self->DecodeJObject(*it))) {
-        self->GetJniEnv()->DeleteGlobalRef(*it);
-        temp_classes.erase(it);
-        FixupTempClass(self, temp_klass, klass);
-        break;
+      for (auto it = temp_classes.begin(); it != temp_classes.end(); ++it) {
+        if (temp_klass.Get() == art::ObjPtr<art::mirror::Class>::DownCast(self->DecodeJObject(*it))) {
+          self->GetJniEnv()->DeleteGlobalRef(*it);
+          temp_classes.erase(it);
+          requires_fixup = true;
+          break;
+        }
       }
     }
+    if (requires_fixup) {
+      FixupTempClass(self, temp_klass, klass);
+    }
   }
 
   void FixupTempClass(art::Thread* self,