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
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::{Alarm, Clock};
use embassy::util::Forever;
use rand_core::{OsRng, RngCore};
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::{Condvar, Mutex};
use std::time::{Duration as StdDuration, Instant as StdInstant};
@ -29,7 +30,8 @@ static mut ALARM_AT: u64 = u64::MAX;
pub struct 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) {
unsafe { ALARM_AT = timestamp }
}
@ -39,57 +41,91 @@ impl Alarm for StdAlarm {
}
}
static EXECUTOR: Forever<Executor> = Forever::new();
lazy_static::lazy_static! {
static ref MUTEX: Mutex<bool> = Mutex::new(false);
static ref CONDVAR: Condvar = Condvar::new();
struct Signaler {
mutex: Mutex<bool>,
condvar: Condvar,
}
pub fn init() -> &'static Executor {
unsafe {
CLOCK_ZERO.as_mut_ptr().write(StdInstant::now());
embassy::time::set_clock(&StdClock);
embassy::rand::set_rand(&StdRand);
impl Signaler {
fn new() -> Self {
Self {
mutex: Mutex::new(false),
condvar: Condvar::new(),
}
}
EXECUTOR.put(Executor::new_with_alarm(&StdAlarm, || {
let mut signaled = MUTEX.lock().unwrap();
*signaled = true;
CONDVAR.notify_one();
}))
fn wait(&self) {
let mut signaled = self.mutex.lock().unwrap();
while !*signaled {
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) -> ! {
unsafe {
pub struct Executor {
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 {
executor.run();
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;
unsafe { self.inner.run_queued() };
self.signaler.wait();
}
}
}

View file

@ -113,13 +113,6 @@ pub struct 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> {
let task = token.raw_task;
mem::forget(token);
@ -165,13 +158,6 @@ unsafe impl Sync for SendSpawner {}
///
/// If you want to spawn tasks from another thread, use [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> {
let header = token.raw_task;
mem::forget(token);
@ -207,7 +193,7 @@ impl Executor {
///
/// This function never returns.
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(Spawner::new(&self.inner));
init(unsafe { self.inner.spawner() });
loop {
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) {
self.irq.disable();
init(Spawner::new(&self.inner));
init(unsafe { self.inner.spawner() });
self.irq.set_handler(
|ctx| unsafe {

View file

@ -1,5 +1,6 @@
use core::cell::Cell;
use core::cmp::min;
use core::marker::PhantomData;
use core::ptr;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicU32, Ordering};
@ -67,7 +68,7 @@ impl Task {
}
}
pub(crate) struct Executor {
pub struct Executor {
run_queue: RunQueue,
timer_queue: TimerQueue,
signal_fn: fn(*mut ()),
@ -76,7 +77,7 @@ pub(crate) struct 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 {
run_queue: RunQueue::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);
}
pub fn set_signal_ctx(&mut self, signal_ctx: *mut ()) {
self.signal_ctx = signal_ctx;
}
unsafe fn enqueue(&self, item: *mut Task) {
if self.run_queue.enqueue(item) {
(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();
task.executor.set(self);
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() {
self.timer_queue.dequeue_expired(Instant::now(), |p| {
p.as_ref().enqueue();
@ -138,6 +143,13 @@ impl Executor {
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;