This repository has been archived by the owner on Jun 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from pros-rs/async_runtime
Async runtime
- Loading branch information
Showing
14 changed files
with
617 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#![no_std] | ||
#![no_main] | ||
|
||
use pros::prelude::*; | ||
|
||
#[derive(Default)] | ||
pub struct Robot; | ||
#[async_trait] | ||
impl AsyncRobot for Robot { | ||
async fn opcontrol(&mut self) -> pros::Result { | ||
println!("basic example"); | ||
|
||
Ok(()) | ||
} | ||
} | ||
async_robot!(Robot); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use core::{ | ||
cell::RefCell, | ||
future::Future, | ||
pin::Pin, | ||
sync::atomic::{AtomicBool, Ordering}, | ||
task::{Context, Poll}, | ||
}; | ||
|
||
use alloc::{collections::VecDeque, sync::Arc}; | ||
use async_task::{Runnable, Task}; | ||
use waker_fn::waker_fn; | ||
|
||
use crate::os_task_local; | ||
|
||
use super::reactor::Reactor; | ||
|
||
os_task_local! { | ||
pub(crate) static EXECUTOR: Executor = Executor::new(); | ||
} | ||
|
||
pub(crate) struct Executor { | ||
queue: RefCell<VecDeque<Runnable>>, | ||
pub(crate) reactor: RefCell<Reactor>, | ||
} | ||
|
||
impl !Send for Executor {} | ||
impl !Sync for Executor {} | ||
|
||
impl Executor { | ||
pub fn new() -> Self { | ||
Self { | ||
queue: RefCell::new(VecDeque::new()), | ||
reactor: RefCell::new(Reactor::new()), | ||
} | ||
} | ||
|
||
pub fn spawn<T>(&'static self, future: impl Future<Output = T> + 'static) -> Task<T> { | ||
// SAFETY: `runnable` will never be moved off this thread or shared with another thread because of the `!Send + !Sync` bounds on `Self`. | ||
// Both `future` and `schedule` are `'static` so they cannot be used after being freed. | ||
// TODO: Make sure that the waker can never be sent off the thread. | ||
let (runnable, task) = unsafe { | ||
async_task::spawn_unchecked(future, |runnable| { | ||
self.queue.borrow_mut().push_back(runnable) | ||
}) | ||
}; | ||
|
||
runnable.schedule(); | ||
|
||
task | ||
} | ||
|
||
pub(crate) fn tick(&self) -> bool { | ||
self.reactor.borrow_mut().tick(); | ||
|
||
let runnable = { | ||
let mut queue = self.queue.borrow_mut(); | ||
queue.pop_front() | ||
}; | ||
match runnable { | ||
Some(runnable) => { | ||
runnable.run(); | ||
true | ||
} | ||
None => false, | ||
} | ||
} | ||
|
||
pub fn block_on<R>(&self, mut task: Task<R>) -> R { | ||
let woken = Arc::new(AtomicBool::new(true)); | ||
|
||
let waker = waker_fn({ | ||
let woken = woken.clone(); | ||
move || woken.store(true, Ordering::Relaxed) | ||
}); | ||
let mut cx = Context::from_waker(&waker); | ||
|
||
loop { | ||
if woken.swap(false, Ordering::Relaxed) { | ||
if let Poll::Ready(output) = Pin::new(&mut task).poll(&mut cx) { | ||
return output; | ||
} | ||
} | ||
|
||
self.tick(); | ||
} | ||
} | ||
|
||
pub fn complete(&self) { | ||
loop { | ||
if !self.tick() { | ||
break; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use core::future::Future; | ||
|
||
use async_task::Task; | ||
|
||
pub(crate) mod executor; | ||
pub(crate) mod reactor; | ||
|
||
/// Runs a future in the background without having to await it | ||
/// To get the the return value you can await a task. | ||
pub fn spawn<T>(future: impl Future<Output = T> + 'static) -> Task<T> { | ||
executor::EXECUTOR.with(|e| e.spawn(future)) | ||
} | ||
|
||
/// Blocks the current task untill a return value can be extracted from the provided future. | ||
/// Does not poll all futures to completion. | ||
/// If you want to complete all futures, use the [`complete_all`] function. | ||
pub fn block_on<F: Future + 'static>(future: F) -> F::Output { | ||
executor::EXECUTOR.with(|e| e.block_on(spawn(future))) | ||
} | ||
|
||
/// Completes all tasks. | ||
/// Return values can be extracted from the futures by awaiting any [`Tasks`]s you have not detached. | ||
pub fn complete_all() { | ||
executor::EXECUTOR.with(|e| { | ||
e.complete(); | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
use core::task::Waker; | ||
|
||
use alloc::collections::BTreeMap; | ||
|
||
pub struct Sleepers { | ||
sleepers: BTreeMap<u32, Waker>, | ||
} | ||
|
||
impl Sleepers { | ||
pub fn push(&mut self, waker: Waker, target: u32) { | ||
self.sleepers.insert(target, waker); | ||
} | ||
|
||
pub fn pop(&mut self) -> Option<Waker> { | ||
self.sleepers.pop_first().map(|(_, waker)| waker) | ||
} | ||
} | ||
|
||
pub struct Reactor { | ||
pub(crate) sleepers: Sleepers, | ||
} | ||
|
||
impl Reactor { | ||
pub fn new() -> Self { | ||
Self { | ||
sleepers: Sleepers { | ||
sleepers: BTreeMap::new(), | ||
}, | ||
} | ||
} | ||
|
||
pub fn tick(&mut self) { | ||
if let Some(sleeper) = self.sleepers.pop() { | ||
sleeper.wake() | ||
} | ||
} | ||
} |
Oops, something went wrong.