Remove mutex dependency on art::Runtime

Breaks the cyclic dependency between mutex and the runtime.  This allows
the use of mutexes without instantiating a runtime.

Bug: 22322814
Test: test-art
Change-Id: Ia642e515937068d385e5bb1e10bbd3e50a6e36d2
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 1c32024..92b7c65 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -23,7 +23,6 @@
 
 #include "base/stringprintf.h"
 #include "base/value_object.h"
-#include "runtime.h"
 #include "thread.h"
 #include "utils.h"
 
@@ -59,8 +58,7 @@
   // on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock.
   // TODO: tighten this check.
   if (kDebugLocking) {
-    Runtime* runtime = Runtime::Current();
-    CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDownLocked() ||
+    CHECK(!Locks::IsSafeToCallAbortRacy() ||
           // Used during thread creation to avoid races with runtime shutdown. Thread::Current not
           // yet established.
           level == kRuntimeShutdownLock ||
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index e77e6d7..bde0327 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -25,12 +25,13 @@
 #include "base/systrace.h"
 #include "base/value_object.h"
 #include "mutex-inl.h"
-#include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 namespace art {
 
+static Atomic<Locks::ClientCallback*> safe_to_call_abort_callback(nullptr);
+
 Mutex* Locks::abort_lock_ = nullptr;
 Mutex* Locks::alloc_tracker_lock_ = nullptr;
 Mutex* Locks::allocated_monitor_ids_lock_ = nullptr;
@@ -320,30 +321,26 @@
   exclusive_owner_ = 0;
 }
 
-// Helper to ignore the lock requirement.
-static bool IsShuttingDown() NO_THREAD_SAFETY_ANALYSIS {
-  Runtime* runtime = Runtime::Current();
-  return runtime == nullptr || runtime->IsShuttingDownLocked();
+// Helper to allow checking shutdown while locking for thread safety.
+static bool IsSafeToCallAbortSafe() {
+  MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
+  return Locks::IsSafeToCallAbortRacy();
 }
 
 Mutex::~Mutex() {
-  bool shutting_down = IsShuttingDown();
+  bool safe_to_call_abort = Locks::IsSafeToCallAbortRacy();
 #if ART_USE_FUTEXES
   if (state_.LoadRelaxed() != 0) {
-    LOG(shutting_down
-            ? ::android::base::WARNING
-            : ::android::base::FATAL) << "destroying mutex with owner: " << exclusive_owner_;
+    LOG(safe_to_call_abort ? FATAL : WARNING)
+        << "destroying mutex with owner: " << exclusive_owner_;
   } else {
     if (exclusive_owner_ != 0) {
-      LOG(shutting_down
-              ? ::android::base::WARNING
-              : ::android::base::FATAL) << "unexpectedly found an owner on unlocked mutex "
-                                           << name_;
+      LOG(safe_to_call_abort ? FATAL : WARNING)
+          << "unexpectedly found an owner on unlocked mutex " << name_;
     }
     if (num_contenders_.LoadSequentiallyConsistent() != 0) {
-      LOG(shutting_down
-              ? ::android::base::WARNING
-              : ::android::base::FATAL) << "unexpectedly found a contender on mutex " << name_;
+      LOG(safe_to_call_abort ? FATAL : WARNING)
+          << "unexpectedly found a contender on mutex " << name_;
     }
   }
 #else
@@ -352,11 +349,8 @@
   int rc = pthread_mutex_destroy(&mutex_);
   if (rc != 0) {
     errno = rc;
-    // TODO: should we just not log at all if shutting down? this could be the logging mutex!
-    MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
-    PLOG(shutting_down
-             ? ::android::base::WARNING
-             : ::android::base::FATAL) << "pthread_mutex_destroy failed for " << name_;
+    PLOG(safe_to_call_abort ? FATAL : WARNING)
+        << "pthread_mutex_destroy failed for " << name_;
   }
 #endif
 }
@@ -544,11 +538,8 @@
   int rc = pthread_rwlock_destroy(&rwlock_);
   if (rc != 0) {
     errno = rc;
-    // TODO: should we just not log at all if shutting down? this could be the logging mutex!
-    MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
-    Runtime* runtime = Runtime::Current();
-    bool shutting_down = runtime == nullptr || runtime->IsShuttingDownLocked();
-    PLOG(shutting_down ? WARNING : FATAL) << "pthread_rwlock_destroy failed for " << name_;
+    bool is_safe_to_call_abort = IsSafeToCallAbortSafe();
+    PLOG(is_safe_to_call_abort ? FATAL : WARNING) << "pthread_rwlock_destroy failed for " << name_;
   }
 #endif
 }
@@ -772,11 +763,8 @@
 ConditionVariable::~ConditionVariable() {
 #if ART_USE_FUTEXES
   if (num_waiters_!= 0) {
-    Runtime* runtime = Runtime::Current();
-    bool shutting_down = runtime == nullptr || runtime->IsShuttingDown(Thread::Current());
-    LOG(shutting_down
-           ? ::android::base::WARNING
-           : ::android::base::FATAL)
+    bool is_safe_to_call_abort = IsSafeToCallAbortSafe();
+    LOG(is_safe_to_call_abort ? FATAL : WARNING)
         << "ConditionVariable::~ConditionVariable for " << name_
         << " called with " << num_waiters_ << " waiters.";
   }
@@ -786,12 +774,8 @@
   int rc = pthread_cond_destroy(&cond_);
   if (rc != 0) {
     errno = rc;
-    MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
-    Runtime* runtime = Runtime::Current();
-    bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDownLocked();
-    PLOG(shutting_down
-             ? ::android::base::WARNING
-             : ::android::base::FATAL) << "pthread_cond_destroy failed for " << name_;
+    bool is_safe_to_call_abort = IsSafeToCallAbortSafe();
+    PLOG(is_safe_to_call_abort ? FATAL : WARNING) << "pthread_cond_destroy failed for " << name_;
   }
 #endif
 }
@@ -1129,4 +1113,14 @@
   thread_exit_cond_ = new ConditionVariable("thread exit condition variable", *thread_list_lock_);
 }
 
