Add sleep in SuspendAllDaemonThreadsForShutdown
Only sleep if there are still daemon threads. Since we have already
shutdown the runtime daemons, this is a rare case. The goal of the
sleep is to leave daemon threads time to become blocked in a place
where they ideally will not touch runtime state.
Bug: 26483935
Bug: 18577101
Change-Id: Iad12209e771720523620e0a3829a75ec4647f58b
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index ae18819..fc1a445 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -1145,6 +1145,7 @@
void ThreadList::SuspendAllDaemonThreadsForShutdown() {
Thread* self = Thread::Current();
MutexLock mu(self, *Locks::thread_list_lock_);
+ size_t daemons_left = 0;
{ // Tell all the daemons it's time to suspend.
MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
for (const auto& thread : list_) {
@@ -1153,12 +1154,21 @@
CHECK(thread->IsDaemon()) << *thread;
if (thread != self) {
thread->ModifySuspendCount(self, +1, nullptr, false);
+ ++daemons_left;
}
// We are shutting down the runtime, set the JNI functions of all the JNIEnvs to be
// the sleep forever one.
thread->GetJniEnv()->SetFunctionsToRuntimeShutdownFunctions();
}
}
+ // If we have any daemons left, wait 200ms to ensure they are not stuck in a place where they
+ // are about to access runtime state and are not in a runnable state. Examples: Monitor code
+ // or waking up from a condition variable. TODO: Try and see if there is a better way to wait
+ // for daemon threads to be in a blocked state.
+ if (daemons_left > 0) {
+ static constexpr size_t kDaemonSleepTime = 200 * 1000;
+ usleep(kDaemonSleepTime);
+ }
// Give the threads a chance to suspend, complaining if they're slow.
bool have_complained = false;
static constexpr size_t kTimeoutMicroseconds = 2000 * 1000;