aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.example.toml1
-rw-r--r--embassy/Cargo.toml2
-rw-r--r--embassy/src/executor/mod.rs3
-rw-r--r--embassy/src/time/driver_std.rs208
-rw-r--r--embassy/src/time/mod.rs3
-rw-r--r--examples/std/Cargo.toml3
-rw-r--r--examples/std/src/bin/net.rs3
-rw-r--r--examples/std/src/bin/serial.rs2
-rw-r--r--examples/std/src/bin/tick.rs2
9 files changed, 218 insertions, 9 deletions
diff --git a/Cargo.example.toml b/Cargo.example.toml
index f072c2f96..0e9d1e32d 100644
--- a/Cargo.example.toml
+++ b/Cargo.example.toml
@@ -45,7 +45,6 @@ members = [
45 #"examples/rp", 45 #"examples/rp",
46 46
47 # std 47 # std
48 #"embassy-std",
49 #"examples/std", 48 #"examples/std",
50] 49]
51 50
diff --git a/embassy/Cargo.toml b/embassy/Cargo.toml
index ec76299e1..0ff71ce1d 100644
--- a/embassy/Cargo.toml
+++ b/embassy/Cargo.toml
@@ -7,7 +7,7 @@ resolver = "2"
7 7
8[features] 8[features]
9default = [] 9default = []
10std = ["futures/std", "embassy-traits/std"] 10std = ["futures/std", "embassy-traits/std", "time", "time-tick-1mhz"]
11 11
12# Enable `embassy::time` module. 12# Enable `embassy::time` module.
13# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation. 13# NOTE: This feature is only intended to be enabled by crates providing the time driver implementation.
diff --git a/embassy/src/executor/mod.rs b/embassy/src/executor/mod.rs
index e0ac566f1..5ffbe689e 100644
--- a/embassy/src/executor/mod.rs
+++ b/embassy/src/executor/mod.rs
@@ -1,4 +1,5 @@
1#[path = "arch/arm.rs"] 1#[cfg_attr(feature = "std", path = "arch/std.rs")]
2#[cfg_attr(not(feature = "std"), path = "arch/arm.rs")]
2mod arch; 3mod arch;
3pub mod raw; 4pub mod raw;
4mod spawner; 5mod spawner;
diff --git a/embassy/src/time/driver_std.rs b/embassy/src/time/driver_std.rs
new file mode 100644
index 000000000..29911c4d2
--- /dev/null
+++ b/embassy/src/time/driver_std.rs
@@ -0,0 +1,208 @@
1use atomic_polyfill::{AtomicU8, Ordering};
2use std::cell::UnsafeCell;
3use std::mem;
4use std::mem::MaybeUninit;
5use std::sync::{Condvar, Mutex, Once};
6use std::time::Duration as StdDuration;
7use std::time::Instant as StdInstant;
8use std::{ptr, thread};
9
10use crate::time::driver::{AlarmHandle, Driver};
11
12const ALARM_COUNT: usize = 4;
13
14struct AlarmState {
15 timestamp: u64,
16
17 // This is really a Option<(fn(*mut ()), *mut ())>
18 // but fn pointers aren't allowed in const yet
19 callback: *const (),
20 ctx: *mut (),
21}
22
23unsafe impl Send for AlarmState {}
24
25impl AlarmState {
26 const fn new() -> Self {
27 Self {
28 timestamp: u64::MAX,
29 callback: ptr::null(),
30 ctx: ptr::null_mut(),
31 }
32 }
33}
34
35struct TimeDriver {
36 alarm_count: AtomicU8,
37
38 once: Once,
39 alarms: UninitCell<Mutex<[AlarmState; ALARM_COUNT]>>,
40 zero_instant: UninitCell<StdInstant>,
41 signaler: UninitCell<Signaler>,
42}
43
44const ALARM_NEW: AlarmState = AlarmState::new();
45crate::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
46 alarm_count: AtomicU8::new(0),
47
48 once: Once::new(),
49 alarms: UninitCell::uninit(),
50 zero_instant: UninitCell::uninit(),
51 signaler: UninitCell::uninit(),
52});
53
54impl TimeDriver {
55 fn init(&self) {
56 self.once.call_once(|| unsafe {
57 self.alarms.write(Mutex::new([ALARM_NEW; ALARM_COUNT]));
58 self.zero_instant.write(StdInstant::now());
59 self.signaler.write(Signaler::new());
60
61 thread::spawn(Self::alarm_thread);
62 });
63 }
64
65 fn alarm_thread() {
66 loop {
67 let now = DRIVER.now();
68
69 let mut next_alarm = u64::MAX;
70 {
71 let alarms = &mut *unsafe { DRIVER.alarms.as_ref() }.lock().unwrap();
72 for alarm in alarms {
73 if alarm.timestamp <= now {
74 alarm.timestamp = u64::MAX;
75
76 // Call after clearing alarm, so the callback can set another alarm.
77
78 // safety:
79 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
80 // - other than that we only store valid function pointers into alarm.callback
81 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback) };
82 f(alarm.ctx);
83 } else {
84 next_alarm = next_alarm.min(alarm.timestamp);
85 }
86 }
87 }
88
89 let until =
90 unsafe { DRIVER.zero_instant.read() } + StdDuration::from_micros(next_alarm);
91
92 unsafe { DRIVER.signaler.as_ref() }.wait_until(until);
93 }
94 }
95}
96
97impl Driver for TimeDriver {
98 fn now(&self) -> u64 {
99 self.init();
100
101 let zero = unsafe { self.zero_instant.read() };
102 StdInstant::now().duration_since(zero).as_micros() as u64
103 }
104
105 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
106 let id = self
107 .alarm_count
108 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
109 if x < ALARM_COUNT as u8 {
110 Some(x + 1)
111 } else {
112 None
113 }
114 });
115
116 match id {
117 Ok(id) => Some(AlarmHandle::new(id)),
118 Err(_) => None,
119 }
120 }
121
122 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
123 self.init();
124 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
125 let alarm = &mut alarms[alarm.id() as usize];
126 alarm.callback = callback as *const ();
127 alarm.ctx = ctx;
128 }
129
130 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
131 self.init();
132 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
133 let alarm = &mut alarms[alarm.id() as usize];
134 alarm.timestamp = timestamp;
135 unsafe { self.signaler.as_ref() }.signal();
136 }
137}
138
139struct Signaler {
140 mutex: Mutex<bool>,
141 condvar: Condvar,
142}
143
144impl Signaler {
145 fn new() -> Self {
146 Self {
147 mutex: Mutex::new(false),
148 condvar: Condvar::new(),
149 }
150 }
151
152 fn wait_until(&self, until: StdInstant) {
153 let mut signaled = self.mutex.lock().unwrap();
154 while !*signaled {
155 let now = StdInstant::now();
156
157 if now >= until {
158 break;
159 }
160
161 let dur = until - now;
162 let (signaled2, timeout) = self.condvar.wait_timeout(signaled, dur).unwrap();
163 signaled = signaled2;
164 if timeout.timed_out() {
165 break;
166 }
167 }
168 *signaled = false;
169 }
170
171 fn signal(&self) {
172 let mut signaled = self.mutex.lock().unwrap();
173 *signaled = true;
174 self.condvar.notify_one();
175 }
176}
177
178pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>);
179unsafe impl<T> Send for UninitCell<T> {}
180unsafe impl<T> Sync for UninitCell<T> {}
181
182impl<T> UninitCell<T> {
183 pub const fn uninit() -> Self {
184 Self(MaybeUninit::uninit())
185 }
186
187 pub unsafe fn as_ptr(&self) -> *const T {
188 (*self.0.as_ptr()).get()
189 }
190
191 pub unsafe fn as_mut_ptr(&self) -> *mut T {
192 (*self.0.as_ptr()).get()
193 }
194
195 pub unsafe fn as_ref(&self) -> &T {
196 &*self.as_ptr()
197 }
198
199 pub unsafe fn write(&self, val: T) {
200 ptr::write(self.as_mut_ptr(), val)
201 }
202}
203
204impl<T: Copy> UninitCell<T> {
205 pub unsafe fn read(&self) -> T {
206 ptr::read(self.as_mut_ptr())
207 }
208}
diff --git a/embassy/src/time/mod.rs b/embassy/src/time/mod.rs
index db48fb3ec..e50742040 100644
--- a/embassy/src/time/mod.rs
+++ b/embassy/src/time/mod.rs
@@ -46,6 +46,9 @@ mod duration;
46mod instant; 46mod instant;
47mod timer; 47mod timer;
48 48
49#[cfg(feature = "std")]
50mod driver_std;
51
49pub use delay::{block_for, Delay}; 52pub use delay::{block_for, Delay};
50pub use duration::Duration; 53pub use duration::Duration;
51pub use instant::Instant; 54pub use instant::Instant;
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 466814850..34b8ebb67 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -5,8 +5,7 @@ name = "embassy-std-examples"
5version = "0.1.0" 5version = "0.1.0"
6 6
7[dependencies] 7[dependencies]
8embassy = { version = "0.1.0", path = "../../embassy", features = ["log"] } 8embassy = { version = "0.1.0", path = "../../embassy", features = ["log", "std", "time"] }
9embassy-std = { version = "0.1.0", path = "../../embassy-std" }
10embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] } 9embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] }
11smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="e4241510337e095b9d21136c5f58b2eaa1b78479", default-features = false } 10smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="e4241510337e095b9d21136c5f58b2eaa1b78479", default-features = false }
12 11
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 323d711a8..b98b97090 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -2,11 +2,10 @@
2#![allow(incomplete_features)] 2#![allow(incomplete_features)]
3 3
4use clap::{AppSettings, Clap}; 4use clap::{AppSettings, Clap};
5use embassy::executor::Spawner; 5use embassy::executor::{Executor, Spawner};
6use embassy::io::AsyncWriteExt; 6use embassy::io::AsyncWriteExt;
7use embassy::util::Forever; 7use embassy::util::Forever;
8use embassy_net::*; 8use embassy_net::*;
9use embassy_std::Executor;
10use heapless::Vec; 9use heapless::Vec;
11use log::*; 10use log::*;
12 11
diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs
index ca596a34c..181c5dfaa 100644
--- a/examples/std/src/bin/serial.rs
+++ b/examples/std/src/bin/serial.rs
@@ -5,9 +5,9 @@
5mod serial_port; 5mod serial_port;
6 6
7use async_io::Async; 7use async_io::Async;
8use embassy::executor::Executor;
8use embassy::io::AsyncBufReadExt; 9use embassy::io::AsyncBufReadExt;
9use embassy::util::Forever; 10use embassy::util::Forever;
10use embassy_std::Executor;
11use log::*; 11use log::*;
12use nix::sys::termios; 12use nix::sys::termios;
13 13
diff --git a/examples/std/src/bin/tick.rs b/examples/std/src/bin/tick.rs
index 16f54b2c6..385b317d4 100644
--- a/examples/std/src/bin/tick.rs
+++ b/examples/std/src/bin/tick.rs
@@ -1,9 +1,9 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2#![allow(incomplete_features)] 2#![allow(incomplete_features)]
3 3
4use embassy::executor::Executor;
4use embassy::time::{Duration, Timer}; 5use embassy::time::{Duration, Timer};
5use embassy::util::Forever; 6use embassy::util::Forever;
6use embassy_std::Executor;
7use log::*; 7use log::*;
8 8
9#[embassy::task] 9#[embassy::task]