1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "thread_list.h" 18 19 #define ATRACE_TAG ATRACE_TAG_DALVIK 20 21 #include <cutils/trace.h> 22 #include <dirent.h> 23 #include <ScopedLocalRef.h> 24 #include <ScopedUtfChars.h> 25 #include <sys/types.h> 26 #include <unistd.h> 27 28 #include <sstream> 29 30 #include "base/histogram-inl.h" 31 #include "base/mutex.h" 32 #include "base/mutex-inl.h" 33 #include "base/time_utils.h" 34 #include "base/timing_logger.h" 35 #include "debugger.h" 36 #include "jni_internal.h" 37 #include "lock_word.h" 38 #include "monitor.h" 39 #include "scoped_thread_state_change.h" 40 #include "thread.h" 41 #include "trace.h" 42 #include "well_known_classes.h" 43 44 namespace art { 45 46 static constexpr uint64_t kLongThreadSuspendThreshold = MsToNs(5); 47 static constexpr uint64_t kThreadSuspendTimeoutMs = 30 * 1000; // 30s. 48 // Use 0 since we want to yield to prevent blocking for an unpredictable amount of time. 49 static constexpr useconds_t kThreadSuspendInitialSleepUs = 0; 50 static constexpr useconds_t kThreadSuspendMaxYieldUs = 3000; 51 static constexpr useconds_t kThreadSuspendMaxSleepUs = 5000; 52 53 ThreadList::ThreadList() 54 : suspend_all_count_(0), debug_suspend_all_count_(0), unregistering_count_(0), 55 suspend_all_historam_("suspend all histogram", 16, 64), long_suspend_(false) { 56 CHECK(Monitor::IsValidLockWord(LockWord::FromThinLockId(kMaxThreadId, 1, 0U))); 57 } 58 59 ThreadList::~ThreadList() { 60 // Detach the current thread if necessary. If we failed to start, there might not be any threads. 61 // We need to detach the current thread here in case there's another thread waiting to join with 62 // us. 63 bool contains = false; 64 { 65 Thread* self = Thread::Current(); 66 MutexLock mu(self, *Locks::thread_list_lock_); 67 contains = Contains(self); 68 } 69 if (contains) { 70 Runtime::Current()->DetachCurrentThread(); 71 } 72 WaitForOtherNonDaemonThreadsToExit(); 73 // TODO: there's an unaddressed race here where a thread may attach during shutdown, see 74 // Thread::Init. 75 SuspendAllDaemonThreads(); 76 } 77 78 bool ThreadList::Contains(Thread* thread) { 79 return find(list_.begin(), list_.end(), thread) != list_.end(); 80 } 81 82 bool ThreadList::Contains(pid_t tid) { 83 for (const auto& thread : list_) { 84 if (thread->GetTid() == tid) { 85 return true; 86 } 87 } 88 return false; 89 } 90 91 pid_t ThreadList::GetLockOwner() { 92 return Locks::thread_list_lock_->GetExclusiveOwnerTid(); 93 } 94 95 void ThreadList::DumpNativeStacks(std::ostream& os) { 96 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); 97 for (const auto& thread : list_) { 98 os << "DUMPING THREAD " << thread->GetTid() << "\n"; 99 DumpNativeStack(os, thread->GetTid(), "\t"); 100 os << "\n"; 101 } 102 } 103 104 void ThreadList::DumpForSigQuit(std::ostream& os) { 105 { 106 ScopedObjectAccess soa(Thread::Current()); 107 // Only print if we have samples. 108 if (suspend_all_historam_.SampleSize() > 0) { 109 Histogram<uint64_t>::CumulativeData data; 110 suspend_all_historam_.CreateHistogram(&data); 111 suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data); // Dump time to suspend. 112 } 113 } 114 Dump(os); 115 DumpUnattachedThreads(os); 116 } 117 118 static void DumpUnattachedThread(std::ostream& os, pid_t tid) NO_THREAD_SAFETY_ANALYSIS { 119 // TODO: No thread safety analysis as DumpState with a null thread won't access fields, should 120 // refactor DumpState to avoid skipping analysis. 121 Thread::DumpState(os, nullptr, tid); 122 DumpKernelStack(os, tid, " kernel: ", false); 123 // TODO: Reenable this when the native code in system_server can handle it. 124 // Currently "adb shell kill -3 `pid system_server`" will cause it to exit. 125 if (false) { 126 DumpNativeStack(os, tid, " native: "); 127 } 128 os << "\n"; 129 } 130 131 void ThreadList::DumpUnattachedThreads(std::ostream& os) { 132 DIR* d = opendir("/proc/self/task"); 133 if (!d) { 134 return; 135 } 136 137 Thread* self = Thread::Current(); 138 dirent* e; 139 while ((e = readdir(d)) != nullptr) { 140 char* end; 141 pid_t tid = strtol(e->d_name, &end, 10); 142 if (!*end) { 143 bool contains; 144 { 145 MutexLock mu(self, *Locks::thread_list_lock_); 146 contains = Contains(tid); 147 } 148 if (!contains) { 149 DumpUnattachedThread(os, tid); 150 } 151 } 152 } 153 closedir(d); 154 } 155 156 // Dump checkpoint timeout in milliseconds. Larger amount on the host, as dumping will invoke 157 // addr2line when available. 158 static constexpr uint32_t kDumpWaitTimeout = kIsTargetBuild ? 10000 : 20000; 159 160 // A closure used by Thread::Dump. 161 class DumpCheckpoint FINAL : public Closure { 162 public: 163 explicit DumpCheckpoint(std::ostream* os) : os_(os), barrier_(0) {} 164 165 void Run(Thread* thread) OVERRIDE { 166 // Note thread and self may not be equal if thread was already suspended at the point of the 167 // request. 168 Thread* self = Thread::Current(); 169 std::ostringstream local_os; 170 { 171 ScopedObjectAccess soa(self); 172 thread->Dump(local_os); 173 } 174 local_os << "\n"; 175 { 176 // Use the logging lock to ensure serialization when writing to the common ostream. 177 MutexLock mu(self, *Locks::logging_lock_); 178 *os_ << local_os.str(); 179 } 180 if (thread->GetState() == kRunnable) { 181 barrier_.Pass(self); 182 } 183 } 184 185 void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) { 186 Thread* self = Thread::Current(); 187 ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun); 188 bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kDumpWaitTimeout); 189 if (timed_out) { 190 // Avoid a recursive abort. 191 LOG((kIsDebugBuild && (gAborting == 0)) ? FATAL : ERROR) 192 << "Unexpected time out during dump checkpoint."; 193 } 194 } 195 196 private: 197 // The common stream that will accumulate all the dumps. 198 std::ostream* const os_; 199 // The barrier to be passed through and for the requestor to wait upon. 200 Barrier barrier_; 201 }; 202 203 void ThreadList::Dump(std::ostream& os) { 204 { 205 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); 206 os << "DALVIK THREADS (" << list_.size() << "):\n"; 207 } 208 DumpCheckpoint checkpoint(&os); 209 size_t threads_running_checkpoint = RunCheckpoint(&checkpoint); 210 if (threads_running_checkpoint != 0) { 211 checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint); 212 } 213 } 214 215 void ThreadList::AssertThreadsAreSuspended(Thread* self, Thread* ignore1, Thread* ignore2) { 216 MutexLock mu(self, *Locks::thread_list_lock_); 217 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 218 for (const auto& thread : list_) { 219 if (thread != ignore1 && thread != ignore2) { 220 CHECK(thread->IsSuspended()) 221 << "\nUnsuspended thread: <<" << *thread << "\n" 222 << "self: <<" << *Thread::Current(); 223 } 224 } 225 } 226 227 #if HAVE_TIMED_RWLOCK 228 // Attempt to rectify locks so that we dump thread list with required locks before exiting. 229 NO_RETURN static void UnsafeLogFatalForThreadSuspendAllTimeout() { 230 Runtime* runtime = Runtime::Current(); 231 std::ostringstream ss; 232 ss << "Thread suspend timeout\n"; 233 Locks::mutator_lock_->Dump(ss); 234 ss << "\n"; 235 runtime->GetThreadList()->Dump(ss); 236 LOG(FATAL) << ss.str(); 237 exit(0); 238 } 239 #endif 240 241 // Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an 242 // individual thread requires polling. delay_us is the requested sleep wait. If delay_us is 0 then 243 // we use sched_yield instead of calling usleep. 244 static void ThreadSuspendSleep(useconds_t delay_us) { 245 if (delay_us == 0) { 246 sched_yield(); 247 } else { 248 usleep(delay_us); 249 } 250 } 251 252 size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) { 253 Thread* self = Thread::Current(); 254 Locks::mutator_lock_->AssertNotExclusiveHeld(self); 255 Locks::thread_list_lock_->AssertNotHeld(self); 256 Locks::thread_suspend_count_lock_->AssertNotHeld(self); 257 if (kDebugLocking && gAborting == 0) { 258 CHECK_NE(self->GetState(), kRunnable); 259 } 260 261 std::vector<Thread*> suspended_count_modified_threads; 262 size_t count = 0; 263 { 264 // Call a checkpoint function for each thread, threads which are suspend get their checkpoint 265 // manually called. 266 MutexLock mu(self, *Locks::thread_list_lock_); 267 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 268 for (const auto& thread : list_) { 269 if (thread != self) { 270 while (true) { 271 if (thread->RequestCheckpoint(checkpoint_function)) { 272 // This thread will run its checkpoint some time in the near future. 273 count++; 274 break; 275 } else { 276 // We are probably suspended, try to make sure that we stay suspended. 277 // The thread switched back to runnable. 278 if (thread->GetState() == kRunnable) { 279 // Spurious fail, try again. 280 continue; 281 } 282 thread->ModifySuspendCount(self, +1, false); 283 suspended_count_modified_threads.push_back(thread); 284 break; 285 } 286 } 287 } 288 } 289 } 290 291 // Run the checkpoint on ourself while we wait for threads to suspend. 292 checkpoint_function->Run(self); 293 294 // Run the checkpoint on the suspended threads. 295 for (const auto& thread : suspended_count_modified_threads) { 296 if (!thread->IsSuspended()) { 297 if (ATRACE_ENABLED()) { 298 std::ostringstream oss; 299 thread->ShortDump(oss); 300 ATRACE_BEGIN((std::string("Waiting for suspension of thread ") + oss.str()).c_str()); 301 } 302 // Busy wait until the thread is suspended. 303 const uint64_t start_time = NanoTime(); 304 do { 305 ThreadSuspendSleep(kThreadSuspendInitialSleepUs); 306 } while (!thread->IsSuspended()); 307 const uint64_t total_delay = NanoTime() - start_time; 308 // Shouldn't need to wait for longer than 1000 microseconds. 309 constexpr uint64_t kLongWaitThreshold = MsToNs(1); 310 ATRACE_END(); 311 if (UNLIKELY(total_delay > kLongWaitThreshold)) { 312 LOG(WARNING) << "Long wait of " << PrettyDuration(total_delay) << " for " 313 << *thread << " suspension!"; 314 } 315 } 316 // We know for sure that the thread is suspended at this point. 317 checkpoint_function->Run(thread); 318 { 319 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 320 thread->ModifySuspendCount(self, -1, false); 321 } 322 } 323 324 { 325 // Imitate ResumeAll, threads may be waiting on Thread::resume_cond_ since we raised their 326 // suspend count. Now the suspend_count_ is lowered so we must do the broadcast. 327 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 328 Thread::resume_cond_->Broadcast(self); 329 } 330 331 return count; 332 } 333 334 // Request that a checkpoint function be run on all active (non-suspended) 335 // threads. Returns the number of successful requests. 336 size_t ThreadList::RunCheckpointOnRunnableThreads(Closure* checkpoint_function) { 337 Thread* self = Thread::Current(); 338 Locks::mutator_lock_->AssertNotExclusiveHeld(self); 339 Locks::thread_list_lock_->AssertNotHeld(self); 340 Locks::thread_suspend_count_lock_->AssertNotHeld(self); 341 CHECK_NE(self->GetState(), kRunnable); 342 343 size_t count = 0; 344 { 345 // Call a checkpoint function for each non-suspended thread. 346 MutexLock mu(self, *Locks::thread_list_lock_); 347 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 348 for (const auto& thread : list_) { 349 if (thread != self) { 350 if (thread->RequestCheckpoint(checkpoint_function)) { 351 // This thread will run its checkpoint some time in the near future. 352 count++; 353 } 354 } 355 } 356 } 357 358 // Return the number of threads that will run the checkpoint function. 359 return count; 360 } 361 362 // A checkpoint/suspend-all hybrid to switch thread roots from 363 // from-space to to-space refs. Used to synchronize threads at a point 364 // to mark the initiation of marking while maintaining the to-space 365 // invariant. 366 size_t ThreadList::FlipThreadRoots(Closure* thread_flip_visitor, Closure* flip_callback, 367 gc::collector::GarbageCollector* collector) { 368 TimingLogger::ScopedTiming split("ThreadListFlip", collector->GetTimings()); 369 const uint64_t start_time = NanoTime(); 370 Thread* self = Thread::Current(); 371 Locks::mutator_lock_->AssertNotHeld(self); 372 Locks::thread_list_lock_->AssertNotHeld(self); 373 Locks::thread_suspend_count_lock_->AssertNotHeld(self); 374 CHECK_NE(self->GetState(), kRunnable); 375 376 std::vector<Thread*> runnable_threads; 377 std::vector<Thread*> other_threads; 378 379 // Suspend all threads once. 380 { 381 MutexLock mu(self, *Locks::thread_list_lock_); 382 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 383 // Update global suspend all state for attaching threads. 384 ++suspend_all_count_; 385 // Increment everybody's suspend count (except our own). 386 for (const auto& thread : list_) { 387 if (thread == self) { 388 continue; 389 } 390 thread->ModifySuspendCount(self, +1, false); 391 } 392 } 393 394 // Run the flip callback for the collector. 395 Locks::mutator_lock_->ExclusiveLock(self); 396 flip_callback->Run(self); 397 Locks::mutator_lock_->ExclusiveUnlock(self); 398 collector->RegisterPause(NanoTime() - start_time); 399 400 // Resume runnable threads. 401 { 402 MutexLock mu(self, *Locks::thread_list_lock_); 403 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 404 --suspend_all_count_; 405 for (const auto& thread : list_) { 406 if (thread == self) { 407 continue; 408 } 409 // Set the flip function for both runnable and suspended threads 410 // because Thread::DumpState/DumpJavaStack() (invoked by a 411 // checkpoint) may cause the flip function to be run for a 412 // runnable/suspended thread before a runnable threads runs it 413 // for itself or we run it for a suspended thread below. 414 thread->SetFlipFunction(thread_flip_visitor); 415 if (thread->IsSuspendedAtSuspendCheck()) { 416 // The thread will resume right after the broadcast. 417 thread->ModifySuspendCount(self, -1, false); 418 runnable_threads.push_back(thread); 419 } else { 420 other_threads.push_back(thread); 421 } 422 } 423 Thread::resume_cond_->Broadcast(self); 424 } 425 426 // Run the closure on the other threads and let them resume. 427 { 428 ReaderMutexLock mu(self, *Locks::mutator_lock_); 429 for (const auto& thread : other_threads) { 430 Closure* flip_func = thread->GetFlipFunction(); 431 if (flip_func != nullptr) { 432 flip_func->Run(thread); 433 } 434 } 435 // Run it for self. 436 thread_flip_visitor->Run(self); 437 } 438 439 // Resume other threads. 440 { 441 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 442 for (const auto& thread : other_threads) { 443 thread->ModifySuspendCount(self, -1, false); 444 } 445 Thread::resume_cond_->Broadcast(self); 446 } 447 448 return runnable_threads.size() + other_threads.size() + 1; // +1 for self. 449 } 450 451 void ThreadList::SuspendAll(const char* cause, bool long_suspend) { 452 Thread* self = Thread::Current(); 453 454 if (self != nullptr) { 455 VLOG(threads) << *self << " SuspendAll for " << cause << " starting..."; 456 } else { 457 VLOG(threads) << "Thread[null] SuspendAll for " << cause << " starting..."; 458 } 459 ATRACE_BEGIN("Suspending mutator threads"); 460 const uint64_t start_time = NanoTime(); 461 462 Locks::mutator_lock_->AssertNotHeld(self); 463 Locks::thread_list_lock_->AssertNotHeld(self); 464 Locks::thread_suspend_count_lock_->AssertNotHeld(self); 465 if (kDebugLocking && self != nullptr) { 466 CHECK_NE(self->GetState(), kRunnable); 467 } 468 { 469 MutexLock mu(self, *Locks::thread_list_lock_); 470 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 471 // Update global suspend all state for attaching threads. 472 ++suspend_all_count_; 473 // Increment everybody's suspend count (except our own). 474 for (const auto& thread : list_) { 475 if (thread == self) { 476 continue; 477 } 478 VLOG(threads) << "requesting thread suspend: " << *thread; 479 thread->ModifySuspendCount(self, +1, false); 480 } 481 } 482 483 // Block on the mutator lock until all Runnable threads release their share of access. 484 #if HAVE_TIMED_RWLOCK 485 while (true) { 486 if (Locks::mutator_lock_->ExclusiveLockWithTimeout(self, kThreadSuspendTimeoutMs, 0)) { 487 break; 488 } else if (!long_suspend_) { 489 // Reading long_suspend without the mutator lock is slightly racy, in some rare cases, this 490 // could result in a thread suspend timeout. 491 // Timeout if we wait more than kThreadSuspendTimeoutMs seconds. 492 UnsafeLogFatalForThreadSuspendAllTimeout(); 493 } 494 } 495 #else 496 Locks::mutator_lock_->ExclusiveLock(self); 497 #endif 498 499 long_suspend_ = long_suspend; 500 501 const uint64_t end_time = NanoTime(); 502 const uint64_t suspend_time = end_time - start_time; 503 suspend_all_historam_.AdjustAndAddValue(suspend_time); 504 if (suspend_time > kLongThreadSuspendThreshold) { 505 LOG(WARNING) << "Suspending all threads took: " << PrettyDuration(suspend_time); 506 } 507 508 if (kDebugLocking) { 509 // Debug check that all threads are suspended. 510 AssertThreadsAreSuspended(self, self); 511 } 512 513 ATRACE_END(); 514 ATRACE_BEGIN((std::string("Mutator threads suspended for ") + cause).c_str()); 515 516 if (self != nullptr) { 517 VLOG(threads) << *self << " SuspendAll complete"; 518 } else { 519 VLOG(threads) << "Thread[null] SuspendAll complete"; 520 } 521 } 522 523 void ThreadList::ResumeAll() { 524 Thread* self = Thread::Current(); 525 526 if (self != nullptr) { 527 VLOG(threads) << *self << " ResumeAll starting"; 528 } else { 529 VLOG(threads) << "Thread[null] ResumeAll starting"; 530 } 531 532 ATRACE_END(); 533 ATRACE_BEGIN("Resuming mutator threads"); 534 535 if (kDebugLocking) { 536 // Debug check that all threads are suspended. 537 AssertThreadsAreSuspended(self, self); 538 } 539 540 long_suspend_ = false; 541 542 Locks::mutator_lock_->ExclusiveUnlock(self); 543 { 544 MutexLock mu(self, *Locks::thread_list_lock_); 545 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 546 // Update global suspend all state for attaching threads. 547 --suspend_all_count_; 548 // Decrement the suspend counts for all threads. 549 for (const auto& thread : list_) { 550 if (thread == self) { 551 continue; 552 } 553 thread->ModifySuspendCount(self, -1, false); 554 } 555 556 // Broadcast a notification to all suspended threads, some or all of 557 // which may choose to wake up. No need to wait for them. 558 if (self != nullptr) { 559 VLOG(threads) << *self << " ResumeAll waking others"; 560 } else { 561 VLOG(threads) << "Thread[null] ResumeAll waking others"; 562 } 563 Thread::resume_cond_->Broadcast(self); 564 } 565 ATRACE_END(); 566 567 if (self != nullptr) { 568 VLOG(threads) << *self << " ResumeAll complete"; 569 } else { 570 VLOG(threads) << "Thread[null] ResumeAll complete"; 571 } 572 } 573 574 void ThreadList::Resume(Thread* thread, bool for_debugger) { 575 // This assumes there was an ATRACE_BEGIN when we suspended the thread. 576 ATRACE_END(); 577 578 Thread* self = Thread::Current(); 579 DCHECK_NE(thread, self); 580 VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") starting..." 581 << (for_debugger ? " (debugger)" : ""); 582 583 { 584 // To check Contains. 585 MutexLock mu(self, *Locks::thread_list_lock_); 586 // To check IsSuspended. 587 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 588 DCHECK(thread->IsSuspended()); 589 if (!Contains(thread)) { 590 // We only expect threads within the thread-list to have been suspended otherwise we can't 591 // stop such threads from delete-ing themselves. 592 LOG(ERROR) << "Resume(" << reinterpret_cast<void*>(thread) 593 << ") thread not within thread list"; 594 return; 595 } 596 thread->ModifySuspendCount(self, -1, for_debugger); 597 } 598 599 { 600 VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") waking others"; 601 MutexLock mu(self, *Locks::thread_suspend_count_lock_); 602 Thread::resume_cond_->Broadcast(self); 603 } 604 605 VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") complete"; 606 } 607 608 static void ThreadSuspendByPeerWarning(Thread* self, LogSeverity severity, const char* message, 609 jobject peer) { 610 JNIEnvExt* env = self->GetJniEnv(); 611 ScopedLocalRef<jstring> 612 scoped_name_string(env, (jstring)env->GetObjectField( 613 peer, WellKnownClasses::java_lang_Thread_name)); 614 ScopedUtfChars scoped_name_chars(env, scoped_name_string.get()); 615 if (scoped_name_chars.c_str() == nullptr) { 616 LOG(severity) << message << ": " << peer; 617 env->ExceptionClear(); 618 } else { 619 LOG(severity) << message << ": " << peer << ":" << scoped_name_chars.c_str(); 620 } 621 } 622 623 Thread* ThreadList::SuspendThreadByPeer(jobject peer, bool request_suspension, 624 bool debug_suspension, bool* timed_out) { 625 const uint64_t start_time = NanoTime(); 626 useconds_t sleep_us = kThreadSuspendInitialSleepUs; 627 *timed_out = false; 628 Thread* const self = Thread::Current(); 629 Thread* suspended_thread = nullptr; 630 VLOG(threads) << "SuspendThreadByPeer starting"; 631 while (true) { 632 Thread* thread; 633 { 634 // Note: this will transition to runnable and potentially suspend. We ensure only one thread 635 // is requesting another suspend, to avoid deadlock, by requiring this function be called 636 // holding Locks::thread_list_suspend_thread_lock_. Its important this thread suspend rather 637 // than request thread suspension, to avoid potential cycles in threads requesting each other 638 // suspend. 639 ScopedObjectAccess soa(self); 640 MutexLock thread_list_mu(self, *Locks::thread_list_lock_); 641 thread = Thread::FromManagedThread(soa, peer); 642 if (thread == nullptr) { 643 if (suspended_thread != nullptr) { 644 MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); 645 // If we incremented the suspend count but the thread reset its peer, we need to 646 // re-decrement it since it is shutting down and may deadlock the runtime in 647 // ThreadList::WaitForOtherNonDaemonThreadsToExit. 648 suspended_thread->ModifySuspendCount(soa.Self(), -1, debug_suspension); 649 } 650 ThreadSuspendByPeerWarning(self, WARNING, "No such thread for suspend", peer); 651 return nullptr; 652 } 653 if (!Contains(thread)) { 654 CHECK(suspended_thread == nullptr); 655 VLOG(threads) << "SuspendThreadByPeer failed for unattached thread: " 656 << reinterpret_cast<void*>(thread); 657 return nullptr; 658 } 659 VLOG(threads) << "SuspendThreadByPeer found thread: " << *thread; 660 { 661 MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); 662 if (request_suspension) { 663 if (self->GetSuspendCount() > 0) { 664 // We hold the suspend count lock but another thread is trying to suspend us. Its not 665 // safe to try to suspend another thread in case we get a cycle. Start the loop again 666 // which will allow this thread to be suspended. 667 continue; 668 } 669 CHECK(suspended_thread == nullptr); 670 suspended_thread = thread; 671 suspended_thread->ModifySuspendCount(self, +1, debug_suspension); 672 request_suspension = false; 673 } else { 674 // If the caller isn't requesting suspension, a suspension should have already occurred. 675 CHECK_GT(thread->GetSuspendCount(), 0); 676 } 677 // IsSuspended on the current thread will fail as the current thread is changed into 678 // Runnable above. As the suspend count is now raised if this is the current thread 679 // it will self suspend on transition to Runnable, making it hard to work with. It's simpler 680 // to just explicitly handle the current thread in the callers to this code. 681 CHECK_NE(thread, self) << "Attempt to suspend the current thread for the debugger"; 682 // If thread is suspended (perhaps it was already not Runnable but didn't have a suspend 683 // count, or else we've waited and it has self suspended) or is the current thread, we're 684 // done. 685 if (thread->IsSuspended()) { 686 VLOG(threads) << "SuspendThreadByPeer thread suspended: " << *thread; 687 if (ATRACE_ENABLED()) { 688 std::string name; 689 thread->GetThreadName(name); 690 ATRACE_BEGIN(StringPrintf("SuspendThreadByPeer suspended %s for peer=%p", name.c_str(), 691 peer).c_str()); 692 } 693 return thread; 694 } 695 const uint64_t total_delay = NanoTime() - start_time; 696 if (total_delay >= MsToNs(kThreadSuspendTimeoutMs)) { 697 ThreadSuspendByPeerWarning(self, FATAL, "Thread suspension timed out", peer); 698 if (suspended_thread != nullptr) { 699 CHECK_EQ(suspended_thread, thread); 700 suspended_thread->ModifySuspendCount(soa.Self(), -1, debug_suspension); 701 } 702 *timed_out = true; 703 return nullptr; 704 } else if (sleep_us == 0 && 705 total_delay > static_cast<uint64_t>(kThreadSuspendMaxYieldUs) * 1000) { 706 // We have spun for kThreadSuspendMaxYieldUs time, switch to sleeps to prevent 707 // excessive CPU usage. 708 sleep_us = kThreadSuspendMaxYieldUs / 2; 709 } 710 } 711 // Release locks and come out of runnable state. 712 } 713 VLOG(threads) << "SuspendThreadByPeer waiting to allow thread chance to suspend"; 714 ThreadSuspendSleep(sleep_us); 715 // This may stay at 0 if sleep_us == 0, but this is WAI since we want to avoid using usleep at 716 // all if possible. This shouldn't be an issue since time to suspend should always be small. 717 sleep_us = std::min(sleep_us * 2, kThreadSuspendMaxSleepUs); 718 } 719 } 720 721 static void ThreadSuspendByThreadIdWarning(LogSeverity severity, const char* message, 722 uint32_t thread_id) { 723 LOG(severity) << StringPrintf("%s: %d", message, thread_id); 724 } 725 726 Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspension, 727 bool* timed_out) { 728 const uint64_t start_time = NanoTime(); 729 useconds_t sleep_us = kThreadSuspendInitialSleepUs; 730 *timed_out = false; 731 Thread* suspended_thread = nullptr; 732 Thread* const self = Thread::Current(); 733 CHECK_NE(thread_id, kInvalidThreadId); 734 VLOG(threads) << "SuspendThreadByThreadId starting"; 735 while (true) { 736 { 737 // Note: this will transition to runnable and potentially suspend. We ensure only one thread 738 // is requesting another suspend, to avoid deadlock, by requiring this function be called 739 // holding Locks::thread_list_suspend_thread_lock_. Its important this thread suspend rather 740 // than request thread suspension, to avoid potential cycles in threads requesting each other 741 // suspend. 742 ScopedObjectAccess soa(self); 743 MutexLock thread_list_mu(self, *Locks::thread_list_lock_); 744 Thread* thread = nullptr; 745 for (const auto& it : list_) { 746 if (it->GetThreadId() == thread_id) { 747 thread = it; 748 break; 749 } 750 } 751 if (thread == nullptr) { 752 CHECK(suspended_thread == nullptr) << "Suspended thread " << suspended_thread 753 << " no longer in thread list"; 754 // There's a race in inflating a lock and the owner giving up ownership and then dying. 755 ThreadSuspendByThreadIdWarning(WARNING, "No such thread id for suspend", thread_id); 756 return nullptr; 757 } 758 VLOG(threads) << "SuspendThreadByThreadId found thread: " << *thread; 759 DCHECK(Contains(thread)); 760 { 761 MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); 762 if (suspended_thread == nullptr) { 763 if (self->GetSuspendCount() > 0) { 764 // We hold the suspend count lock but another thread is trying to suspend us. Its not 765 // safe to try to suspend another thread in case we get a cycle. Start the loop again 766 // which will allow this thread to be suspended. 767 continue; 768 } 769 thread->ModifySuspendCount(self, +1, debug_suspension); 770 suspended_thread = thread; 771 } else { 772 CHECK_EQ(suspended_thread, thread); 773 // If the caller isn't requesting suspension, a suspension should have already occurred. 774 CHECK_GT(thread->GetSuspendCount(), 0); 775 } 776 // IsSuspended on the current thread will fail as the current thread is changed into 777 // Runnable above. As the suspend count is now raised if this is the current thread 778 // it will self suspend on transition to Runnable, making it hard to work with. It's simpler 779 // to just explicitly handle the current thread in the callers to this code. 780 CHECK_NE(thread, self) << "Attempt to suspend the current thread for the debugger"; 781 // If thread is suspended (perhaps it was already not Runnable but didn't have a suspend 782 // count, or else we've waited and it has self suspended) or is the current thread, we're 783 // done. 784 if (thread->IsSuspended()) { 785 if (ATRACE_ENABLED()) { 786 std::string name; 787 thread->GetThreadName(name); 788 ATRACE_BEGIN(StringPrintf("SuspendThreadByThreadId suspended %s id=%d", 789 name.c_str(), thread_id).c_str()); 790 } 791 VLOG(threads) << "SuspendThreadByThreadId thread suspended: " << *thread; 792 return thread; 793 } 794 const uint64_t total_delay = NanoTime() - start_time; 795 if (total_delay >= MsToNs(kThreadSuspendTimeoutMs)) { 796 ThreadSuspendByThreadIdWarning(WARNING, "Thread suspension timed out", thread_id); 797 if (suspended_thread != nullptr) { 798 thread->ModifySuspendCount(soa.Self(), -1, debug_suspension); 799 } 800 *timed_out = true; 801 return nullptr; 802 } else if (sleep_us == 0 && 803 total_delay > static_cast<uint64_t>(kThreadSuspendMaxYieldUs) * 1000) { 804 // We have spun for kThreadSuspendMaxYieldUs time, switch to sleeps to prevent 805 // excessive CPU usage. 806 sleep_us = kThreadSuspendMaxYieldUs / 2; 807 } 808 } 809 // Release locks and come out of runnable state. 810 } 811 VLOG(threads) << "SuspendThreadByThreadId waiting to allow thread chance to suspend"; 812 ThreadSuspendSleep(sleep_us); 813 sleep_us = std::min(sleep_us * 2, kThreadSuspendMaxSleepUs); 814 } 815 } 816 817 Thread* ThreadList::FindThreadByThreadId(uint32_t thin_lock_id) { 818 Thread* self = Thread::Current(); 819 MutexLock mu(self, *Locks::thread_list_lock_); 820 for (const auto& thread : list_) { 821 if (thread->GetThreadId() == thin_lock_id) { 822 CHECK(thread == self || thread->IsSuspended()); 823 return thread; 824 } 825 } 826 return nullptr; 827 } 828 829 void ThreadList::SuspendAllForDebugger() { 830 Thread* self = Thread::Current(); 831 Thread* debug_thread = Dbg::GetDebugThread(); 832 833 VLOG(threads) << *self << " SuspendAllForDebugger starting..."; 834 835 { 836 MutexLock thread_list_mu(self, *Locks::thread_list_lock_); 837 { 838 MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); 839 // Update global suspend all state for attaching threads. 840 DCHECK_GE(suspend_all_count_, debug_suspend_all_count_); 841 ++suspend_all_count_; 842 ++debug_suspend_all_count_; 843 // Increment everybody's suspend count (except our own). 844 for (const auto& thread : list_) { 845 if (thread == self || thread == debug_thread) { 846 continue; 847 } 848 VLOG(threads) << "requesting thread suspend: " << *thread; 849 thread->ModifySuspendCount(self, +1, true); 850 } 851 } 852 } 853 854 // Block on the mutator lock until all Runnable threads release their share of access then 855 // immediately unlock again. 856 #if HAVE_TIMED_RWLOCK 857 // Timeout if we wait more than 30 seconds. 858 if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) { 859 UnsafeLogFatalForThreadSuspendAllTimeout(); 860 } else { 861 Locks::mutator_lock_->ExclusiveUnlock(self); 862 } 863 #else 864 Locks::mutator_lock_->ExclusiveLock(self); 865 Locks::mutator_lock_->ExclusiveUnlock(self); 866 #endif 867 AssertThreadsAreSuspended(self, self, debug_thread); 868 869 VLOG(threads) << *self << " SuspendAllForDebugger complete"; 870 } 871 872 void ThreadList::SuspendSelfForDebugger() { 873 Thread* const self = Thread::Current(); 874 self->SetReadyForDebugInvoke(true); 875 876 // The debugger thread must not suspend itself due to debugger activity! 877 Thread* debug_thread = Dbg::GetDebugThread(); 878 CHECK(self != debug_thread); 879 CHECK_NE(self->GetState(), kRunnable); 880 Locks::mutator_lock_->AssertNotHeld(self); 881 882 // The debugger may have detached while we were executing an invoke request. In that case, we 883 // must not suspend ourself. 884 DebugInvokeReq* pReq = self->GetInvokeReq(); 885 const bool skip_thread_suspension = (pReq != nullptr && !Dbg::IsDebuggerActive()); 886 if (!skip_thread_suspension) { 887 // Collisions with other suspends aren't really interesting. We want 888 // to ensure that we're the only one fiddling with the suspend count 889 // though. 890 MutexLock mu(self, *Locks::thread_suspend_count_lock_); 891 self->ModifySuspendCount(self, +1, true); 892 CHECK_GT(self->GetSuspendCount(), 0); 893 894 VLOG(threads) << *self << " self-suspending (debugger)"; 895 } else { 896 // We must no longer be subject to debugger suspension. 897 MutexLock mu(self, *Locks::thread_suspend_count_lock_); 898 CHECK_EQ(self->GetDebugSuspendCount(), 0) << "Debugger detached without resuming us"; 899 900 VLOG(threads) << *self << " not self-suspending because debugger detached during invoke"; 901 } 902 903 // If the debugger requested an invoke, we need to send the reply and clear the request. 904 if (pReq != nullptr) { 905 Dbg::FinishInvokeMethod(pReq); 906 self->ClearDebugInvokeReq(); 907 pReq = nullptr; // object has been deleted, clear it for safety. 908 } 909 910 // Tell JDWP that we've completed suspension. The JDWP thread can't 911 // tell us to resume before we're fully asleep because we hold the 912 // suspend count lock. 913 Dbg::ClearWaitForEventThread(); 914 915 { 916 MutexLock mu(self, *Locks::thread_suspend_count_lock_); 917 while (self->GetSuspendCount() != 0) { 918 Thread::resume_cond_->Wait(self); 919 if (self->GetSuspendCount() != 0) { 920 // The condition was signaled but we're still suspended. This 921 // can happen when we suspend then resume all threads to 922 // update instrumentation or compute monitor info. This can 923 // also happen if the debugger lets go while a SIGQUIT thread 924 // dump event is pending (assuming SignalCatcher was resumed for 925 // just long enough to try to grab the thread-suspend lock). 926 VLOG(jdwp) << *self << " still suspended after undo " 927 << "(suspend count=" << self->GetSuspendCount() << ", " 928 << "debug suspend count=" << self->GetDebugSuspendCount() << ")"; 929 } 930 } 931 CHECK_EQ(self->GetSuspendCount(), 0); 932 } 933 934 self->SetReadyForDebugInvoke(false); 935 VLOG(threads) << *self << " self-reviving (debugger)"; 936 } 937 938 void ThreadList::ResumeAllForDebugger() { 939 Thread* self = Thread::Current(); 940 Thread* debug_thread = Dbg::GetDebugThread(); 941 942 VLOG(threads) << *self << " ResumeAllForDebugger starting..."; 943 944 // Threads can't resume if we exclusively hold the mutator lock. 945 Locks::mutator_lock_->AssertNotExclusiveHeld(self); 946 947 { 948 MutexLock thread_list_mu(self, *Locks::thread_list_lock_); 949 { 950 MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); 951 // Update global suspend all state for attaching threads. 952 DCHECK_GE(suspend_all_count_, debug_suspend_all_count_); 953 if (debug_suspend_all_count_ > 0) { 954 --suspend_all_count_; 955 --debug_suspend_all_count_; 956 } else { 957 // We've been asked to resume all threads without being asked to 958 // suspend them all before. That may happen if a debugger tries 959 // to resume some suspended threads (with suspend count == 1) 960 // at once with a VirtualMachine.Resume command. Let's print a 961 // warning. 962 LOG(WARNING) << "Debugger attempted to resume all threads without " 963 << "having suspended them all before."; 964 } 965 // Decrement everybody's suspend count (except our own). 966 for (const auto& thread : list_) { 967 if (thread == self || thread == debug_thread) { 968 continue; 969 } 970 if (thread->GetDebugSuspendCount() == 0) { 971 // This thread may have been individually resumed with ThreadReference.Resume. 972 continue; 973 } 974 VLOG(threads) << "requesting thread resume: " << *thread; 975 thread->ModifySuspendCount(self, -1, true); 976 } 977 } 978 } 979 980 { 981 MutexLock mu(self, *Locks::thread_suspend_count_lock_); 982 Thread::resume_cond_->Broadcast(self); 983 } 984 985 VLOG(threads) << *self << " ResumeAllForDebugger complete"; 986 } 987 988 void ThreadList::UndoDebuggerSuspensions() { 989 Thread* self = Thread::Current(); 990 991 VLOG(threads) << *self << " UndoDebuggerSuspensions starting"; 992 993 { 994 MutexLock mu(self, *Locks::thread_list_lock_); 995 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 996 // Update global suspend all state for attaching threads. 997 suspend_all_count_ -= debug_suspend_all_count_; 998 debug_suspend_all_count_ = 0; 999 // Update running threads. 1000 for (const auto& thread : list_) { 1001 if (thread == self || thread->GetDebugSuspendCount() == 0) { 1002 continue; 1003 } 1004 thread->ModifySuspendCount(self, -thread->GetDebugSuspendCount(), true); 1005 } 1006 } 1007 1008 { 1009 MutexLock mu(self, *Locks::thread_suspend_count_lock_); 1010 Thread::resume_cond_->Broadcast(self); 1011 } 1012 1013 VLOG(threads) << "UndoDebuggerSuspensions(" << *self << ") complete"; 1014 } 1015 1016 void ThreadList::WaitForOtherNonDaemonThreadsToExit() { 1017 Thread* self = Thread::Current(); 1018 Locks::mutator_lock_->AssertNotHeld(self); 1019 while (true) { 1020 { 1021 // No more threads can be born after we start to shutdown. 1022 MutexLock mu(self, *Locks::runtime_shutdown_lock_); 1023 CHECK(Runtime::Current()->IsShuttingDownLocked()); 1024 CHECK_EQ(Runtime::Current()->NumberOfThreadsBeingBorn(), 0U); 1025 } 1026 MutexLock mu(self, *Locks::thread_list_lock_); 1027 // Also wait for any threads that are unregistering to finish. This is required so that no 1028 // threads access the thread list after it is deleted. TODO: This may not work for user daemon 1029 // threads since they could unregister at the wrong time. 1030 bool done = unregistering_count_ == 0; 1031 if (done) { 1032 for (const auto& thread : list_) { 1033 if (thread != self && !thread->IsDaemon()) { 1034 done = false; 1035 break; 1036 } 1037 } 1038 } 1039 if (done) { 1040 break; 1041 } 1042 // Wait for another thread to exit before re-checking. 1043 Locks::thread_exit_cond_->Wait(self); 1044 } 1045 } 1046 1047 void ThreadList::SuspendAllDaemonThreads() { 1048 Thread* self = Thread::Current(); 1049 MutexLock mu(self, *Locks::thread_list_lock_); 1050 { // Tell all the daemons it's time to suspend. 1051 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 1052 for (const auto& thread : list_) { 1053 // This is only run after all non-daemon threads have exited, so the remainder should all be 1054 // daemons. 1055 CHECK(thread->IsDaemon()) << *thread; 1056 if (thread != self) { 1057 thread->ModifySuspendCount(self, +1, false); 1058 } 1059 } 1060 } 1061 // Give the threads a chance to suspend, complaining if they're slow. 1062 bool have_complained = false; 1063 for (int i = 0; i < 10; ++i) { 1064 usleep(200 * 1000); 1065 bool all_suspended = true; 1066 for (const auto& thread : list_) { 1067 if (thread != self && thread->GetState() == kRunnable) { 1068 if (!have_complained) { 1069 LOG(WARNING) << "daemon thread not yet suspended: " << *thread; 1070 have_complained = true; 1071 } 1072 all_suspended = false; 1073 } 1074 } 1075 if (all_suspended) { 1076 return; 1077 } 1078 } 1079 LOG(ERROR) << "suspend all daemons failed"; 1080 } 1081 void ThreadList::Register(Thread* self) { 1082 DCHECK_EQ(self, Thread::Current()); 1083 1084 if (VLOG_IS_ON(threads)) { 1085 std::ostringstream oss; 1086 self->ShortDump(oss); // We don't hold the mutator_lock_ yet and so cannot call Dump. 1087 LOG(INFO) << "ThreadList::Register() " << *self << "\n" << oss.str(); 1088 } 1089 1090 // Atomically add self to the thread list and make its thread_suspend_count_ reflect ongoing 1091 // SuspendAll requests. 1092 MutexLock mu(self, *Locks::thread_list_lock_); 1093 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 1094 CHECK_GE(suspend_all_count_, debug_suspend_all_count_); 1095 // Modify suspend count in increments of 1 to maintain invariants in ModifySuspendCount. While 1096 // this isn't particularly efficient the suspend counts are most commonly 0 or 1. 1097 for (int delta = debug_suspend_all_count_; delta > 0; delta--) { 1098 self->ModifySuspendCount(self, +1, true); 1099 } 1100 for (int delta = suspend_all_count_ - debug_suspend_all_count_; delta > 0; delta--) { 1101 self->ModifySuspendCount(self, +1, false); 1102 } 1103 CHECK(!Contains(self)); 1104 list_.push_back(self); 1105 } 1106 1107 void ThreadList::Unregister(Thread* self) { 1108 DCHECK_EQ(self, Thread::Current()); 1109 CHECK_NE(self->GetState(), kRunnable); 1110 Locks::mutator_lock_->AssertNotHeld(self); 1111 1112 VLOG(threads) << "ThreadList::Unregister() " << *self; 1113 1114 { 1115 MutexLock mu(self, *Locks::thread_list_lock_); 1116 ++unregistering_count_; 1117 } 1118 1119 // Any time-consuming destruction, plus anything that can call back into managed code or 1120 // suspend and so on, must happen at this point, and not in ~Thread. The self->Destroy is what 1121 // causes the threads to join. It is important to do this after incrementing unregistering_count_ 1122 // since we want the runtime to wait for the daemon threads to exit before deleting the thread 1123 // list. 1124 self->Destroy(); 1125 1126 // If tracing, remember thread id and name before thread exits. 1127 Trace::StoreExitingThreadInfo(self); 1128 1129 uint32_t thin_lock_id = self->GetThreadId(); 1130 while (true) { 1131 // Remove and delete the Thread* while holding the thread_list_lock_ and 1132 // thread_suspend_count_lock_ so that the unregistering thread cannot be suspended. 1133 // Note: deliberately not using MutexLock that could hold a stale self pointer. 1134 MutexLock mu(self, *Locks::thread_list_lock_); 1135 if (!Contains(self)) { 1136 std::string thread_name; 1137 self->GetThreadName(thread_name); 1138 std::ostringstream os; 1139 DumpNativeStack(os, GetTid(), " native: ", nullptr); 1140 LOG(ERROR) << "Request to unregister unattached thread " << thread_name << "\n" << os.str(); 1141 break; 1142 } else { 1143 MutexLock mu2(self, *Locks::thread_suspend_count_lock_); 1144 if (!self->IsSuspended()) { 1145 list_.remove(self); 1146 break; 1147 } 1148 } 1149 // We failed to remove the thread due to a suspend request, loop and try again. 1150 } 1151 delete self; 1152 1153 // Release the thread ID after the thread is finished and deleted to avoid cases where we can 1154 // temporarily have multiple threads with the same thread id. When this occurs, it causes 1155 // problems in FindThreadByThreadId / SuspendThreadByThreadId. 1156 ReleaseThreadId(nullptr, thin_lock_id); 1157 1158 // Clear the TLS data, so that the underlying native thread is recognizably detached. 1159 // (It may wish to reattach later.) 1160 CHECK_PTHREAD_CALL(pthread_setspecific, (Thread::pthread_key_self_, nullptr), "detach self"); 1161 1162 // Signal that a thread just detached. 1163 MutexLock mu(nullptr, *Locks::thread_list_lock_); 1164 --unregistering_count_; 1165 Locks::thread_exit_cond_->Broadcast(nullptr); 1166 } 1167 1168 void ThreadList::ForEach(void (*callback)(Thread*, void*), void* context) { 1169 for (const auto& thread : list_) { 1170 callback(thread, context); 1171 } 1172 } 1173 1174 void ThreadList::VisitRoots(RootVisitor* visitor) const { 1175 MutexLock mu(Thread::Current(), *Locks::thread_list_lock_); 1176 for (const auto& thread : list_) { 1177 thread->VisitRoots(visitor); 1178 } 1179 } 1180 1181 uint32_t ThreadList::AllocThreadId(Thread* self) { 1182 MutexLock mu(self, *Locks::allocated_thread_ids_lock_); 1183 for (size_t i = 0; i < allocated_ids_.size(); ++i) { 1184 if (!allocated_ids_[i]) { 1185 allocated_ids_.set(i); 1186 return i + 1; // Zero is reserved to mean "invalid". 1187 } 1188 } 1189 LOG(FATAL) << "Out of internal thread ids"; 1190 return 0; 1191 } 1192 1193 void ThreadList::ReleaseThreadId(Thread* self, uint32_t id) { 1194 MutexLock mu(self, *Locks::allocated_thread_ids_lock_); 1195 --id; // Zero is reserved to mean "invalid". 1196 DCHECK(allocated_ids_[id]) << id; 1197 allocated_ids_.reset(id); 1198 } 1199 1200 } // namespace art 1201