+void Locks::SetClientCallback(ClientCallback* safe_to_call_abort_cb) {
+  safe_to_call_abort_callback.StoreRelease(safe_to_call_abort_cb);
+}
+
+// Helper to allow checking shutdown while ignoring locking requirements.
+bool Locks::IsSafeToCallAbortRacy() {
+  Locks::ClientCallback* safe_to_call_abort_cb = safe_to_call_abort_callback.LoadAcquire();
+  return safe_to_call_abort_cb != nullptr && safe_to_call_abort_cb();
+}
+
 }  // namespace art
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index e0cca7b..3f2c5a9 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -558,6 +558,18 @@
  public:
   static void Init();
   static void InitConditions() NO_THREAD_SAFETY_ANALYSIS;  // Condition variables.
+
+  // Destroying various lock types can emit errors that vary depending upon
+  // whether the client (art::Runtime) is currently active.  Allow the client
+  // to set a callback that is used to check when it is acceptable to call
+  // Abort.  The default behavior is that the client *is not* able to call
+  // Abort if no callback is established.
+  using ClientCallback = bool();
+  static void SetClientCallback(ClientCallback* is_safe_to_call_abort_cb) NO_THREAD_SAFETY_ANALYSIS;
+  // Checks for whether it is safe to call Abort() without using locks.
+  static bool IsSafeToCallAbortRacy() NO_THREAD_SAFETY_ANALYSIS;
+
+
   // Guards allocation entrypoint instrumenting.
   static Mutex* instrument_entrypoints_lock_;
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index bde4185..e8f41d4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -508,12 +508,21 @@
   return true;
 }
 
+// Callback to check whether it is safe to call Abort (e.g., to use a call to
+// LOG(FATAL)).  It is only safe to call Abort if the runtime has been created,
+// properly initialized, and has not shut down.
+static bool IsSafeToCallAbort() NO_THREAD_SAFETY_ANALYSIS {
+  Runtime* runtime = Runtime::Current();
+  return runtime != nullptr && runtime->IsStarted() && !runtime->IsShuttingDownLocked();
+}
+
 bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
   // TODO: acquire a static mutex on Runtime to avoid racing.
   if (Runtime::instance_ != nullptr) {
     return false;
   }
   instance_ = new Runtime;
+  Locks::SetClientCallback(IsSafeToCallAbort);
   if (!instance_->Init(std::move(runtime_options))) {
     // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
     // leak memory, instead. Fix the destructor. b/19100793.
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 6c3811b..5fa9353 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -29,6 +29,7 @@
 #include "base/mutex-inl.h"
 #include "gc/heap.h"
 #include "jni_env_ext.h"
+#include "runtime.h"
 #include "thread_pool.h"
 
 namespace art {