Update embassy-std to new executor api

This commit is contained in:
Dario Nieuwenhuis 2021-02-03 04:30:11 +01:00
parent edca627286
commit 4192e52629
4 changed files with 103 additions and 69 deletions

2
.gitignore vendored
View file

@ -1,3 +1,3 @@
/target target
Cargo.lock Cargo.lock
third_party third_party

View file

@ -1,9 +1,10 @@
use embassy::executor::Executor; use embassy::executor::{raw, Spawner};
use embassy::time::TICKS_PER_SECOND; use embassy::time::TICKS_PER_SECOND;
use embassy::time::{Alarm, Clock}; use embassy::time::{Alarm, Clock};
use embassy::util::Forever;
use rand_core::{OsRng, RngCore}; use rand_core::{OsRng, RngCore};
use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::ptr;
use std::sync::{Condvar, Mutex}; use std::sync::{Condvar, Mutex};
use std::time::{Duration as StdDuration, Instant as StdInstant}; use std::time::{Duration as StdDuration, Instant as StdInstant};
@ -29,7 +30,8 @@ static mut ALARM_AT: u64 = u64::MAX;
pub struct StdAlarm; pub struct StdAlarm;
impl Alarm for StdAlarm { impl Alarm for StdAlarm {
fn set_callback(&self, _callback: fn()) {} fn set_callback(&self, _callback: fn(*mut ()), _ctx: *mut ()) {}
fn set(&self, timestamp: u64) { fn set(&self, timestamp: u64) {
unsafe { ALARM_AT = timestamp } unsafe { ALARM_AT = timestamp }
} }
@ -39,57 +41,91 @@ impl Alarm for StdAlarm {
} }
} }
static EXECUTOR: Forever<Executor> = Forever::new(); struct Signaler {
mutex: Mutex<bool>,
lazy_static::lazy_static! { condvar: Condvar,
static ref MUTEX: Mutex<bool> = Mutex::new(false);
static ref CONDVAR: Condvar = Condvar::new();
} }
pub fn init() -> &'static Executor { impl Signaler {
unsafe { fn new() -> Self {
CLOCK_ZERO.as_mut_ptr().write(StdInstant::now()); Self {
embassy::time::set_clock(&StdClock); mutex: Mutex::new(false),
embassy::rand::set_rand(&StdRand); condvar: Condvar::new(),
}
}
EXECUTOR.put(Executor::new_with_alarm(&StdAlarm, || { fn wait(&self) {
let mut signaled = MUTEX.lock().unwrap(); let mut signaled = self.mutex.lock().unwrap();
*signaled = true; while !*signaled {
CONDVAR.notify_one(); let alarm_at = unsafe { ALARM_AT };
})) if alarm_at == u64::MAX {
signaled = self.condvar.wait(signaled).unwrap();
} else {
let now = StdClock.now();
if now >= alarm_at {
break;
}
let left = alarm_at - now;
let dur = StdDuration::new(
left / (TICKS_PER_SECOND as u64),
(left % (TICKS_PER_SECOND as u64) * 1_000_000_000 / (TICKS_PER_SECOND as u64))
as u32,
);
let (signaled2, timeout) = self.condvar.wait_timeout(signaled, dur).unwrap();
signaled = signaled2;
if timeout.timed_out() {
break;
}
}
}
*signaled = false;
}
fn signal(ctx: *mut ()) {
let this = unsafe { &*(ctx as *mut Self) };
let mut signaled = this.mutex.lock().unwrap();
*signaled = true;
this.condvar.notify_one();
} }
} }
pub fn run(executor: &'static Executor) -> ! { pub struct Executor {
unsafe { inner: raw::Executor,
not_send: PhantomData<*mut ()>,
signaler: Signaler,
}
impl Executor {
pub fn new() -> Self {
unsafe {
CLOCK_ZERO.as_mut_ptr().write(StdInstant::now());
embassy::time::set_clock(&StdClock);
embassy::rand::set_rand(&StdRand);
}
Self {
inner: raw::Executor::new(Signaler::signal, ptr::null_mut()),
not_send: PhantomData,
signaler: Signaler::new(),
}
}
pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) {
self.inner.set_alarm(alarm);
}
/// Runs the executor.
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
self.inner.set_signal_ctx(&self.signaler as *const _ as _);
init(unsafe { self.inner.spawner() });
loop { loop {
executor.run(); unsafe { self.inner.run_queued() };
self.signaler.wait();
let mut signaled = MUTEX.lock().unwrap();
while !*signaled {
let alarm_at = ALARM_AT;
if alarm_at == u64::MAX {
signaled = CONDVAR.wait(signaled).unwrap();
} else {
let now = StdClock.now();
if now >= alarm_at {
break;
}
let left = alarm_at - now;
let dur = StdDuration::new(
left / (TICKS_PER_SECOND as u64),
(left % (TICKS_PER_SECOND as u64) * 1_000_000_000
/ (TICKS_PER_SECOND as u64)) as u32,
);
let (signaled2, timeout) = CONDVAR.wait_timeout(signaled, dur).unwrap();
signaled = signaled2;
if timeout.timed_out() {
break;
}
}
}
*signaled = false;
} }
} }
} }

