Modify the behavior of thread suspend shootouts.
The thread doing the suspension doesn't attempt to suspend the other thread
unless it knows another thread isn't trying to suspend it. Use the suspend
count, and its lock, for this purpose.
Re-enable ThreadStress test.
Bug: 15446488
Change-Id: Idd34410c7b89d8abd6973e5699a15ca699472c78
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 423ea77..4957988 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -57,7 +57,6 @@
Mutex* Locks::reference_queue_weak_references_lock_ = nullptr;
Mutex* Locks::runtime_shutdown_lock_ = nullptr;
Mutex* Locks::thread_list_lock_ = nullptr;
-Mutex* Locks::thread_list_suspend_thread_lock_ = nullptr;
Mutex* Locks::thread_suspend_count_lock_ = nullptr;
Mutex* Locks::trace_lock_ = nullptr;
Mutex* Locks::unexpected_signal_lock_ = nullptr;
@@ -202,7 +201,7 @@
if (i != level_) {
BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
// We expect waits to happen while holding the thread list suspend thread lock.
- if (held_mutex != NULL && i != kThreadListSuspendThreadLock) {
+ if (held_mutex != NULL) {
LOG(ERROR) << "Holding \"" << held_mutex->name_ << "\" "
<< "(level " << LockLevel(i) << ") while performing wait on "
<< "\"" << name_ << "\" (level " << level_ << ")";
@@ -918,16 +917,14 @@
DCHECK(mutator_lock_ != nullptr);
DCHECK(profiler_lock_ != nullptr);
DCHECK(thread_list_lock_ != nullptr);
- DCHECK(thread_list_suspend_thread_lock_ != nullptr);
DCHECK(thread_suspend_count_lock_ != nullptr);
DCHECK(trace_lock_ != nullptr);
DCHECK(unexpected_signal_lock_ != nullptr);
} else {
// Create global locks in level order from highest lock level to lowest.
- LockLevel current_lock_level = kThreadListSuspendThreadLock;
- DCHECK(thread_list_suspend_thread_lock_ == nullptr);
- thread_list_suspend_thread_lock_ =
- new Mutex("thread list suspend thread by .. lock", current_lock_level);
+ LockLevel current_lock_level = kInstrumentEntrypointsLock;
+ DCHECK(instrument_entrypoints_lock_ == nullptr);
+ instrument_entrypoints_lock_ = new Mutex("instrument entrypoint lock", current_lock_level);
#define UPDATE_CURRENT_LOCK_LEVEL(new_level) \
if (new_level >= current_lock_level) { \
@@ -938,10 +935,6 @@
} \
current_lock_level = new_level;
- UPDATE_CURRENT_LOCK_LEVEL(kInstrumentEntrypointsLock);
- DCHECK(instrument_entrypoints_lock_ == nullptr);
- instrument_entrypoints_lock_ = new Mutex("instrument entrypoint lock", current_lock_level);
-
UPDATE_CURRENT_LOCK_LEVEL(kMutatorLock);
DCHECK(mutator_lock_ == nullptr);
mutator_lock_ = new ReaderWriterMutex("mutator lock", current_lock_level);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index d589eb6..9c93cc6 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -101,7 +101,6 @@
kHeapBitmapLock,
kMutatorLock,
kInstrumentEntrypointsLock,
- kThreadListSuspendThreadLock,
kZygoteCreationLock,
kLockLevelCount // Must come last.
@@ -486,17 +485,8 @@
public:
static void Init();
- // There's a potential race for two threads to try to suspend each other and for both of them
- // to succeed and get blocked becoming runnable. This lock ensures that only one thread is
- // requesting suspension of another at any time. As the the thread list suspend thread logic
- // transitions to runnable, if the current thread were tried to be suspended then this thread
- // would block holding this lock until it could safely request thread suspension of the other
- // thread without that thread having a suspension request against this thread. This avoids a
- // potential deadlock cycle.
- static Mutex* thread_list_suspend_thread_lock_;
-
// Guards allocation entrypoint instrumenting.
- static Mutex* instrument_entrypoints_lock_ ACQUIRED_AFTER(thread_list_suspend_thread_lock_);
+ static Mutex* instrument_entrypoints_lock_;
// The mutator_lock_ is used to allow mutators to execute in a shared (reader) mode or to block
// mutators by having an exclusive (writer) owner. In normal execution each mutator thread holds