diff --git a/Source/Task/TaskQueue.cpp b/Source/Task/TaskQueue.cpp index 252f8a21..59549581 100644 --- a/Source/Task/TaskQueue.cpp +++ b/Source/Task/TaskQueue.cpp @@ -1212,6 +1212,14 @@ bool TaskQueuePortImpl::ArmTimerForNextPendingDueTime( // must re-evaluate instead of resurrecting it. bool TaskQueuePortImpl::RearmTimerIfDueTimeUnchanged(uint64_t dueTime) { + // UINT64_MAX is the "nothing armed" sentinel and must never be programmed + // as a real deadline (see SubmitPendingCallbacks). Mirrors the guard in + // ArmTimerIfEarlier. + if (dueTime == UINT64_MAX) + { + return true; + } + while (true) { uint64_t currentDue = m_timerDue.load(); @@ -1402,6 +1410,17 @@ void TaskQueuePortImpl::SubmitPendingCallbacks() { uint64_t dueTime = m_timerDue.load(); + // UINT64_MAX is the "nothing armed" sentinel. It must never be programmed + // as a real deadline: WaitTimer::Start(UINT64_MAX) converts to a duration + // of -1 (before the steady_clock epoch), a perpetually-past deadline that + // fires immediately and re-arms the sentinel in an infinite loop, starving + // every real pending callback. If the timer is disarmed there is nothing + // to sweep, so return. + if (dueTime == UINT64_MAX) + { + return; + } + // Timer callbacks are advisory: a threadpool fire can arrive after // retargeting, or slightly before the steady-clock deadline due to // clock-source differences on Win32. If the deadline hasn't arrived,