Fix the empty checkpoint timeout.

The problem happens when a thread is indirectly blocked on a mutex
that another thread holds and is blocked on a weak ref access.

Add a way to do a dummy wakeup on a thread that's blocked on a mutex
so that the thread will respond to the empty checkpoint request. Do
this for the mutexes that are expected to be held when a weak ref is
accessed. Add a check that detects an unexpected case.

Bug: 33006388
Bug: 12687968
Test: test-art-host.
Change-Id: Iefec69b9a21aa25a928cb31fcf4fb872f867a8c2
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index ffe18c6..9b6938f 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -152,6 +152,16 @@
 
   static void DumpAll(std::ostream& os);
 
+  bool ShouldRespondToEmptyCheckpointRequest() const {
+    return should_respond_to_empty_checkpoint_request_;
+  }
+
+  void SetShouldRespondToEmptyCheckpointRequest(bool value) {
+    should_respond_to_empty_checkpoint_request_ = value;
+  }
+
+  virtual void WakeupToRespondToEmptyCheckpoint() = 0;
+
  protected:
   friend class ConditionVariable;
 
@@ -168,6 +178,7 @@
 
   const LockLevel level_;  // Support for lock hierarchy.
   const char* const name_;
+  bool should_respond_to_empty_checkpoint_request_;
 
   // A log entry that records contention but makes no guarantee that either tid will be held live.
   struct ContentionLogEntry {
@@ -266,6 +277,8 @@
   // For negative capabilities in clang annotations.
   const Mutex& operator!() const { return *this; }
 
+  void WakeupToRespondToEmptyCheckpoint() OVERRIDE;
+
  private:
 #if ART_USE_FUTEXES
   // 0 is unheld, 1 is held.
@@ -386,6 +399,8 @@
   // For negative capabilities in clang annotations.
   const ReaderWriterMutex& operator!() const { return *this; }
 
+  void WakeupToRespondToEmptyCheckpoint() OVERRIDE;
+
  private:
 #if ART_USE_FUTEXES
   // Out-of-inline path for handling contention for a SharedLock.
@@ -713,6 +728,12 @@
 
   // Have an exclusive logging thread.
   static Mutex* logging_lock_ ACQUIRED_AFTER(unexpected_signal_lock_);
+
+  // List of mutexes that we expect a thread may hold when accessing weak refs. This is used to
+  // avoid a deadlock in the empty checkpoint while weak ref access is disabled (b/34964016). If we
+  // encounter an unexpected mutex on accessing weak refs,
+  // Thread::CheckEmptyCheckpointFromWeakRefAccess will detect it.
+  static std::vector<BaseMutex*> expected_mutexes_on_weak_ref_access_;
 };
 
 class Roles {