aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/time/driver_wasm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/time/driver_wasm.rs')
-rw-r--r--embassy-executor/src/time/driver_wasm.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/embassy-executor/src/time/driver_wasm.rs b/embassy-executor/src/time/driver_wasm.rs
new file mode 100644
index 000000000..5f585a19a
--- /dev/null
+++ b/embassy-executor/src/time/driver_wasm.rs
@@ -0,0 +1,134 @@
1use std::cell::UnsafeCell;
2use std::mem::MaybeUninit;
3use std::ptr;
4use std::sync::{Mutex, Once};
5
6use atomic_polyfill::{AtomicU8, Ordering};
7use wasm_bindgen::prelude::*;
8use wasm_timer::Instant as StdInstant;
9
10use crate::time::driver::{AlarmHandle, Driver};
11
12const ALARM_COUNT: usize = 4;
13
14struct AlarmState {
15 token: Option<f64>,
16 closure: Option<Closure<dyn FnMut() + 'static>>,
17}
18
19unsafe impl Send for AlarmState {}
20
21impl AlarmState {
22 const fn new() -> Self {
23 Self {
24 token: None,
25 closure: None,
26 }
27 }
28}
29
30#[wasm_bindgen]
31extern "C" {
32 fn setTimeout(closure: &Closure<dyn FnMut()>, millis: u32) -> f64;
33 fn clearTimeout(token: f64);
34}
35
36struct TimeDriver {
37 alarm_count: AtomicU8,
38
39 once: Once,
40 alarms: UninitCell<Mutex<[AlarmState; ALARM_COUNT]>>,
41 zero_instant: UninitCell<StdInstant>,
42}
43
44const ALARM_NEW: AlarmState = AlarmState::new();
45crate::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
46 alarm_count: AtomicU8::new(0),
47 once: Once::new(),
48 alarms: UninitCell::uninit(),
49 zero_instant: UninitCell::uninit(),
50});
51
52impl TimeDriver {
53 fn init(&self) {
54 self.once.call_once(|| unsafe {
55 self.alarms.write(Mutex::new([ALARM_NEW; ALARM_COUNT]));
56 self.zero_instant.write(StdInstant::now());
57 });
58 }
59}
60
61impl Driver for TimeDriver {
62 fn now(&self) -> u64 {
63 self.init();
64
65 let zero = unsafe { self.zero_instant.read() };
66 StdInstant::now().duration_since(zero).as_micros() as u64
67 }
68
69 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
70 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
71 if x < ALARM_COUNT as u8 {
72 Some(x + 1)
73 } else {
74 None
75 }
76 });
77
78 match id {
79 Ok(id) => Some(AlarmHandle::new(id)),
80 Err(_) => None,
81 }
82 }
83
84 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
85 self.init();
86 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
87 let alarm = &mut alarms[alarm.id() as usize];
88 alarm.closure.replace(Closure::new(move || {
89 callback(ctx);
90 }));
91 }
92
93 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
94 self.init();
95 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
96 let alarm = &mut alarms[alarm.id() as usize];
97 let timeout = (timestamp - self.now()) as u32;
98 if let Some(token) = alarm.token {
99 clearTimeout(token);
100 }
101 alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000));
102 }
103}
104
105pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>);
106unsafe impl<T> Send for UninitCell<T> {}
107unsafe impl<T> Sync for UninitCell<T> {}
108
109impl<T> UninitCell<T> {
110 pub const fn uninit() -> Self {
111 Self(MaybeUninit::uninit())
112 }
113 unsafe fn as_ptr(&self) -> *const T {
114 (*self.0.as_ptr()).get()
115 }
116
117 pub unsafe fn as_mut_ptr(&self) -> *mut T {
118 (*self.0.as_ptr()).get()
119 }
120
121 pub unsafe fn as_ref(&self) -> &T {
122 &*self.as_ptr()
123 }
124
125 pub unsafe fn write(&self, val: T) {
126 ptr::write(self.as_mut_ptr(), val)
127 }
128}
129
130impl<T: Copy> UninitCell<T> {
131 pub unsafe fn read(&self) -> T {
132 ptr::read(self.as_mut_ptr())
133 }
134}