cortex_m_asyncrt/os/
executor.rs1extern crate alloc;
2
3use super::*;
4use alloc::collections::BTreeMap;
5use alloc::sync::Arc;
6use alloc::task::Wake;
7use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
8use cortex_m::asm;
9use crossbeam_queue::ArrayQueue;
10
11struct TaskWaker {
12 task_id: TaskId,
13 task_queue: Arc<ArrayQueue<TaskId>>,
14}
15
16impl TaskWaker {
17 fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker {
18 Waker::from(Arc::new(TaskWaker {
19 task_id,
20 task_queue,
21 }))
22 }
23 fn wake_task(&self) {
24 self.task_queue
25 .push(self.task_id)
26 .expect("Task queue is full!");
27 }
28}
29
30impl Wake for TaskWaker {
31 fn wake(self: Arc<Self>) {
32 self.wake_task();
33 }
34
35 fn wake_by_ref(self: &Arc<Self>) {
36 self.wake_task();
37 }
38}
39
40pub struct Executor {
42 tasks: BTreeMap<TaskId, Task>,
46 task_queue: Arc<ArrayQueue<TaskId>>,
50 waker_cache: BTreeMap<TaskId, Waker>,
54}
55
56impl Executor {
57 pub fn new<const N: usize>() -> Executor {
59 Executor {
60 tasks: BTreeMap::new(),
61 task_queue: Arc::new(ArrayQueue::new(N)),
62 waker_cache: BTreeMap::new(),
63 }
64 }
65
66 pub fn spawn(&mut self, task: Task) {
68 let task_id = task.id;
69 if self.tasks.insert(task_id, task).is_some() {
70 panic!("task with same ID already in tasks");
71 }
72 self.task_queue.push(task_id).expect("Task queue is full.");
73 }
74
75 fn run_ready_tasks(&mut self) {
77 while let Some(task_id) = self.task_queue.pop() {
79 let task = match self.tasks.get_mut(&task_id) {
81 Some(task) => task,
82 None => continue, };
84
85 let waker = self
87 .waker_cache
88 .entry(task_id)
89 .or_insert_with(|| TaskWaker::new(task_id, self.task_queue.clone())); let mut context = Context::from_waker(waker);
93
94 match task.poll(&mut context) {
96 Poll::Ready(()) => {
97 self.tasks.remove(&task_id);
99 self.waker_cache.remove(&task_id);
100 }
101 Poll::Pending => {} }
103 }
104 }
105
106 fn sleep_if_idle(&self) {
108 cortex_m::interrupt::free(|_| {
110 if self.task_queue.is_empty() {
111 asm::wfi(); }
113 });
114 }
115
116 pub fn run(&mut self) {
118 loop {
119 self.run_ready_tasks();
120 self.sleep_if_idle();
121 }
122 }
123}
124
125pub fn dummy_raw_waker() -> RawWaker {
126 fn no_op(_: *const ()) {}
127 fn clone(_: *const ()) -> RawWaker {
128 dummy_raw_waker()
129 }
130
131 let vtable = &RawWakerVTable::new(clone, no_op, no_op, no_op);
132
133 RawWaker::new(0 as *const (), vtable)
134}
135
136pub fn dummy_waker() -> Waker {
137 unsafe { Waker::from_raw(dummy_raw_waker()) }
138}