add basic yield executor
All checks were successful
continuous-integration/drone/push Build is passing

Signed-off-by: Julien CLEMENT <julien.clement@epita.fr>
This commit is contained in:
Julien CLEMENT 2023-01-06 18:42:12 +01:00
parent 87ba7f2ab4
commit 77a7f1229c
4 changed files with 127 additions and 17 deletions

@ -1,7 +1,7 @@
use crate::println; use crate::println;
use crate::proc::thread::{resume_k_thread, RUNNING_THREAD}; use crate::proc::thread::{resume_k_thread, RUNNING_THREAD};
use crate::proc::scheduler::SCHEDULER; use crate::proc::scheduler::SCHEDULER;
use crate::task::executor::EXECUTOR; use crate::task::yield_executor::YieldExecutor;
use crate::task::Task; use crate::task::Task;
pub use ids::*; pub use ids::*;
@ -25,8 +25,6 @@ impl SyscallContext {
pub async fn run(&mut self) { pub async fn run(&mut self) {
println!("Running async syscall runner for {:?}", self.id); println!("Running async syscall runner for {:?}", self.id);
self.dispatch().await; self.dispatch().await;
println!("Syscall {:?} end, unblocking thread", self.id);
SCHEDULER.lock().await.unblock(self.thread_id);
} }
pub async fn dispatch(&mut self) { pub async fn dispatch(&mut self) {
@ -51,18 +49,9 @@ pub fn syscall_routine(syscall_id: SyscallId) -> u64 {
})); }));
println!("Spawning async syscall runner"); println!("Spawning async syscall runner");
EXECUTOR let mut executor = YieldExecutor::new(context.borrow().thread_id);
.try_lock() executor.spawn(Task::new(syscall_runner(context.clone())));
.unwrap() executor.run();
.spawn(Task::new(syscall_runner(context.clone())));
println!("Blocking thread");
SCHEDULER
.try_lock()
.unwrap()
.block(context.borrow().thread_id);
println!("Returning to scheduler");
resume_k_thread();
let res = context.borrow().res; let res = context.borrow().res;
res res

@ -1,10 +1,11 @@
use crate::println; use crate::println;
use crate::proc::scheduler::SCHEDULER; use crate::proc::scheduler::SCHEDULER;
use crate::proc::thread::resume_k_thread;
use super::SyscallContext; use super::SyscallContext;
pub async fn exit(context: &SyscallContext) { pub async fn exit(context: &SyscallContext) {
println!("Running exit(2)"); println!("Running exit(2)");
let mut scheduler = SCHEDULER.lock().await; SCHEDULER.lock().await.exit(context.thread_id);
scheduler.exit(context.thread_id); resume_k_thread();
} }

@ -5,6 +5,7 @@ use core::sync::atomic::{AtomicU64, Ordering};
use core::task::{Context, Poll}; use core::task::{Context, Poll};
pub mod executor; pub mod executor;
pub mod yield_executor;
pub mod keyboard; pub mod keyboard;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]

119
src/task/yield_executor.rs Normal file

@ -0,0 +1,119 @@
use crate::println;
use crate::proc::thread::{ThreadId, resume_k_thread};
use crate::proc::scheduler::SCHEDULER;
use super::{Task, TaskId};
use alloc::{collections::BTreeMap, sync::Arc, task::Wake};
use core::task::{Context, Poll, Waker};
use crossbeam_queue::ArrayQueue;
pub struct YieldExecutor {
tasks: BTreeMap<TaskId, Task>,
task_queue: Arc<ArrayQueue<TaskId>>,
waker_cache: BTreeMap<TaskId, Waker>,
thread_id: ThreadId,
}
impl YieldExecutor {
pub fn new(thread_id: ThreadId) -> Self {
YieldExecutor {
tasks: BTreeMap::new(),
task_queue: Arc::new(ArrayQueue::new(100)),
waker_cache: BTreeMap::new(),
thread_id: thread_id,
}
}
pub fn run(&mut self) {
loop {
self.run_ready_tasks();
if self.done() {
break;
} else {
println!("Blocking thread");
SCHEDULER
.try_lock()
.unwrap()
.block(self.thread_id);
println!("Returning to scheduler");
resume_k_thread();
}
}
}
fn done(&self) -> bool {
self.tasks.is_empty()
}
pub fn spawn(&mut self, task: Task) {
let task_id = task.id;
if self.tasks.insert(task.id, task).is_some() {
panic!("Duplicate task ID");
}
self.task_queue.push(task_id).expect("Task queue full");
}
fn run_ready_tasks(&mut self) {
let Self {
tasks,
task_queue,
waker_cache,
thread_id,
} = self; // Executor destructuring
while let Ok(task_id) = task_queue.pop() {
let task = match tasks.get_mut(&task_id) {
Some(task) => task,
None => continue, // Task does not exist anymore
};
let waker = waker_cache
.entry(task_id)
.or_insert_with(|| YieldTaskWaker::new(task_id, task_queue.clone(), *thread_id));
let mut context = Context::from_waker(waker);
match task.poll(&mut context) {
Poll::Ready(()) => {
// task is done
tasks.remove(&task_id);
waker_cache.remove(&task_id);
}
Poll::Pending => {}
}
}
}
}
struct YieldTaskWaker {
task_id: TaskId,
task_queue: Arc<ArrayQueue<TaskId>>,
thread_id: ThreadId,
}
impl YieldTaskWaker {
fn new(task_id: TaskId, task_queue: Arc<ArrayQueue<TaskId>>, thread_id: ThreadId) -> Waker {
Waker::from(Arc::new(YieldTaskWaker {
task_id,
task_queue,
thread_id
}))
}
fn wake_task(&self) {
self.task_queue.push(self.task_id).expect("Task queue full");
SCHEDULER
.try_lock()
.unwrap()
.unblock(self.thread_id);
}
}
impl Wake for YieldTaskWaker {
fn wake(self: Arc<Self>) {
self.wake_task();
}
fn wake_by_ref(self: &Arc<Self>) {
self.wake_task();
}
}