mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-25 21:19:35 +01:00
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:
parent
4ccc7d3dcb
commit
613b3c59fc
1 changed files with 48 additions and 39 deletions
87
src/tq.rs
87
src/tq.rs
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue