Closed Bug 2045418 Opened 2 days ago Closed 1 day ago

IdleTaskRunner enters endless dispatch loop when timer creation fails during shutdown

Categories

(Core :: XPCOM, defect)

defect

Tracking

()

RESOLVED FIXED
153 Branch
Tracking Status
firefox-esr140 --- unaffected
firefox151 --- affected
firefox152 --- affected
firefox153 --- fixed

People

(Reporter: jstutte, Assigned: jstutte)

References

(Regression)

Details

(Keywords: regression)

Attachments

(1 file)

As seen in this endles log spam, we can end in an endless re-dispatch loop on the main thread during shutdown. Lesson: "very late shutdown edge cases that should not occur" will occur, actually.

Details:

Bug 2005474 fixed the MOZ_ASSERT(NS_SUCCEEDED(rv)) in IdleTaskRunner::ResetTimer by
mooting it with a shutdown-phase check, and correctly moved mTimerActive = true into the
success branch so a failed timer no longer marks itself as active.

However, the fix leaves an endless dispatch loop in place. When ResetTimer fails (timer
service has shut down), mTimerActive stays false. But Schedule() had already added an
IdleTaskRunnerTask to the TaskController before calling SetTimerInternal:

https://searchfox.org/firefox-main/rev/7ec900f9af2037fc305d1c555f9e96d5c1a45fe5/xpcom/threads/IdleTaskRunner.cpp#188-196

When that task fires Run(), it clears mTask = nullptr and calls Schedule() again.
Schedule() sees !mTask and enqueues another task — even though the timer will fail
again immediately. This repeats indefinitely while NS_ProcessPendingEvents drains the
main thread queue during ShutdownXPCOM, preventing it from ever returning.

Observed in CI: child process generated 1,114,617 NS_WARN_IF(NS_FAILED(rv)) warnings
at IdleTaskRunner.cpp:291 over 13 minutes before being killed by the parent with SIGABRT.
The process blocked shutdown for the entire duration.

Fix: Call Cancel() when the timer fails during shutdown, so the runner stops
re-enqueuing itself:

if (NS_WARN_IF(NS_FAILED(rv))) {
    MOZ_ASSERT(AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads));
    if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
        Cancel();
    }
} else {
    mTimerActive = true;
}

When timer creation fails in ResetTimer, mTimerActive stays false. The
IdleTaskRunnerTask previously added to the TaskController still fires,
calls Schedule(), sees !mTask, and enqueues another task — creating an
endless dispatch loop that prevents ShutdownXPCOM from draining the
event queue.

Fix by calling Cancel() when the timer fails and we are in or beyond
XPCOMShutdownThreads, which stops the runner from re-enqueuing itself.

Assignee: nobody → jstutte
Status: NEW → ASSIGNED

Set release status flags based on info from the regressing bug 2005474

Status: ASSIGNED → RESOLVED
Closed: 1 day ago
Resolution: --- → FIXED
Target Milestone: --- → 153 Branch
Blocks: 2045529
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: