Implement mutex requeueing for cv broadcasts.
Make the mutex guarding a condition variable part of its state. On a
broadcast requeue waiters on the mutex so they are awoken as the mutex
is unlocked (thereby avoiding thundering herds). Explicit futex use
still guarded behind ART_USE_FUTEXES which remains disabled as I'm
unhappy with some of the warts of mutex usage. Uploading so that the API
changes can stabilize.
Change-Id: Iedb601856ccd8bbc3a64da4ba0cee82246e7bcbf
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 09a8de6..5ef8625 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -30,7 +30,7 @@
ThreadList::ThreadList()
: allocated_ids_lock_("allocated thread ids lock"),
suspend_all_count_(0), debug_suspend_all_count_(0),
- thread_exit_cond_("thread exit condition variable") {
+ thread_exit_cond_("thread exit condition variable", *Locks::thread_list_lock_) {
}
ThreadList::~ThreadList() {
@@ -184,10 +184,7 @@
// Block on the mutator lock until all Runnable threads release their share of access.
#if HAVE_TIMED_RWLOCK
// Timeout if we wait more than 30 seconds.
- timespec timeout;
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_sec += 30;
- if (UNLIKELY(!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, timeout))) {
+ if (UNLIKELY(!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0))) {
UnsafeLogFatalForThreadSuspendAllTimeout(self);
}
#else
@@ -226,7 +223,7 @@
// Broadcast a notification to all suspended threads, some or all of
// which may choose to wake up. No need to wait for them.
VLOG(threads) << *self << " ResumeAll waking others";
- Thread::resume_cond_->Broadcast();
+ Thread::resume_cond_->Broadcast(self);
}
VLOG(threads) << *self << " ResumeAll complete";
}
@@ -251,7 +248,7 @@
{
VLOG(threads) << "Resume(" << *thread << ") waking others";
MutexLock mu(self, *Locks::thread_suspend_count_lock_);
- Thread::resume_cond_->Broadcast();
+ Thread::resume_cond_->Broadcast(self);
}
VLOG(threads) << "Resume(" << *thread << ") complete";
@@ -286,10 +283,7 @@
// immediately unlock again.
#if HAVE_TIMED_RWLOCK
// Timeout if we wait more than 30 seconds.
- timespec timeout;
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_sec += 30;
- if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, timeout)) {
+ if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) {
UnsafeLogFatalForThreadSuspendAllTimeout(self);
} else {
Locks::mutator_lock_->ExclusiveUnlock(self);
@@ -328,7 +322,7 @@
Dbg::ClearWaitForEventThread();
while (self->suspend_count_ != 0) {
- Thread::resume_cond_->Wait(self, *Locks::thread_suspend_count_lock_);
+ Thread::resume_cond_->Wait(self);
if (self->suspend_count_ != 0) {
// The condition was signaled but we're still suspended. This
// can happen if the debugger lets go while a SIGQUIT thread
@@ -366,7 +360,7 @@
{
MutexLock mu(self, *Locks::thread_suspend_count_lock_);
- Thread::resume_cond_->Broadcast();
+ Thread::resume_cond_->Broadcast(self);
}
VLOG(threads) << "UndoDebuggerSuspensions(" << *self << ") complete";
@@ -396,7 +390,7 @@
}
if (!all_threads_are_daemons) {
// Wait for another thread to exit before re-checking.
- thread_exit_cond_.Wait(self, *Locks::thread_list_lock_);
+ thread_exit_cond_.Wait(self);
}
} while(!all_threads_are_daemons);
}
@@ -486,7 +480,7 @@
// Signal that a thread just detached.
MutexLock mu(NULL, *Locks::thread_list_lock_);
- thread_exit_cond_.Signal();
+ thread_exit_cond_.Signal(NULL);
}
void ThreadList::ForEach(void (*callback)(Thread*, void*), void* context) {