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.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