Skip to content

Commit

Permalink
Provide a common implementation for global queues
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Dec 8, 2024
1 parent 76135a8 commit 9e23362
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 300 deletions.
1 change: 0 additions & 1 deletion ci-xtensa.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ cargo batch \
--- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \
--- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,mock-driver \
--- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-const-generic \
--- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
--- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
Expand Down
1 change: 0 additions & 1 deletion ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ cargo batch \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \
--- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-const-generic \
--- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
Expand Down
2 changes: 1 addition & 1 deletion embassy-executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ nightly = ["embassy-executor-macros/nightly"]
turbowakers = []

## Use the executor-integrated `embassy-time` timer queue.
integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"]
integrated-timers = ["dep:embassy-time-driver"]

#! ### Architecture
_arch = [] # some arch was picked
Expand Down
59 changes: 5 additions & 54 deletions embassy-nrf/src/time_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use critical_section::CriticalSection;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
use embassy_time_driver::Driver;
use embassy_time_queue_driver::GlobalTimerQueue;

use crate::interrupt::InterruptExt;
use crate::{interrupt, pac};
Expand Down Expand Up @@ -277,57 +278,7 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
DRIVER.init(irq_prio)
}

#[cfg(feature = "integrated-timers")]
type RawQueue = embassy_executor::raw::timer_queue::TimerQueue;

#[cfg(not(feature = "integrated-timers"))]
type RawQueue = embassy_time_queue_driver::queue_generic::RefCellQueue;

struct TimerQueueDriver {
inner: Mutex<RawQueue>,
}

embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE_DRIVER: TimerQueueDriver = TimerQueueDriver::new());

impl embassy_time_queue_driver::TimerQueue for TimerQueueDriver {
fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) {
#[cfg(feature = "integrated-timers")]
let waker = embassy_executor::raw::task_from_waker(waker);
self.inner.lock(|q| {
if q.schedule_wake(at, waker) {
self.dispatch();
}
});
}
}

impl TimerQueueDriver {
const fn new() -> Self {
Self {
inner: Mutex::new(RawQueue::new()),
}
}

pub fn dispatch(&self) {
let now = DRIVER.now();
let next_expiration = self.inner.lock(|q| dequeue(q, now));
self.arm_alarm(next_expiration);
}

fn arm_alarm(&self, mut next_expiration: u64) {
while !DRIVER.set_alarm(next_expiration) {
// next_expiration is in the past, dequeue and find a new expiration
next_expiration = self.inner.lock(|q| dequeue(q, next_expiration));
}
}
}

fn dequeue(q: &RawQueue, now: u64) -> u64 {
#[cfg(feature = "integrated-timers")]
let next = unsafe { q.next_expiration(now, embassy_executor::raw::wake_task) };

#[cfg(not(feature = "integrated-timers"))]
let next = q.next_expiration(now);

next
}
embassy_time_queue_driver::timer_queue_impl!(
static TIMER_QUEUE_DRIVER: GlobalTimerQueue
= GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
);
59 changes: 5 additions & 54 deletions embassy-rp/src/time_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use core::cell::Cell;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex;
use embassy_time_driver::Driver;
use embassy_time_queue_driver::GlobalTimerQueue;
#[cfg(feature = "rp2040")]
use pac::TIMER;
#[cfg(feature = "_rp235x")]
Expand Down Expand Up @@ -125,57 +126,7 @@ fn TIMER0_IRQ_0() {
DRIVER.check_alarm()
}

#[cfg(feature = "integrated-timers")]
type RawQueue = embassy_executor::raw::timer_queue::TimerQueue;

#[cfg(not(feature = "integrated-timers"))]
type RawQueue = embassy_time_queue_driver::queue_generic::RefCellQueue;

struct TimerQueueDriver {
inner: Mutex<CriticalSectionRawMutex, RawQueue>,
}

embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE_DRIVER: TimerQueueDriver = TimerQueueDriver::new());

impl embassy_time_queue_driver::TimerQueue for TimerQueueDriver {
fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) {
#[cfg(feature = "integrated-timers")]
let waker = embassy_executor::raw::task_from_waker(waker);
self.inner.lock(|q| {
if q.schedule_wake(at, waker) {
self.dispatch();
}
});
}
}

impl TimerQueueDriver {
const fn new() -> Self {
Self {
inner: Mutex::new(RawQueue::new()),
}
}

pub fn dispatch(&self) {
let now = DRIVER.now();
let next_expiration = self.inner.lock(|q| dequeue(q, now));
self.arm_alarm(next_expiration);
}

fn arm_alarm(&self, mut next_expiration: u64) {
while !DRIVER.set_alarm(next_expiration) {
// next_expiration is in the past, dequeue and find a new expiration
next_expiration = self.inner.lock(|q| dequeue(q, next_expiration));
}
}
}

