| 516 | } |
| 517 | |
| 518 | Status ThreadJoiner::Join() { |
| 519 | if (Thread::current_thread() && |
| 520 | Thread::current_thread()->tid() == thread_->tid()) { |
| 521 | return Status::InvalidArgument("Can't join on own thread", thread_->name_); |
| 522 | } |
| 523 | |
| 524 | // Early exit: double join is a no-op. |
| 525 | if (!thread_->joinable_) { |
| 526 | return Status::OK(); |
| 527 | } |
| 528 | |
| 529 | int waited_ms = 0; |
| 530 | bool keep_trying = true; |
| 531 | while (keep_trying) { |
| 532 | if (waited_ms >= warn_after_ms_) { |
| 533 | LOG(WARNING) << Substitute("Waited for $0ms trying to join with $1 (tid $2)", |
| 534 | waited_ms, thread_->name_, thread_->tid_); |
| 535 | } |
| 536 | |
| 537 | int remaining_before_giveup = MathLimits<int>::kMax; |
| 538 | if (give_up_after_ms_ != -1) { |
| 539 | remaining_before_giveup = give_up_after_ms_ - waited_ms; |
| 540 | } |
| 541 | |
| 542 | int remaining_before_next_warn = warn_every_ms_; |
| 543 | if (waited_ms < warn_after_ms_) { |
| 544 | remaining_before_next_warn = warn_after_ms_ - waited_ms; |
| 545 | } |
| 546 | |
| 547 | if (remaining_before_giveup < remaining_before_next_warn) { |
| 548 | keep_trying = false; |
| 549 | } |
| 550 | |
| 551 | int wait_for = std::min(remaining_before_giveup, remaining_before_next_warn); |
| 552 | |
| 553 | if (thread_->done_.WaitFor(MonoDelta::FromMilliseconds(wait_for))) { |
| 554 | // Unconditionally join before returning, to guarantee that any TLS |
| 555 | // has been destroyed (pthread_key_create() destructors only run |
| 556 | // after a pthread's user method has returned). |
| 557 | int ret = pthread_join(thread_->thread_, nullptr); |
| 558 | CHECK_EQ(ret, 0); |
| 559 | thread_->joinable_ = false; |
| 560 | return Status::OK(); |
| 561 | } |
| 562 | waited_ms += wait_for; |
| 563 | } |
| 564 | return Status::Aborted(strings::Substitute("Timed out after $0ms joining on $1", |
| 565 | waited_ms, thread_->name_)); |
| 566 | } |
| 567 | |
| 568 | Thread::~Thread() { |
| 569 | if (joinable_) { |