1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
use super::{super::task, with_executor_as, Executor};
use core::{cell::UnsafeCell, future::Future, marker::Sync};

/// Run a future, and all the tasks is spawns recursively,
/// using an executor optimized for running single threaded.
///
/// As this relies on `with_executor_as()`, the caller should
/// ensure that this function is not called on multiple threads.
pub fn run<T>(future: impl Future<Output = T>) -> T {
    let executor = SerialExecutor(UnsafeCell::new(Runtime {
        run_queue: task::List::default(),
    }));

    with_executor_as(&executor, move |executor| {
        let mut future = task::FutureTask::new(task::Priority::Normal, future);
        if future.resume().is_ready() {
            return future.into_output().unwrap();
        }

        while let Some(task) = executor.poll() {
            task.resume();
        }

        debug_assert!(future.resume().is_ready());
        future.into_output().unwrap()
    })
}

struct Runtime {
    run_queue: task::List,
}

/// Encapsulate the runtime so that it can be accessed from a global state.
/// Should be safe to do so without synchronization considering it should
/// only be accessed by a single thread.  
struct SerialExecutor(UnsafeCell<Runtime>);

unsafe impl Sync for SerialExecutor {}

impl SerialExecutor {
    pub fn poll<'a>(&self) -> Option<&'a mut task::Task> {
        let runtime = unsafe { &mut *self.0.get() };
        runtime.run_queue.pop()
    }
}

impl Executor for SerialExecutor {
    fn schedule(&self, task: &mut task::Task) {
        let mut list = task::PriorityList::default();
        list.push(task);

        let runtime = unsafe { &mut *self.0.get() };
        runtime.run_queue.push(&list);
    }
}