diff options
| author | Dario Nieuwenhuis <[email protected]> | 2020-12-28 03:40:28 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2020-12-28 03:41:40 +0100 |
| commit | 4a7344cb6f33bc6acdb982b7c180e0da81ad2710 (patch) | |
| tree | 289c869ccd6cb953d554fc085dfed388649e0b2b /embassy-std | |
| parent | 32c67381df48979f6cf3c188b0dec447d1935d12 (diff) | |
Add embassy-std crate with glue to run embassy on std.
Diffstat (limited to 'embassy-std')
| -rw-r--r-- | embassy-std/Cargo.toml | 10 | ||||
| -rw-r--r-- | embassy-std/src/lib.rs | 95 |
2 files changed, 105 insertions, 0 deletions
diff --git a/embassy-std/Cargo.toml b/embassy-std/Cargo.toml new file mode 100644 index 000000000..2a8028137 --- /dev/null +++ b/embassy-std/Cargo.toml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-std" | ||
| 3 | version = "0.1.0" | ||
| 4 | authors = ["Dario Nieuwenhuis <[email protected]>"] | ||
| 5 | edition = "2018" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy = { version = "0.1.0", path = "../embassy", features = ["std"] } | ||
| 9 | lazy_static = "1.4.0" | ||
| 10 | rand_core = { version = "0.6.0", features = ["std"] } | ||
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 @@ | |||
| 1 | use embassy::executor::Executor; | ||
| 2 | use embassy::time::TICKS_PER_SECOND; | ||
| 3 | use embassy::time::{Alarm, Clock}; | ||
| 4 | use embassy::util::Forever; | ||
| 5 | use rand_core::{OsRng, RngCore}; | ||
| 6 | use std::mem::MaybeUninit; | ||
| 7 | use std::sync::{Condvar, Mutex}; | ||
| 8 | use std::time::{Duration as StdDuration, Instant as StdInstant}; | ||
| 9 | |||
| 10 | static mut CLOCK_ZERO: MaybeUninit<StdInstant> = MaybeUninit::uninit(); | ||
| 11 | struct StdClock; | ||
| 12 | impl Clock for StdClock { | ||
| 13 | fn now(&self) -> u64 { | ||
| 14 | let zero = unsafe { CLOCK_ZERO.as_ptr().read() }; | ||
| 15 | let dur = StdInstant::now().duration_since(zero); | ||
| 16 | dur.as_secs() * (TICKS_PER_SECOND as u64) | ||
| 17 | + (dur.subsec_nanos() as u64) * (TICKS_PER_SECOND as u64) / 1_000_000_000 | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | struct StdRand; | ||
| 22 | impl embassy::rand::Rand for StdRand { | ||
| 23 | fn rand(&self, buf: &mut [u8]) { | ||
| 24 | OsRng.fill_bytes(buf); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | static mut ALARM_AT: u64 = u64::MAX; | ||
| 29 | |||
| 30 | pub struct StdAlarm; | ||
| 31 | impl Alarm for StdAlarm { | ||
| 32 | fn set_callback(&self, _callback: fn()) {} | ||
| 33 | fn set(&self, timestamp: u64) { | ||
| 34 | unsafe { ALARM_AT = timestamp } | ||
| 35 | } | ||
| 36 | |||
| 37 | fn clear(&self) { | ||
| 38 | unsafe { ALARM_AT = u64::MAX } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | static EXECUTOR: Forever<Executor> = Forever::new(); | ||
| 43 | |||
| 44 | lazy_static::lazy_static! { | ||
| 45 | static ref MUTEX: Mutex<bool> = Mutex::new(false); | ||
| 46 | static ref CONDVAR: Condvar = Condvar::new(); | ||
| 47 | } | ||
| 48 | |||
| 49 | pub fn init() -> &'static Executor { | ||
| 50 | unsafe { | ||
| 51 | CLOCK_ZERO.as_mut_ptr().write(StdInstant::now()); | ||
| 52 | embassy::time::set_clock(&StdClock); | ||
| 53 | embassy::rand::set_rand(&StdRand); | ||
| 54 | |||
| 55 | EXECUTOR.put(Executor::new_with_alarm(&StdAlarm, || { | ||
| 56 | let mut signaled = MUTEX.lock().unwrap(); | ||
| 57 | *signaled = true; | ||
| 58 | CONDVAR.notify_one(); | ||
| 59 | })) | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | pub fn run(executor: &'static Executor) -> ! { | ||
| 64 | unsafe { | ||
| 65 | loop { | ||
| 66 | executor.run(); | ||
| 67 | |||
| 68 | let mut signaled = MUTEX.lock().unwrap(); | ||
| 69 | while !*signaled { | ||
| 70 | let alarm_at = ALARM_AT; | ||
| 71 | if alarm_at == u64::MAX { | ||
| 72 | signaled = CONDVAR.wait(signaled).unwrap(); | ||
| 73 | } else { | ||
| 74 | let now = StdClock.now(); | ||
| 75 | if now >= alarm_at { | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | |||
| 79 | let left = alarm_at - now; | ||
| 80 | let dur = StdDuration::new( | ||
| 81 | left / (TICKS_PER_SECOND as u64), | ||
| 82 | (left % (TICKS_PER_SECOND as u64) * 1_000_000_000 | ||
| 83 | / (TICKS_PER_SECOND as u64)) as u32, | ||
| 84 | ); | ||
| 85 | let (signaled2, timeout) = CONDVAR.wait_timeout(signaled, dur).unwrap(); | ||
| 86 | signaled = signaled2; | ||
| 87 | if timeout.timed_out() { | ||
| 88 | break; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | *signaled = false; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | } | ||
