Skip to content

Commit 50b4b89

Browse files
committed
Implement an executor with waker support
1 parent d7b1443 commit 50b4b89

File tree

4 files changed

+112
-8
lines changed

4 files changed

+112
-8
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(const_fn)]
77
#![feature(alloc_layout_extra)]
88
#![feature(const_in_array_repeat_expressions)]
9+
#![feature(wake_trait)]
910
#![test_runner(crate::test_runner)]
1011
#![reexport_test_harness_main = "test_main"]
1112

src/main.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
extern crate alloc;
88

99
use blog_os::println;
10-
use blog_os::task::{keyboard, simple_executor::SimpleExecutor, Task};
10+
use blog_os::task::{executor::Executor, keyboard, Task};
1111
use bootloader::{entry_point, BootInfo};
1212
use core::panic::PanicInfo;
1313

@@ -27,16 +27,13 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
2727

2828
allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
2929

30-
let mut executor = SimpleExecutor::new();
31-
executor.spawn(Task::new(example_task()));
32-
executor.spawn(Task::new(keyboard::print_keypresses()));
33-
executor.run();
34-
3530
#[cfg(test)]
3631
test_main();
3732

38-
println!("It did not crash!");
39-
blog_os::hlt_loop();
33+
let mut executor = Executor::new();
34+
executor.spawn(Task::new(example_task()));
35+
executor.spawn(Task::new(keyboard::print_keypresses()));
36+
executor.run();
4037
}
4138

4239
/// This function is called on panic.

src/task/executor.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use super::{Task, TaskId};
2+
use alloc::{
3+
collections::{BTreeMap, VecDeque},
4+
sync::Arc,
5+
task::Wake,
6+
};
7+
use core::task::{Context, Poll, Waker};
8+
use crossbeam_queue::ArrayQueue;
9+
10+
pub struct Executor {
11+
task_queue: VecDeque<Task>,
12+
waiting_tasks: BTreeMap<TaskId, Task>,
13+
wake_queue: Arc<ArrayQueue<TaskId>>,
14+
waker_cache: BTreeMap<TaskId, Waker>,
15+
}
16+
17+
impl Executor {
18+
pub fn new() -> Self {
19+
Executor {
20+
task_queue: VecDeque::new(),
21+
waiting_tasks: BTreeMap::new(),
22+
wake_queue: Arc::new(ArrayQueue::new(100)),
23+
waker_cache: BTreeMap::new(),
24+
}
25+
}
26+
27+
pub fn spawn(&mut self, task: Task) {
28+
self.task_queue.push_back(task)
29+
}
30+
31+
pub fn run(&mut self) -> ! {
32+
loop {
33+
self.wake_tasks();
34+
self.run_ready_tasks();
35+
}
36+
}
37+
38+
fn run_ready_tasks(&mut self) {
39+
while let Some(mut task) = self.task_queue.pop_front() {
40+
let task_id = task.id();
41+
if !self.waker_cache.contains_key(&task_id) {
42+
self.waker_cache.insert(task_id, self.create_waker(task_id));
43+
}
44+
let waker = self.waker_cache.get(&task_id).expect("should exist");
45+
let mut context = Context::from_waker(waker);
46+
match task.poll(&mut context) {
47+
Poll::Ready(()) => {
48+
// task done -> remove cached waker
49+
self.waker_cache.remove(&task_id);
50+
}
51+
Poll::Pending => {
52+
if self.waiting_tasks.insert(task_id, task).is_some() {
53+
panic!("task with same ID already in waiting_tasks");
54+
}
55+
}
56+
}
57+
}
58+
}
59+
60+
fn wake_tasks(&mut self) {
61+
while let Ok(task_id) = self.wake_queue.pop() {
62+
if let Some(task) = self.waiting_tasks.remove(&task_id) {
63+
self.task_queue.push_back(task);
64+
}
65+
}
66+
}
67+
68+
fn create_waker(&self, task_id: TaskId) -> Waker {
69+
Waker::from(Arc::new(TaskWaker {
70+
task_id,
71+
wake_queue: self.wake_queue.clone(),
72+
}))
73+
}
74+
}
75+
76+
struct TaskWaker {
77+
task_id: TaskId,
78+
wake_queue: Arc<ArrayQueue<TaskId>>,
79+
}
80+
81+
impl TaskWaker {
82+
fn wake_task(&self) {
83+
self.wake_queue.push(self.task_id).expect("wake_queue full");
84+
}
85+
}
86+
87+
impl Wake for TaskWaker {
88+
fn wake(self: Arc<Self>) {
89+
self.wake_task();
90+
}
91+
92+
fn wake_by_ref(self: &Arc<Self>) {
93+
self.wake_task();
94+
}
95+
}

src/task/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use core::{
55
task::{Context, Poll},
66
};
77

8+
pub mod executor;
89
pub mod keyboard;
910
pub mod simple_executor;
1011

@@ -22,4 +23,14 @@ impl Task {
2223
fn poll(&mut self, context: &mut Context) -> Poll<()> {
2324
self.future.as_mut().poll(context)
2425
}
26+
27+
fn id(&self) -> TaskId {
28+
use core::ops::Deref;
29+
30+
let addr = Pin::deref(&self.future) as *const _ as *const () as usize;
31+
TaskId(addr)
32+
}
2533
}
34+
35+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
36+
struct TaskId(usize);

0 commit comments

Comments
 (0)