Fixed a bug in the timer queue

When a waker was dequeued, and it had already exipired, the dequeue
was not re-run to set a proper new compare match for the monotonic.
This is now fixed.
This commit is contained in:
Emil Fresk 2022-10-08 20:40:45 +02:00
parent 4ccc7d3dcb
commit 613b3c59fc

View file

@ -136,8 +136,7 @@ where
instant: Mono::Instant, instant: Mono::Instant,
mono: &mut Mono, mono: &mut Mono,
) -> Option<(Task, u8)> { ) -> Option<(Task, u8)> {
let now = mono.now(); if instant <= mono.now() {
if instant <= now {
// task became ready // task became ready
let nr = unsafe { self.task_queue.pop_unchecked() }; let nr = unsafe { self.task_queue.pop_unchecked() };
Some((nr.task, nr.index)) Some((nr.task, nr.index))
@ -149,7 +148,7 @@ where
// dequeue. If the monotonic is fast enough it can happen that from the // dequeue. If the monotonic is fast enough it can happen that from the
// read of now to the set of the compare, the time can overflow. This is to // read of now to the set of the compare, the time can overflow. This is to
// guard against this. // guard against this.
if instant <= now { if instant <= mono.now() {
let nr = unsafe { self.task_queue.pop_unchecked() }; let nr = unsafe { self.task_queue.pop_unchecked() };
Some((nr.task, nr.index)) Some((nr.task, nr.index))
} else { } else {
@ -158,12 +157,15 @@ where
} }
} }
fn dequeue_waker_queue(&mut self, instant: Mono::Instant, mono: &mut Mono) { fn dequeue_waker_queue(&mut self, instant: Mono::Instant, mono: &mut Mono) -> bool {
let now = mono.now(); let mut did_wake = false;
if instant <= now {
if instant <= mono.now() {
// Task became ready, wake the waker // Task became ready, wake the waker
if let Some(v) = self.waker_queue.pop() { if let Some(v) = self.waker_queue.pop() {
v.val.waker.wake_by_ref() v.val.waker.wake_by_ref();
did_wake = true;
} }
} else { } else {
// Set compare // Set compare
@ -173,12 +175,16 @@ where
// dequeue. If the monotonic is fast enough it can happen that from the // dequeue. If the monotonic is fast enough it can happen that from the
// read of now to the set of the compare, the time can overflow. This is to // read of now to the set of the compare, the time can overflow. This is to
// guard against this. // guard against this.
if instant <= now { if instant <= mono.now() {
if let Some(v) = self.waker_queue.pop() { if let Some(v) = self.waker_queue.pop() {
v.val.waker.wake_by_ref() v.val.waker.wake_by_ref();
did_wake = true;
} }
} }
} }
did_wake
} }
/// Dequeue a task from the ``TimerQueue`` /// Dequeue a task from the ``TimerQueue``
@ -188,46 +194,49 @@ where
{ {
mono.clear_compare_flag(); mono.clear_compare_flag();
let tq = self.task_queue.peek().map(|p| p.instant); loop {
let wq = self.waker_queue.peek().map(|p| p.instant); let tq = self.task_queue.peek().map(|p| p.instant);
let wq = self.waker_queue.peek().map(|p| p.instant);
let dequeue_task; let dequeue_task;
let instant; let instant;
match (tq, wq) { match (tq, wq) {
(Some(tq_instant), Some(wq_instant)) => { (Some(tq_instant), Some(wq_instant)) => {
if tq_instant <= wq_instant { if tq_instant <= wq_instant {
dequeue_task = true;
instant = tq_instant;
} else {
dequeue_task = false;
instant = wq_instant;
}
}
(Some(tq_instant), None) => {
dequeue_task = true; dequeue_task = true;
instant = tq_instant; instant = tq_instant;
} else { }
(None, Some(wq_instant)) => {
dequeue_task = false; dequeue_task = false;
instant = wq_instant; instant = wq_instant;
} }
} (None, None) => {
(Some(tq_instant), None) => { // The queue is empty, disable the interrupt.
dequeue_task = true; if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
instant = tq_instant; disable_interrupt();
} mono.disable_timer();
(None, Some(wq_instant)) => { }
dequeue_task = false;
instant = wq_instant; return None;
}
(None, None) => {
// The queue is empty, disable the interrupt.
if Mono::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
disable_interrupt();
mono.disable_timer();
} }
return None;
} }
}
if dequeue_task { if dequeue_task {
self.dequeue_task_queue(instant, mono) return self.dequeue_task_queue(instant, mono);
} else { } else if !self.dequeue_waker_queue(instant, mono) {
self.dequeue_waker_queue(instant, mono); return None;
None } else {
// Run the dequeue again
}
} }
} }
} }