OSDN Git Service

Stop daemon threads in runtime shutdown
authorMathieu Chartier <mathieuc@google.com>
Wed, 10 Dec 2014 01:38:52 +0000 (17:38 -0800)
committerMathieu Chartier <mathieuc@google.com>
Wed, 10 Dec 2014 17:43:29 +0000 (09:43 -0800)
Ensure that daemons are stopped and joins before bringing down the
runtime. This fixes bugs related to native code still running when
we shutdown the runtime.

Also changed the mutex destructor to allow contenders if we are
deleting a monitor lock level mutex.

Bug: 18577101
Change-Id: I6457b35fd69c6997b9003b5f15f39861749843a9

runtime/base/mutex.cc
runtime/runtime.cc
runtime/well_known_classes.cc
runtime/well_known_classes.h

index aa2aefc..da78082 100644 (file)
@@ -327,8 +327,12 @@ Mutex::~Mutex() {
     LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " << exclusive_owner_;
   } else {
     CHECK_EQ(exclusive_owner_, 0U)  << "unexpectedly found an owner on unlocked mutex " << name_;
-    CHECK_EQ(num_contenders_.LoadSequentiallyConsistent(), 0)
-        << "unexpectedly found a contender on mutex " << name_;
+    if (level_ != kMonitorLock) {
+      // Only check the lock level for non monitor locks since we may still have java threads
+      // waiting on monitors.
+      CHECK_EQ(num_contenders_.LoadSequentiallyConsistent(), 0)
+          << "unexpectedly found a contender on mutex " << name_;
+    }
   }
 #else
   // We can't use CHECK_MUTEX_CALL here because on shutdown a suspended daemon thread
index 078e7d2..32d787a 100644 (file)
@@ -190,6 +190,13 @@ Runtime::~Runtime() {
   }
 
   Thread* self = Thread::Current();
+  if (self == nullptr) {
+    CHECK(AttachCurrentThread("Shutdown thread", false, nullptr, false));
+    self = Thread::Current();
+  } else {
+    LOG(WARNING) << "Current thread not detached in Runtime shutdown";
+  }
+
   {
     MutexLock mu(self, *Locks::runtime_shutdown_lock_);
     shutting_down_started_ = true;
@@ -198,6 +205,16 @@ Runtime::~Runtime() {
     }
     shutting_down_ = true;
   }
+  // Shutdown and wait for the daemons.
+  CHECK(self != nullptr);
+  if (IsFinishedStarting()) {
+    self->ClearException();
+    self->GetJniEnv()->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
+                                            WellKnownClasses::java_lang_Daemons_stop);
+  }
+  DetachCurrentThread();
+  self = nullptr;
+
   // Shut down background profiler before the runtime exits.
   if (profiler_started_) {
     BackgroundMethodSamplingProfiler::Shutdown();
index 16338c4..80bed23 100644 (file)
@@ -69,6 +69,7 @@ jmethodID WellKnownClasses::java_lang_ClassNotFoundException_init;
 jmethodID WellKnownClasses::java_lang_Daemons_requestGC;
 jmethodID WellKnownClasses::java_lang_Daemons_requestHeapTrim;
 jmethodID WellKnownClasses::java_lang_Daemons_start;
+jmethodID WellKnownClasses::java_lang_Daemons_stop;
 jmethodID WellKnownClasses::java_lang_Double_valueOf;
 jmethodID WellKnownClasses::java_lang_Float_valueOf;
 jmethodID WellKnownClasses::java_lang_Integer_valueOf;
@@ -207,6 +208,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
   java_lang_Daemons_requestGC = CacheMethod(env, java_lang_Daemons, true, "requestGC", "()V");
   java_lang_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V");
   java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V");
+  java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V");
 
   ScopedLocalRef<jclass> java_lang_ref_FinalizerReference(env, env->FindClass("java/lang/ref/FinalizerReference"));
   java_lang_ref_FinalizerReference_add = CacheMethod(env, java_lang_ref_FinalizerReference.get(), true, "add", "(Ljava/lang/Object;)V");
index d651b90..cb75e6e 100644 (file)
@@ -80,6 +80,7 @@ struct WellKnownClasses {
   static jmethodID java_lang_Daemons_requestGC;
   static jmethodID java_lang_Daemons_requestHeapTrim;
   static jmethodID java_lang_Daemons_start;
+  static jmethodID java_lang_Daemons_stop;
   static jmethodID java_lang_Double_valueOf;
   static jmethodID java_lang_Float_valueOf;
   static jmethodID java_lang_Integer_valueOf;