Initial commit
This commit is contained in:
commit
54e908530d
7 changed files with 167 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
16
Cargo.lock
generated
Normal file
16
Cargo.lock
generated
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "microasync"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"microlock",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "microlock"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "849d9daa132b37b3082c2ef186343573aedf6ebc7e1b57343e9278e81a2b5b20"
|
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "microasync"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
microlock = "0.2.0"
|
13
examples/basic.rs
Normal file
13
examples/basic.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use microasync::rt::{MiniAsync, TimerDuration};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let rt = MiniAsync::new(TimerDuration::Real(Duration::from_millis(20)));
|
||||||
|
rt.add_task(async_main());
|
||||||
|
rt.run_until_empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_main() {
|
||||||
|
println!("Hello from async!")
|
||||||
|
}
|
27
src/lib.rs
Normal file
27
src/lib.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
pub mod rt;
|
||||||
|
|
||||||
|
use std::{cell::RefCell, ptr};
|
||||||
|
|
||||||
|
use rt::MiniAsync;
|
||||||
|
thread_local! {
|
||||||
|
static RUNTIME: RefCell<*const MiniAsync> = const { RefCell::new(ptr::null()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn current_runtime(rt: &MiniAsync) {
|
||||||
|
RUNTIME.with_borrow_mut(|x| *x = rt as *const _);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn exiting_runtime() {
|
||||||
|
RUNTIME.with_borrow_mut(|x| *x = ptr::null());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// The lifetime given out by this function is static but the underlying
|
||||||
|
/// struct is not, leading to use after free if this is not paid attention to.
|
||||||
|
pub unsafe fn get_runtime() -> &'static MiniAsync {
|
||||||
|
unsafe { &*RUNTIME.with_borrow(|x| *x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn runtime(f: impl FnOnce(&MiniAsync)) {
|
||||||
|
f(unsafe { get_runtime() })
|
||||||
|
}
|
66
src/rt/mod.rs
Normal file
66
src/rt/mod.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
mod waker;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
|
sync::Mutex,
|
||||||
|
task::{Context, Poll},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use microlock::timer::TimerDuration;
|
||||||
|
use microlock::Lock;
|
||||||
|
|
||||||
|
use crate::{current_runtime, exiting_runtime};
|
||||||
|
|
||||||
|
use self::waker::MicroWaker;
|
||||||
|
|
||||||
|
pub type Task<T> = Pin<Box<dyn Future<Output = T>>>;
|
||||||
|
|
||||||
|
pub struct MiniAsync {
|
||||||
|
tasks: Vec<Task<()>>,
|
||||||
|
tasks_to_add: Mutex<Vec<Task<()>>>,
|
||||||
|
waker: MicroWaker,
|
||||||
|
wake_attempt_delay: TimerDuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MiniAsync {
|
||||||
|
pub fn new(wake_attempt_delay: TimerDuration) -> Self {
|
||||||
|
Self {
|
||||||
|
tasks: Vec::new(),
|
||||||
|
tasks_to_add: Mutex::new(Vec::new()),
|
||||||
|
waker: MicroWaker::new(),
|
||||||
|
wake_attempt_delay,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_boxed_task(&self, future: Pin<Box<impl Future<Output = ()> + 'static>>) {
|
||||||
|
self.tasks_to_add.lock().unwrap().push(future);
|
||||||
|
self.waker.lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_task(&self, future: impl Future<Output = ()> + 'static) {
|
||||||
|
self.tasks_to_add.lock().unwrap().push(Box::pin(future));
|
||||||
|
self.waker.lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_until_empty(mut self) {
|
||||||
|
current_runtime(&self);
|
||||||
|
let waker = self.waker.rust_waker();
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
while !self.tasks.is_empty() {
|
||||||
|
let mut next_tasks = Vec::with_capacity(self.tasks.len());
|
||||||
|
for mut task in self.tasks {
|
||||||
|
match Future::poll(task.as_mut(), &mut cx) {
|
||||||
|
Poll::Ready(_) => drop(task),
|
||||||
|
Poll::Pending => next_tasks.push(task),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
next_tasks.append(&mut self.tasks_to_add.lock().unwrap());
|
||||||
|
self.tasks = next_tasks;
|
||||||
|
self.waker.lock.wait_here_for(self.wake_attempt_delay);
|
||||||
|
self.waker.lock.try_lock();
|
||||||
|
}
|
||||||
|
exiting_runtime();
|
||||||
|
}
|
||||||
|
}
|
37
src/rt/waker.rs
Normal file
37
src/rt/waker.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use std::task::{RawWaker, RawWakerVTable, Waker};
|
||||||
|
|
||||||
|
use microlock::{Lock, TimedLock};
|
||||||
|
|
||||||
|
pub struct MicroWaker {
|
||||||
|
pub(crate) lock: TimedLock,
|
||||||
|
}
|
||||||
|
impl MicroWaker {
|
||||||
|
pub fn new() -> MicroWaker {
|
||||||
|
Self {
|
||||||
|
lock: TimedLock::locked(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rust_waker(&self) -> Waker {
|
||||||
|
unsafe { Waker::from_raw(Self::clone(self as *const _ as _)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone(me: *const ()) -> RawWaker {
|
||||||
|
RawWaker::new(
|
||||||
|
me,
|
||||||
|
&RawWakerVTable::new(Self::clone, Self::wake, Self::wake_by_ref, Self::drop),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake(me: *const ()) {
|
||||||
|
let me = &*(me as *const Self);
|
||||||
|
me.lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake_by_ref(me: *const ()) {
|
||||||
|
let me = &*(me as *const Self);
|
||||||
|
me.lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn drop(_me: *const ()) {}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue