Compare commits

...

2 Commits

Author SHA1 Message Date
957e767dfc add todos
Some checks reported errors
continuous-integration/drone/push Build is passing
continuous-integration/drone Build encountered an error
Signed-off-by: Julien CLEMENT <julien.clement@epita.fr>
2023-01-07 16:06:05 +01:00
77a7f1229c add basic yield executor
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: Julien CLEMENT <julien.clement@epita.fr>
2023-01-06 18:42:12 +01:00
7 changed files with 131 additions and 17 deletions

@ -9,6 +9,7 @@ pub fn gettick() -> u64 {
}
pub extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
// TODO: thread preemption
unsafe {
TICKS += 1;
PICS.lock()

@ -15,6 +15,7 @@ use futures_util::task::AtomicWaker;
use lazy_static::lazy_static;
lazy_static! {
// TODO: put this in a spin mutex instead
pub static ref SCHEDULER: AsyncMutex<Scheduler> = AsyncMutex::new(Scheduler::new());
}
@ -23,6 +24,7 @@ pub type Threadt = Arc<RefCell<Thread>>;
pub const K_THREAD_ID: ThreadId = ThreadId(0); // Kernel main thread identifier
struct ThreadStream {
// TODO: add the double scheduler queue
ids: ArrayQueue<ThreadId>,
waker: AtomicWaker,
}

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

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

@ -5,6 +5,7 @@ use core::sync::atomic::{AtomicU64, Ordering};
use core::task::{Context, Poll};
pub mod executor;
pub mod yield_executor;
pub mod keyboard;
#[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();
}
}

@ -11,6 +11,7 @@ use futures_util::task::AtomicWaker;
#[derive(Clone)]
struct Lock {
lock: Arc<AtomicBool>,
// TODO: Make a queue of wakers
waker: Arc<AtomicWaker>,
}