Skip to content

Commit f118749

Browse files
authored
Merge pull request phil-opp#804 from phil-opp/post-12-merge-queues
Simplify executor by merging task_queue and wake_queue
2 parents b862534 + 9887c12 commit f118749

File tree

1 file changed

+39
-49
lines changed

1 file changed

+39
-49
lines changed

src/task/executor.rs

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,93 @@
11
use super::{Task, TaskId};
2-
use alloc::{
3-
collections::{BTreeMap, VecDeque},
4-
sync::Arc,
5-
task::Wake,
6-
};
2+
use alloc::{collections::BTreeMap, sync::Arc, task::Wake};
73
use core::task::{Context, Poll, Waker};
84
use crossbeam_queue::ArrayQueue;
95

106
pub struct Executor {
11-
task_queue: VecDeque<Task>,
12-
waiting_tasks: BTreeMap<TaskId, Task>,
13-
wake_queue: Arc<ArrayQueue<TaskId>>,
7+
tasks: BTreeMap<TaskId, Task>,
8+
task_queue: Arc<ArrayQueue<TaskId>>,
149
waker_cache: BTreeMap<TaskId, Waker>,
1510
}
1611

1712
impl Executor {
1813
pub fn new() -> Self {
1914
Executor {
20-
task_queue: VecDeque::new(),
21-
waiting_tasks: BTreeMap::new(),
22-
wake_queue: Arc::new(ArrayQueue::new(100)),
15+
tasks: BTreeMap::new(),
16+
task_queue: Arc::new(ArrayQueue::new(100)),
2317
waker_cache: BTreeMap::new(),
2418
}
2519
}
2620

2721
pub fn spawn(&mut self, task: Task) {
28-
self.task_queue.push_back(task)
22+
let task_id = task.id;
23+
if self.tasks.insert(task.id, task).is_some() {
24+
panic!("task with same ID already in tasks");
25+
}
26+
self.task_queue.push(task_id).expect("queue full");
2927
}
3028

3129
pub fn run(&mut self) -> ! {
3230
loop {
33-
self.wake_tasks();
3431
self.run_ready_tasks();
3532
self.sleep_if_idle();
3633
}
3734
}
3835

3936
fn run_ready_tasks(&mut self) {
40-
while let Some(mut task) = self.task_queue.pop_front() {
41-
let task_id = task.id;
42-
if !self.waker_cache.contains_key(&task_id) {
43-
self.waker_cache.insert(task_id, self.create_waker(task_id));
44-
}
45-
let waker = self.waker_cache.get(&task_id).expect("should exist");
37+
// destructure `self` to avoid borrow checker errors
38+
let Self {
39+
tasks,
40+
task_queue,
41+
waker_cache,
42+
} = self;
43+
44+
while let Ok(task_id) = task_queue.pop() {
45+
let task = match tasks.get_mut(&task_id) {
46+
Some(task) => task,
47+
None => continue, // task no longer exists
48+
};
49+
let waker = waker_cache
50+
.entry(task_id)
51+
.or_insert_with(|| TaskWaker::new(task_id, task_queue.clone()));
4652
let mut context = Context::from_waker(waker);
4753
match task.poll(&mut context) {
4854
Poll::Ready(()) => {
49-
// task done -> remove cached waker
50-
self.waker_cache.remove(&task_id);
55+
// task done -> remove it and its cached waker
56+
tasks.remove(&task_id);
57+
waker_cache.remove(&task_id);
5158
}
52-
Poll::Pending => {
53-
if self.waiting_tasks.insert(task_id, task).is_some() {
54-
panic!("task with same ID already in waiting_tasks");
55-
}
56-
}
57-
}
58-
}
59-
}
60-
61-
fn wake_tasks(&mut self) {
62-
while let Ok(task_id) = self.wake_queue.pop() {
63-
if let Some(task) = self.waiting_tasks.remove(&task_id) {
64-
self.task_queue.push_back(task);
59+
Poll::Pending => {}
6560
}
6661
}
6762
}
6863

6964
fn sleep_if_idle(&self) {
7065
use x86_64::instructions::interrupts::{self, enable_interrupts_and_hlt};
7166

72-
// fast path
73-
if !self.wake_queue.is_empty() {
74-
return;
75-
}
76-
7767
interrupts::disable();
78-
if self.wake_queue.is_empty() {
68+
if self.task_queue.is_empty() {
7969
enable_interrupts_and_hlt();
8070
} else {
8171
interrupts::enable();
8272
}
8373
}
84-
85-
fn create_waker(&self, task_id: TaskId) -> Waker {
86-
Waker::from(Arc::new(TaskWaker {
87-
task_id,
88-
wake_queue: self.wake_queue.clone(),
89-
}))
90-
}
9174
}
9275

9376
struct TaskWaker {
9477
task_id: TaskId,
95-
wake_queue: Arc<ArrayQueue<TaskId>>,
78+
task_queue: Arc<ArrayQueue<TaskId>>,
9679
}
9780

9881
impl TaskWaker {
82+
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>) -> Waker {
83+
Waker::from(Arc::new(TaskWaker {
84+
task_id,
85+
task_queue,
86+
}))
87+
}
88+
9989
fn wake_task(&self) {
100-
self.wake_queue.push(self.task_id).expect("wake_queue full");
90+
self.task_queue.push(self.task_id).expect("task_queue full");
10191
}
10292
}
10393

0 commit comments

Comments
 (0)