View file

@ -113,13 +113,6 @@ pub struct Spawner {
} }
impl Spawner { impl Spawner {
fn new(executor: &'static raw::Executor) -> Self {
Self {
executor,
not_send: PhantomData,
}
}
pub fn spawn<F>(&self, token: SpawnToken<F>) -> Result<(), SpawnError> { pub fn spawn<F>(&self, token: SpawnToken<F>) -> Result<(), SpawnError> {
let task = token.raw_task; let task = token.raw_task;
mem::forget(token); mem::forget(token);
@ -165,13 +158,6 @@ unsafe impl Sync for SendSpawner {}
/// ///
/// If you want to spawn tasks from another thread, use [SendSpawner]. /// If you want to spawn tasks from another thread, use [SendSpawner].
impl SendSpawner { impl SendSpawner {
fn new(executor: &'static raw::Executor) -> Self {
Self {
executor,
not_send: PhantomData,
}
}
pub fn spawn<F: Send>(&self, token: SpawnToken<F>) -> Result<(), SpawnError> { pub fn spawn<F: Send>(&self, token: SpawnToken<F>) -> Result<(), SpawnError> {
let header = token.raw_task; let header = token.raw_task;
mem::forget(token); mem::forget(token);
@ -207,7 +193,7 @@ impl Executor {
/// ///
/// This function never returns. /// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(Spawner::new(&self.inner)); init(unsafe { self.inner.spawner() });
loop { loop {
unsafe { self.inner.run_queued() }; unsafe { self.inner.run_queued() };
@ -253,7 +239,7 @@ impl<I: OwnedInterrupt> IrqExecutor<I> {
pub fn start(&'static mut self, init: impl FnOnce(Spawner) + Send) { pub fn start(&'static mut self, init: impl FnOnce(Spawner) + Send) {
self.irq.disable(); self.irq.disable();
init(Spawner::new(&self.inner)); init(unsafe { self.inner.spawner() });
self.irq.set_handler( self.irq.set_handler(
|ctx| unsafe { |ctx| unsafe {

View file

@ -1,5 +1,6 @@
use core::cell::Cell; use core::cell::Cell;
use core::cmp::min; use core::cmp::min;
use core::marker::PhantomData;
use core::ptr; use core::ptr;
use core::ptr::NonNull; use core::ptr::NonNull;
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
@ -67,7 +68,7 @@ impl Task {
} }
} }
pub(crate) struct Executor { pub struct Executor {
run_queue: RunQueue, run_queue: RunQueue,
timer_queue: TimerQueue, timer_queue: TimerQueue,
signal_fn: fn(*mut ()), signal_fn: fn(*mut ()),
@ -76,7 +77,7 @@ pub(crate) struct Executor {
} }
impl Executor { impl Executor {
pub(crate) const fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { pub const fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
Self { Self {
run_queue: RunQueue::new(), run_queue: RunQueue::new(),
timer_queue: TimerQueue::new(), timer_queue: TimerQueue::new(),
@ -86,23 +87,27 @@ impl Executor {
} }
} }
pub(crate) fn set_alarm(&mut self, alarm: &'static dyn Alarm) { pub fn set_alarm(&mut self, alarm: &'static dyn Alarm) {
self.alarm = Some(alarm); self.alarm = Some(alarm);
} }
pub fn set_signal_ctx(&mut self, signal_ctx: *mut ()) {
self.signal_ctx = signal_ctx;
}
unsafe fn enqueue(&self, item: *mut Task) { unsafe fn enqueue(&self, item: *mut Task) {
if self.run_queue.enqueue(item) { if self.run_queue.enqueue(item) {
(self.signal_fn)(self.signal_ctx) (self.signal_fn)(self.signal_ctx)
} }
} }
pub(crate) unsafe fn spawn(&'static self, task: NonNull<Task>) { pub unsafe fn spawn(&'static self, task: NonNull<Task>) {
let task = task.as_ref(); let task = task.as_ref();
task.executor.set(self); task.executor.set(self);
self.enqueue(task as *const _ as _); self.enqueue(task as *const _ as _);
} }
pub(crate) unsafe fn run_queued(&self) { pub unsafe fn run_queued(&'static self) {
if self.alarm.is_some() { if self.alarm.is_some() {
self.timer_queue.dequeue_expired(Instant::now(), |p| { self.timer_queue.dequeue_expired(Instant::now(), |p| {
p.as_ref().enqueue(); p.as_ref().enqueue();
@ -138,6 +143,13 @@ impl Executor {
alarm.set(next_expiration.as_ticks()); alarm.set(next_expiration.as_ticks());
} }
} }
pub unsafe fn spawner(&'static self) -> super::Spawner {
super::Spawner {
executor: self,
not_send: PhantomData,
}
}
} }
pub use super::waker::task_from_waker; pub use super::waker::task_from_waker;