From 4a7344cb6f33bc6acdb982b7c180e0da81ad2710 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 28 Dec 2020 03:40:28 +0100 Subject: Add embassy-std crate with glue to run embassy on std. --- embassy-std/src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 embassy-std/src/lib.rs (limited to 'embassy-std/src') diff --git a/embassy-std/src/lib.rs b/embassy-std/src/lib.rs new file mode 100644 index 000000000..2fb814b4d --- /dev/null +++ b/embassy-std/src/lib.rs @@ -0,0 +1,95 @@ +use embassy::executor::Executor; +use embassy::time::TICKS_PER_SECOND; +use embassy::time::{Alarm, Clock}; +use embassy::util::Forever; +use rand_core::{OsRng, RngCore}; +use std::mem::MaybeUninit; +use std::sync::{Condvar, Mutex}; +use std::time::{Duration as StdDuration, Instant as StdInstant}; + +static mut CLOCK_ZERO: MaybeUninit = MaybeUninit::uninit(); +struct StdClock; +impl Clock for StdClock { + fn now(&self) -> u64 { + let zero = unsafe { CLOCK_ZERO.as_ptr().read() }; + let dur = StdInstant::now().duration_since(zero); + dur.as_secs() * (TICKS_PER_SECOND as u64) + + (dur.subsec_nanos() as u64) * (TICKS_PER_SECOND as u64) / 1_000_000_000 + } +} + +struct StdRand; +impl embassy::rand::Rand for StdRand { + fn rand(&self, buf: &mut [u8]) { + OsRng.fill_bytes(buf); + } +} + +static mut ALARM_AT: u64 = u64::MAX; + +pub struct StdAlarm; +impl Alarm for StdAlarm { + fn set_callback(&self, _callback: fn()) {} + fn set(&self, timestamp: u64) { + unsafe { ALARM_AT = timestamp } + } + + fn clear(&self) { + unsafe { ALARM_AT = u64::MAX } + } +} + +static EXECUTOR: Forever = Forever::new(); + +lazy_static::lazy_static! { + static ref MUTEX: Mutex = Mutex::new(false); + static ref CONDVAR: Condvar = Condvar::new(); +} + +pub fn init() -> &'static Executor { + unsafe { + CLOCK_ZERO.as_mut_ptr().write(StdInstant::now()); + embassy::time::set_clock(&StdClock); + embassy::rand::set_rand(&StdRand); + + EXECUTOR.put(Executor::new_with_alarm(&StdAlarm, || { + let mut signaled = MUTEX.lock().unwrap(); + *signaled = true; + CONDVAR.notify_one(); + })) + } +} + +pub fn run(executor: &'static Executor) -> ! { + unsafe { + 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; + } + } +} -- cgit