WIP: skeleton of rt::future using a global semaphore

This commit is contained in:
Chris Copeland 2023-11-12 22:19:53 -08:00
parent 74f76b300e
commit d648fc94d9
Signed by: chrisnc
GPG Key ID: 14550DA72485DF30
5 changed files with 97 additions and 0 deletions

View File

@ -35,6 +35,10 @@ panic = "abort"
lto = "on"
debug = true
[[example]]
name = "async"
path = "rust/examples/async.rs"
[[example]]
name = "donate"
path = "rust/examples/donate.rs"

24
rust/examples/async.rs Normal file
View File

@ -0,0 +1,24 @@
#![no_main]
rt::semaphore!(SEM, 0);
async fn foo() -> i32 {
SEM.async_wait().await;
1
}
fn poster() {
rt::task::sleep(10);
SEM.post();
}
fn async_runner() {
assert_eq!(rt::future::block_on(foo()), 1);
rt::trap()
}
rt::task!(poster, rt::task::STACK_MIN, 2);
/* TODO: block_on with a semaphore async_wait doesn't actually block (right now), so this task must
* be lower priority to allow poster to run. */
rt::task!(async_runner, rt::task::STACK_MIN, 1);

43
rust/src/future.rs Normal file
View File

@ -0,0 +1,43 @@
use core::{
future::Future,
pin::pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};
use crate::{semaphore_binary, sync::Semaphore};
static SEM_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
semaphore_binary!(SEM_WAKER);
unsafe fn clone(w: *const ()) -> RawWaker {
RawWaker::new(w, &SEM_WAKER_VTABLE)
}
unsafe fn wake(w: *const ()) {
wake_by_ref(w)
}
unsafe fn wake_by_ref(w: *const ()) {
let sem = &*(w as *mut () as *mut Semaphore);
sem.post();
}
unsafe fn drop(_: *const ()) {}
pub fn block_on<F: Future>(f: F) -> F::Output {
let waker = unsafe {
Waker::from_raw(RawWaker::new(
&SEM_WAKER as *const Semaphore as *const (),
&SEM_WAKER_VTABLE,
))
};
let mut cx = Context::from_waker(&waker);
let mut f = pin!(f);
loop {
if let Poll::Ready(o) = f.as_mut().poll(&mut cx) {
return o;
}
SEM_WAKER.wait();
}
}

View File

@ -1,6 +1,7 @@
#![cfg_attr(not(test), no_std)]
pub mod cycle;
pub mod future;
pub mod sync;
pub mod task;
pub mod tick;

View File

@ -1,10 +1,13 @@
use core::{
cell::UnsafeCell,
ffi::c_int,
future::Future,
marker::PhantomPinned,
mem::{size_of, transmute},
panic::{RefUnwindSafe, UnwindSafe},
pin::Pin,
ptr::null_mut,
task::{Context, Poll},
};
use crate::{
@ -90,6 +93,10 @@ impl Semaphore {
self.acquire();
SemaphoreGuard { sem: self }
}
pub fn async_wait(&self) -> WaitFuture {
WaitFuture { sem: self }
}
}
pub struct SemaphoreGuard<'a> {
@ -102,6 +109,24 @@ impl<'a> Drop for SemaphoreGuard<'a> {
}
}
pub struct WaitFuture<'a> {
sem: &'a Semaphore,
}
impl Future for WaitFuture<'_> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.sem.try_wait() {
Poll::Ready(())
} else {
// TODO: wake only once the semaphore is ready
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
#[macro_export]
macro_rules! semaphore {
($name: ident, $count: expr, $max: expr) => {