fn dequeue(q: &RawQueue, now: u64) -> u64 {
#[cfg(feature = "integrated-timers")]
let next = unsafe { q.next_expiration(now, embassy_executor::raw::wake_task) };

#[cfg(not(feature = "integrated-timers"))]
let next = q.next_expiration(now);

next
}
embassy_time_queue_driver::timer_queue_impl!(
static TIMER_QUEUE_DRIVER: GlobalTimerQueue
= GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
);
71 changes: 5 additions & 66 deletions embassy-stm32/src/time_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use critical_section::CriticalSection;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex;
use embassy_time_driver::{Driver, TICK_HZ};
use embassy_time_queue_driver::GlobalTimerQueue;
use stm32_metapac::timer::{regs, TimGp16};

use crate::interrupt::typelevel::Interrupt;
Expand All @@ -23,18 +24,6 @@ use crate::{interrupt, peripherals};
// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST
// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not
// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.)
//
// The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number
// available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers:
// CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3.

//cfg_if::cfg_if! {
// if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] {
// const ALARM_COUNT: usize = 1;
// } else {
// const ALARM_COUNT: usize = 3;
// }
//}

#[cfg(time_driver_tim1)]
type T = peripherals::TIM1;
Expand Down Expand Up @@ -518,57 +507,7 @@ pub(crate) fn init(cs: CriticalSection) {
DRIVER.init(cs)
}

#[cfg(feature = "integrated-timers")]
type RawQueue = embassy_executor::raw::timer_queue::TimerQueue;

#[cfg(not(feature = "integrated-timers"))]
type RawQueue = embassy_time_queue_driver::queue_generic::RefCellQueue;

struct TimerQueueDriver {
inner: Mutex<CriticalSectionRawMutex, RawQueue>,
}

embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE_DRIVER: TimerQueueDriver = TimerQueueDriver::new());

impl embassy_time_queue_driver::TimerQueue for TimerQueueDriver {
fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) {
#[cfg(feature = "integrated-timers")]
let waker = embassy_executor::raw::task_from_waker(waker);
self.inner.lock(|q| {
if q.schedule_wake(at, waker) {
self.dispatch();
}
});
}
}

impl TimerQueueDriver {
const fn new() -> Self {
Self {
inner: Mutex::new(RawQueue::new()),
}
}

pub fn dispatch(&self) {
let now = DRIVER.now();
let next_expiration = self.inner.lock(|q| dequeue(q, now));
self.arm_alarm(next_expiration);
}

fn arm_alarm(&self, mut next_expiration: u64) {
while !DRIVER.set_alarm(next_expiration) {
// next_expiration is in the past, dequeue and find a new expiration
next_expiration = self.inner.lock(|q| dequeue(q, next_expiration));
}
}
}

fn dequeue(q: &RawQueue, now: u64) -> u64 {
#[cfg(feature = "integrated-timers")]
let next = unsafe { q.next_expiration(now, embassy_executor::raw::wake_task) };

#[cfg(not(feature = "integrated-timers"))]
let next = q.next_expiration(now);

next
}
embassy_time_queue_driver::timer_queue_impl!(
static TIMER_QUEUE_DRIVER: GlobalTimerQueue
= GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
);
20 changes: 13 additions & 7 deletions embassy-time-queue-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@ categories = [
links = "embassy-time-queue"

[dependencies]
critical-section = "1.2.0"
heapless = "0.8"
embassy-executor = { version = "0.6.3", path = "../embassy-executor", optional = true }
embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" }

[features]
#! ### Generic Queue

## Create a global, generic queue that can be used with any executor.
## Use the executor-integrated `embassy-time` timer queue. The timer items are stored inside
## the task headers, so you do not need to set a capacity for the queue.
## To use this you must have a time driver provided.
generic-queue = []
##
## If this feature is not enabled, a generic queue is available with a configurable capacity.
integrated-timers = ["embassy-executor/integrated-timers"]

#! The following features set how many timers are used for the generic queue. At most one
#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used.
Expand All @@ -37,15 +43,15 @@ generic-queue = []
#! end user to pick.

## Generic Queue with 8 timers
generic-queue-8 = ["generic-queue"]
generic-queue-8 = []
## Generic Queue with 16 timers
generic-queue-16 = ["generic-queue"]
generic-queue-16 = []
## Generic Queue with 32 timers
generic-queue-32 = ["generic-queue"]
generic-queue-32 = []
## Generic Queue with 64 timers
generic-queue-64 = ["generic-queue"]
generic-queue-64 = []
## Generic Queue with 128 timers
generic-queue-128 = ["generic-queue"]
generic-queue-128 = []

[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/"
Expand Down
Loading

0 comments on commit 9e23362

Please sign in to comment.