cfx_core/
runtime.rs

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