src: run same-priority platform tasks in posting order - #65353
Open
codebytere wants to merge 1 commit into
Open
Conversation
TaskQueue became a std::priority_queue when worker tasks started to honor v8::TaskPriority. Its comparator returns false for entry types without a priority member, and for entries of equal priority, on the assumption that the heap then keeps insertion order. It does not: three tasks pushed A, B, C pop as A, C, B, and larger batches come out in heap order. That affects the per-isolate foreground task queue (tasks of one priority no longer run in the order they were posted), the foreground delayed task queue, and the delayed task scheduler of the worker thread task runner, whose local queue is drained in one batch: when v8 posts a delayed worker task shortly before the platform shuts down, the StopTask pushed by Stop() can run before a ScheduleTask that was pushed earlier, that ScheduleTask then starts a timer on the scheduler's loop after all timers were supposed to be stopped, and Shutdown() blocks in uv_thread_join() until the delay (e.g. the 8 s of the memory reducer) expires. Give every queued item a sequence number and use it as the tie breaker, so that tasks of equal priority, and tasks without one, come out in FIFO order again; higher priorities still come first. PopAll() now returns the tasks in that order instead of handing out the heap. Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #65353 +/- ##
==========================================
- Coverage 90.13% 90.12% -0.02%
==========================================
Files 752 752
Lines 251568 251816 +248
Branches 47270 47348 +78
==========================================
+ Hits 226759 226943 +184
- Misses 16168 16176 +8
- Partials 8641 8697 +56
🚀 New features to boost your workflow:
|
jasnell
reviewed
Aug 17, 2026
Comment on lines
+770
to
+771
| std::unique_ptr<T> task = | ||
| std::move(const_cast<Item&>(task_queue_.top()).task); |
Member
There was a problem hiding this comment.
Nit: The readability of this is... poor ;-) ... Might be better to split these lines up a bit.
jasnell
approved these changes
Aug 17, 2026
Collaborator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TaskQueue<T>has been astd::priority_queuesince #58047 so that worker tasks honorv8::TaskPriority. Itscomparator returns
falsefor entry types without aprioritymember and for equal priorities, and the comment expectsthat to keep insertion order. A binary heap doesn't: three tasks pushed A, B, C pop as A, C, B, and 64 pushes come back
out as 0, 2, 6, 14, 30, 62, ...
Three queues are affected: the per-isolate foreground queue (tasks of one priority no longer run in the order they were
posted), the foreground delayed queue, and the worker runner's
DelayedTaskScheduler, where it can hang shutdown. Thatscheduler drains its local queue in one batch, so when V8 posts a delayed worker task shortly before the platform shuts
down, the
StopTaskpushed byStop()can run before aScheduleTaskthat was pushed earlier; theScheduleTaskthenstarts a timer on the scheduler's loop after all timers were stopped, and
Shutdown()sits inuv_thread_join()untilthe delay expires (8 s when the late task is the memory reducer). It shows up as an intermittent multi-second exit stall
in processes that exit soon after doing some work.
This is the other half of the shutdown race #61999 addressed: that change makes
PostDelayedTask()return early onceStop()has run (both under thetasks_lock), so everyScheduleTaskthat is queued was queued before theStopTask;with posting order restored it also runs before it, and no further flag is needed.
The fix gives every queued item a sequence number and uses it as the tie breaker, so equal-priority and priority-less
tasks come out FIFO again while higher priorities still go first;
PopAll()returns the tasks in that order instead ofhanding out the heap, which also removes the
const_castloops at its three call sites.Tests: new cctest (
TaskQueueTest.HigherPriorityFirstThenPostingOrder: FIFO acrossPopAll()/Pop()for apriority-less queue, priority-then-FIFO for
TaskQueueEntry) fails onmainand passes here; cctest and the defaultsuite pass.
Refs: #58047
Refs: #61999
Disclosure: the code, test and this description were written by Claude Code, directed and reviewed by @codebytere.