src: run same-priority platform tasks in posting order · nodejs/node@340b983 · GitHub
Skip to content

Commit 340b983

Browse files
codebytereaduh95
authored andcommitted
src: run same-priority platform tasks in posting order
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> PR-URL: #65353 Refs: #58047 Refs: #61999 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 2de845b commit 340b983

3 files changed

Lines changed: 103 additions & 60 deletions

File tree

src/node_platform.cc

Lines changed: 29 additions & 43 deletions

src/node_platform.h

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,6 @@ concept has_priority = requires(T t) { t.priority; };
2727
template <class T>
2828
class TaskQueue {
2929
public:
30-
// If the entry type has a priority member, order the priority queue by
31-
// that - higher priority first. Otherwise, maintain insertion order.
32-
struct EntryCompare {
33-
bool operator()(const std::unique_ptr<T>& a,
34-
const std::unique_ptr<T>& b) const {
35-
if constexpr (has_priority<T>) {
36-
return a->priority < b->priority;
37-
} else {
38-
return false;
39-
}
40-
}
41-
};
42-
43-
using PriorityQueue = std::priority_queue<std::unique_ptr<T>,
44-
std::vector<std::unique_ptr<T>>,
45-
EntryCompare>;
4630
class Locked {
4731
public:
4832
void Push(std::unique_ptr<T> task, bool outstanding = false);
@@ -51,7 +35,8 @@ class TaskQueue {
5135
void NotifyOfOutstandingCompletion();
5236
void BlockingDrain();
5337
void Stop();
54-
PriorityQueue PopAll();
38+
// All queued tasks, in the order Pop() would have returned them.
39+
std::vector<std::unique_ptr<T>> PopAll();
5540

5641
private:
5742
friend class TaskQueue;
@@ -67,11 +52,33 @@ class TaskQueue {
6752
Locked Lock() { return Locked(this); }
6853

6954
private:
55+
struct Item {
56+
std::unique_ptr<T> task;
57+
uint64_t sequence;
58+
};
59+
// Higher priority first if the entry type has one; posting order otherwise
60+
// and among equal priorities (a sequence number breaks the tie).
61+
struct ItemCompare {
62+
bool operator()(const Item& a, const Item& b) const {
63+
if constexpr (has_priority<T>) {
64+
if (a.task->priority != b.task->priority) {
65+
return a.task->priority < b.task->priority;
66+
}
67+
}
68+
return a.sequence > b.sequence;
69+
}
70+
};
71+
using PriorityQueue =
72+
std::priority_queue<Item, std::vector<Item>, ItemCompare>;
73+
74+
std::unique_ptr<T> PopTask();
75+
7076
Mutex lock_;
7177
ConditionVariable tasks_available_;
7278
ConditionVariable outstanding_tasks_drained_;
7379
int outstanding_tasks_;
7480
bool stopped_;
81+
uint64_t next_sequence_ = 0;
7582
PriorityQueue task_queue_;
7683
};
7784

test/cctest/test_platform.cc

Lines changed: 50 additions & 0 deletions

0 commit comments

Comments
 (0)