1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
extern crate alloc;
use futures::{
channel::oneshot::{self, Sender},
executor::{LocalPool, LocalSpawner},
task::{LocalSpawnExt, SpawnError},
TryFutureExt,
};
use core::alloc::Layout;
use std::future::Future;
use std::{cell::RefCell, time::Instant};
use std::{collections::BTreeMap, time::Duration};
#[no_mangle]
pub unsafe extern "C" fn __cfx_alloc(size: u32, align: u32) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size as _, align as _);
alloc::alloc::alloc(layout)
}
#[no_mangle]
pub unsafe extern "C" fn __cfx_free(ptr: *mut u8, size: u32, align: u32) {
let layout = Layout::from_size_align_unchecked(size as _, align as _);
alloc::alloc::dealloc(ptr, layout);
}
thread_local! {
pub(crate) static LOCAL_POOL: RefCell<LocalPool> = RefCell::new(LocalPool::new());
static SPAWNER: RefCell<LocalSpawner> = LOCAL_POOL.with(|lp| RefCell::new(lp.borrow().spawner()));
static TIMERS: RefCell<BTreeMap<Instant, Vec<Sender<()>>>> = RefCell::new(BTreeMap::new());
}
pub fn spawn<Fut: Future<Output = ()> + 'static>(future: Fut) -> Result<(), SpawnError> {
SPAWNER.with(|sp| sp.borrow().spawn_local(future))
}
#[no_mangle]
pub extern "C" fn __cfx_on_tick() {
fire_timers();
LOCAL_POOL.with(|lp| {
let mut lp = lp.borrow_mut();
lp.run_until_stalled();
});
}
fn fire_timers() {
let now = Instant::now();
TIMERS.with(|timers| {
let mut timers = timers.borrow_mut();
let expiered: Vec<Instant> = timers.range(..=now).map(|(time, _)| *time).collect();
for key in expiered {
if let Some(senders) = timers.remove(&key) {
for tx in senders {
let _ = tx.send(());
}
}
}
});
}
pub fn sleep_for(duration: Duration) -> impl Future<Output = ()> {
let instant = Instant::now().checked_add(duration).unwrap();
let (tx, rx) = oneshot::channel();
TIMERS.with(|timers| {
let mut timers = timers.borrow_mut();
let entry = timers.entry(instant).or_insert_with(Vec::new);
entry.push(tx);
});
rx.unwrap_or_else(|_| ())
}