Implement proper wakeups using RawWaker

This commit is contained in:
Philipp Oppermann
2020-03-22 16:54:47 +01:00
parent 51f90236a5
commit 2772abc8eb
2 changed files with 50 additions and 15 deletions

View File

@@ -19,4 +19,8 @@ impl Task {
fn poll(&mut self, context: &mut Context) -> Poll<()> { fn poll(&mut self, context: &mut Context) -> Poll<()> {
self.future.as_mut().poll(context) self.future.as_mut().poll(context)
} }
fn id(&self) -> usize {
&*self.future as *const _ as *const () as usize
}
} }

View File

@@ -1,18 +1,23 @@
use super::Task; use super::Task;
use alloc::collections::VecDeque; use crate::println;
use core::{ use alloc::collections::{BTreeMap, VecDeque};
ptr, use conquer_once::spin::OnceCell;
task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
}; use crossbeam_queue::ArrayQueue;
static WAKE_QUEUE: OnceCell<ArrayQueue<usize>> = OnceCell::uninit();
pub struct SimpleExecutor { pub struct SimpleExecutor {
task_queue: VecDeque<Task>, task_queue: VecDeque<Task>,
waiting_tasks: BTreeMap<usize, Task>,
} }
impl SimpleExecutor { impl SimpleExecutor {
pub fn new() -> SimpleExecutor { pub fn new() -> SimpleExecutor {
WAKE_QUEUE.init_once(|| ArrayQueue::new(100));
SimpleExecutor { SimpleExecutor {
task_queue: VecDeque::new(), task_queue: VecDeque::new(),
waiting_tasks: BTreeMap::new(),
} }
} }
@@ -21,29 +26,55 @@ impl SimpleExecutor {
} }
pub fn run(&mut self) { pub fn run(&mut self) {
loop {
self.handle_wakeups();
self.run_ready_tasks();
}
}
fn handle_wakeups(&mut self) {
while let Ok(task_id) = WAKE_QUEUE.get().unwrap().pop() {
if let Some(task) = self.waiting_tasks.remove(&task_id) {
self.task_queue.push_back(task);
}
}
}
fn run_ready_tasks(&mut self) {
while let Some(mut task) = self.task_queue.pop_front() { while let Some(mut task) = self.task_queue.pop_front() {
let waker = waker(); let waker = waker(task.id());
let mut context = Context::from_waker(&waker); let mut context = Context::from_waker(&waker);
match task.poll(&mut context) { match task.poll(&mut context) {
Poll::Ready(()) => {} // task done Poll::Ready(()) => {} // task done
Poll::Pending => self.task_queue.push_back(task), Poll::Pending => {
if self.waiting_tasks.insert(task.id(), task).is_some() {
panic!("Same task inserted into waiting_tasks twice");
}
}
} }
} }
} }
} }
fn raw_waker() -> RawWaker { fn raw_waker(task_id: usize) -> RawWaker {
fn no_op(_: *const ()) {} fn clone(id: *const ()) -> RawWaker {
fn clone(_: *const ()) -> RawWaker { raw_waker(id as usize)
raw_waker()
} }
fn wake(id: *const ()) {
if let Err(_) = WAKE_QUEUE.try_get().unwrap().push(id as usize) {
println!("WARNING: WAKE_QUEUE full; dropping wakeup")
}
}
fn drop(_id: *const ()) {}
RawWaker::new( RawWaker::new(
ptr::null(), task_id as *const (),
&RawWakerVTable::new(clone, no_op, no_op, no_op), &RawWakerVTable::new(clone, wake, wake, drop),
) )
} }
fn waker() -> Waker { fn waker(task_id: usize) -> Waker {
unsafe { Waker::from_raw(raw_waker()) } unsafe { Waker::from_raw(raw_waker(task_id)) }
} }