mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibCore: Make timer firing order stable for equal deadlines
Timers scheduled with identical `fire_time` could fire out of order because the heap is not stable. This change assigns a monotonically increasing `sequence_id` when a timer is scheduled and extend the heap comparator to order by (`fire_time`, `sequence_id`). This guarantees FIFO among timers with the same deadline. This matches the HTML "run steps after a timeout" ordering requirement: older invocations with <= delay complete before newer ones. https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout
This commit is contained in:
parent
1d41cf10f4
commit
de3f32a5c9
|
|
@ -70,6 +70,9 @@ public:
|
|||
|
||||
bool is_scheduled() const { return m_index != INVALID_INDEX; }
|
||||
|
||||
void set_sequence_id(u64 id) { m_sequence_id = id; }
|
||||
u64 sequence_id() const { return m_sequence_id; }
|
||||
|
||||
protected:
|
||||
union {
|
||||
AK::Duration m_duration;
|
||||
|
|
@ -78,6 +81,7 @@ protected:
|
|||
|
||||
private:
|
||||
ssize_t m_index = INVALID_INDEX;
|
||||
u64 m_sequence_id { 0 };
|
||||
};
|
||||
|
||||
class TimeoutSet {
|
||||
|
|
@ -122,12 +126,14 @@ public:
|
|||
|
||||
void schedule_relative(EventLoopTimeout* timeout)
|
||||
{
|
||||
timeout->set_sequence_id(m_next_sequence_id++);
|
||||
timeout->set_index({}, -1 - static_cast<ssize_t>(m_scheduled_timeouts.size()));
|
||||
m_scheduled_timeouts.append(timeout);
|
||||
}
|
||||
|
||||
void schedule_absolute(EventLoopTimeout* timeout)
|
||||
{
|
||||
timeout->set_sequence_id(m_next_sequence_id++);
|
||||
m_heap.insert(timeout);
|
||||
}
|
||||
|
||||
|
|
@ -160,6 +166,8 @@ private:
|
|||
IntrusiveBinaryHeap<
|
||||
EventLoopTimeout*,
|
||||
decltype([](EventLoopTimeout* a, EventLoopTimeout* b) {
|
||||
if (a->fire_time() == b->fire_time())
|
||||
return a->sequence_id() < b->sequence_id();
|
||||
return a->fire_time() < b->fire_time();
|
||||
}),
|
||||
decltype([](EventLoopTimeout* timeout, size_t index) {
|
||||
|
|
@ -168,6 +176,7 @@ private:
|
|||
8>
|
||||
m_heap;
|
||||
Vector<EventLoopTimeout*, 8> m_scheduled_timeouts;
|
||||
u64 m_next_sequence_id { 0 };
|
||||
};
|
||||
|
||||
class EventLoopTimer final : public EventLoopTimeout {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
13
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
20
|
||||
21
|
||||
22
|
||||
23
|
||||
24
|
||||
25
|
||||
26
|
||||
27
|
||||
28
|
||||
29
|
||||
30
|
||||
31
|
||||
32
|
||||
33
|
||||
34
|
||||
35
|
||||
36
|
||||
37
|
||||
38
|
||||
39
|
||||
40
|
||||
41
|
||||
42
|
||||
43
|
||||
44
|
||||
45
|
||||
46
|
||||
47
|
||||
48
|
||||
49
|
||||
50
|
||||
51
|
||||
52
|
||||
53
|
||||
54
|
||||
55
|
||||
56
|
||||
57
|
||||
58
|
||||
59
|
||||
60
|
||||
61
|
||||
62
|
||||
63
|
||||
64
|
||||
65
|
||||
66
|
||||
67
|
||||
68
|
||||
69
|
||||
70
|
||||
71
|
||||
72
|
||||
73
|
||||
74
|
||||
75
|
||||
76
|
||||
77
|
||||
78
|
||||
79
|
||||
80
|
||||
81
|
||||
82
|
||||
83
|
||||
84
|
||||
85
|
||||
86
|
||||
87
|
||||
88
|
||||
89
|
||||
90
|
||||
91
|
||||
92
|
||||
93
|
||||
94
|
||||
95
|
||||
96
|
||||
97
|
||||
98
|
||||
99
|
||||
100
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="include.js"></script>
|
||||
<script>
|
||||
asyncTest(done => {
|
||||
let invocation = 0;
|
||||
function makeTimeout() {
|
||||
const count = ++invocation;
|
||||
setTimeout(() => {
|
||||
println(count);
|
||||
if (count === 100)
|
||||
done();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
makeTimeout();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in New Issue
Block a user