Add two locks to expected_mutexes_on_weak_ref_access_.
The ObjectRegistry lock and the jdwp event list lock to avoid DCHECK
failures.
Some cleanup.
Bug: 35360959
Bug: 35745310
Test: test-art-host
Test: jdwp test.
Test: angler boot.
Change-Id: I16000c0c7624b1271d40c4c1a01a4e249271b67e
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index b93b293..b0394a5 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -73,6 +73,7 @@
Mutex* Locks::jni_weak_globals_lock_ = nullptr;
ReaderWriterMutex* Locks::dex_lock_ = nullptr;
std::vector<BaseMutex*> Locks::expected_mutexes_on_weak_ref_access_;
+Atomic<const BaseMutex*> Locks::expected_mutexes_on_weak_ref_access_guard_;
struct AllMutexData {
// A guard for all_mutexes_ that's not a mutex (Mutexes must CAS to acquire and busy wait).
@@ -117,6 +118,26 @@
const BaseMutex* const mutex_;
};
+class Locks::ScopedExpectedMutexesOnWeakRefAccessLock FINAL {
+ public:
+ explicit ScopedExpectedMutexesOnWeakRefAccessLock(const BaseMutex* mutex) : mutex_(mutex) {
+ while (!Locks::expected_mutexes_on_weak_ref_access_guard_.CompareExchangeWeakAcquire(0,
+ mutex)) {
+ NanoSleep(100);
+ }
+ }
+
+ ~ScopedExpectedMutexesOnWeakRefAccessLock() {
+ while (!Locks::expected_mutexes_on_weak_ref_access_guard_.CompareExchangeWeakRelease(mutex_,
+ 0)) {
+ NanoSleep(100);
+ }
+ }
+
+ private:
+ const BaseMutex* const mutex_;
+};
+
// Scoped class that generates events at the beginning and end of lock contention.
class ScopedContentionRecorder FINAL : public ValueObject {
public:
@@ -1163,12 +1184,9 @@
#undef UPDATE_CURRENT_LOCK_LEVEL
// List of mutexes that we may hold when accessing a weak ref.
- dex_lock_->SetShouldRespondToEmptyCheckpointRequest(true);
- expected_mutexes_on_weak_ref_access_.push_back(dex_lock_);
- classlinker_classes_lock_->SetShouldRespondToEmptyCheckpointRequest(true);
- expected_mutexes_on_weak_ref_access_.push_back(classlinker_classes_lock_);
- jni_libraries_lock_->SetShouldRespondToEmptyCheckpointRequest(true);
- expected_mutexes_on_weak_ref_access_.push_back(jni_libraries_lock_);
+ AddToExpectedMutexesOnWeakRefAccess(dex_lock_, /*need_lock*/ false);
+ AddToExpectedMutexesOnWeakRefAccess(classlinker_classes_lock_, /*need_lock*/ false);
+ AddToExpectedMutexesOnWeakRefAccess(jni_libraries_lock_, /*need_lock*/ false);
InitConditions();
}
@@ -1188,4 +1206,38 @@
return safe_to_call_abort_cb != nullptr && safe_to_call_abort_cb();
}
+void Locks::AddToExpectedMutexesOnWeakRefAccess(BaseMutex* mutex, bool need_lock) {
+ if (need_lock) {
+ ScopedExpectedMutexesOnWeakRefAccessLock mu(mutex);
+ mutex->SetShouldRespondToEmptyCheckpointRequest(true);
+ expected_mutexes_on_weak_ref_access_.push_back(mutex);
+ } else {
+ mutex->SetShouldRespondToEmptyCheckpointRequest(true);
+ expected_mutexes_on_weak_ref_access_.push_back(mutex);
+ }
+}
+
+void Locks::RemoveFromExpectedMutexesOnWeakRefAccess(BaseMutex* mutex, bool need_lock) {
+ if (need_lock) {
+ ScopedExpectedMutexesOnWeakRefAccessLock mu(mutex);
+ mutex->SetShouldRespondToEmptyCheckpointRequest(false);
+ std::vector<BaseMutex*>& list = expected_mutexes_on_weak_ref_access_;
+ auto it = std::find(list.begin(), list.end(), mutex);
+ DCHECK(it != list.end());
+ list.erase(it);
+ } else {
+ mutex->SetShouldRespondToEmptyCheckpointRequest(false);
+ std::vector<BaseMutex*>& list = expected_mutexes_on_weak_ref_access_;
+ auto it = std::find(list.begin(), list.end(), mutex);
+ DCHECK(it != list.end());
+ list.erase(it);
+ }
+}
+
+bool Locks::IsExpectedOnWeakRefAccess(BaseMutex* mutex) {
+ ScopedExpectedMutexesOnWeakRefAccessLock mu(mutex);
+ std::vector<BaseMutex*>& list = expected_mutexes_on_weak_ref_access_;
+ return std::find(list.begin(), list.end(), mutex) != list.end();
+}
+
} // namespace art