| 557 | } |
| 558 | |
| 559 | std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout, bool& interrupt) |
| 560 | { |
| 561 | Assume(timeout >= 0ms); // No internal callers should use a negative timeout |
| 562 | if (timeout < 0ms) timeout = 0ms; |
| 563 | if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono |
| 564 | auto deadline{std::chrono::steady_clock::now() + timeout}; |
| 565 | { |
| 566 | WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock); |
| 567 | // For callers convenience, wait longer than the provided timeout |
| 568 | // during startup for the tip to be non-null. That way this function |
| 569 | // always returns valid tip information when possible and only |
| 570 | // returns null when shutting down, not when timing out. |
| 571 | kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) { |
| 572 | return kernel_notifications.TipBlock() || chainman.m_interrupt || interrupt; |
| 573 | }); |
| 574 | if (chainman.m_interrupt || interrupt) { |
| 575 | interrupt = false; |
| 576 | return {}; |
| 577 | } |
| 578 | // At this point TipBlock is set, so continue to wait until it is |
| 579 | // different then `current_tip` provided by caller. |
| 580 | kernel_notifications.m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) { |
| 581 | return Assume(kernel_notifications.TipBlock()) != current_tip || chainman.m_interrupt || interrupt; |
| 582 | }); |
| 583 | if (chainman.m_interrupt || interrupt) { |
| 584 | interrupt = false; |
| 585 | return {}; |
| 586 | } |
| 587 | } |
| 588 | |
| 589 | // Must release m_tip_block_mutex before getTip() locks cs_main, to |
| 590 | // avoid deadlocks. |
| 591 | return GetTip(chainman); |
| 592 | } |
| 593 | |
| 594 | } // namespace node |
no test coverage detected