Skip to content

Instantly share code, notes, and snippets.

@DoumanAsh
Created August 15, 2019 16:03
Show Gist options
  • Save DoumanAsh/1c6e0d6198d02ab242ad148fd4c4bd4f to your computer and use it in GitHub Desktop.
Save DoumanAsh/1c6e0d6198d02ab242ad148fd4c4bd4f to your computer and use it in GitHub Desktop.
///Describes Executor configuration
pub trait ExecutorConfig {
///Function to call when exectur goes to sleep.
fn on_sleep(&mut self) {
#[cfg(not(feature = "std"))]
core::sync::atomic::spin_loop_hint();
#[cfg(feature = "std")]
std::thread::yield_now();
}
///Function to perform poll of future.
fn poll_block<R, F: FnOnce() -> R>(&self, poll: F) -> R {
poll()
}
///Function to be called when `Executor` is woken.
///
///Does nothing by default
fn wake() {
}
}
///Default configuration
///
///By default it uses following `ON_SLEEP`:
///
///`no_std` - `core::sync::atomic::spin_loop_hint`
///`std` - `std::thread::yield_now`
pub struct DefaultCfg;
impl ExecutorConfig for DefaultCfg {}
///Trivial single threaded executor than can only run single future.
pub struct Executor<C=DefaultCfg> where C: ExecutorConfig {
config: C,
waker: MehishaWaker,
}
impl Executor {
///Creates Executor with [Default Config](struct.DefaultCfg.html).
pub const fn with_default() -> Self {
Self::new(DefaultCfg)
}
}
impl<C: ExecutorConfig> Executor<C> {
///Creates Executor with provided configuration.
pub const fn new(config: C) -> Self {
Self {
config,
waker: MehishaWaker::new(C::wake),
}
}
}
impl<C: ExecutorConfig> super::Executor for Executor<C> {
fn run<F: Future>(&mut self, mut future: F) -> F::Output {
let waker = self.waker.waker();
let mut context = task::Context::from_waker(&waker);
loop {
let poll = self.config.poll_block(|| Future::poll(unsafe { Pin::new_unchecked(&mut future) }, &mut context));
match poll {
task::Poll::Ready(result) => break result,
task::Poll::Pending => while !self.waker.take_woke_status() {
self.config.on_sleep();
}
}
}
}
}
struct Config {
reactor: tokio::reactor::Reactor,
}
impl Config {
fn new() -> Self {
Self {
reactor: tokio::reactor::Reactor::new().expect("To create tokio reactor"),
}
}
}
impl ExecutorConfig for Config {
fn poll_block<R, F: FnOnce() -> R>(&self, poll: F) -> R {
tokio_reactor::with_default(&self.reactor.handle(), poll)
}
fn on_sleep(&mut self) {
match self.reactor.is_idle() {
true => (),
false => {
self.reactor.turn(None).expect("To turn reactor");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment