toy_async_runtime/
task.rs

1//! Task implementation
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::atomic::Ordering;
5use std::sync::{Arc, Mutex};
6use std::task::{Context, Poll, Wake, Waker};
7
8use crate::runitime::Runtime;
9
10/// The `Task` is the basic unit for the executor. It represents a `Future`
11/// that may or may not be completed. We spawn `Task`s to be run and poll
12/// them until completion in a non-blocking manner unless specifically asked
13/// for.
14pub(crate) struct Task {
15    /// This is the actual `Future` we will poll inside of a `Task`. We `Box`
16    /// and `Pin` the `Future` when we create a task so that we don't need
17    /// to worry about pinning or more complicated things in the runtime. We
18    /// also need to make sure this is `Send + Sync` so we can use it across threads
19    /// and so we lock the `Pin<Box<dyn Future>>` inside a `Mutex`.
20    future: Mutex<Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>>,
21    /// We need a way to check if the runtime should block on this task and
22    /// so we use a boolean here to check that!
23    block: bool,
24}
25
26impl Wake for Task {
27    fn wake(self: Arc<Self>) {
28        if self.is_blocking() {
29            Runtime::spawner().inner_spawn_blocking(self);
30        } else {
31            Runtime::spawner().inner_spawn(self);
32        }
33    }
34}
35
36impl Drop for Task {
37    fn drop(&mut self) {
38        Runtime::get().size.fetch_sub(1, Ordering::Relaxed);
39    }
40}
41
42impl Task {
43    pub(crate) fn new(
44        block: bool,
45        future: impl Future<Output = ()> + Send + Sync + 'static,
46    ) -> Arc<Self> {
47        Runtime::get().size.fetch_add(1, Ordering::Relaxed);
48        Arc::new(Task {
49            future: Mutex::new(Box::pin(future)),
50            block,
51        })
52    }
53
54    /// Pool the following task!
55    pub fn poll(self: &Arc<Self>) -> Poll<()> {
56        let waker = self.waker();
57        let mut ctx = Context::from_waker(&waker);
58        self.future.lock().unwrap().as_mut().poll(&mut ctx)
59    }
60
61    // FIXIME: what is this method?
62    pub fn waker(self: &Arc<Self>) -> Waker {
63        self.clone().into()
64    }
65
66    /// The Task is blocking.
67    pub fn is_blocking(&self) -> bool {
68        self.block
69    }
70}