use std::cell::RefCell; use std::rc::Rc; use crate::utility::list::List; use crate::kernel::thread::Thread; use super::thread_manager::ThreadManager; #[derive(PartialEq)] pub struct Scheduler { ready_list: List<Rc<RefCell<Thread>>>, pub thread_manager: Option<Rc<RefCell<ThreadManager>>> } impl Scheduler { /// Constructor /// /// Initilize the list of ready thread pub fn new() -> Self { Self { ready_list: List::new(), thread_manager: Option::None } } /// Mark a thread as aready, but not necessarily running yet. /// /// Put it in the ready list, for later scheduling onto the CPU. /// /// ## Pamameter /// /// **thread** is the thread to be put on the read list pub fn ready_to_run(&mut self, thread: Rc<RefCell<Thread>>) { self.ready_list.push(thread); } /// Return the next thread to be scheduled onto the CPU. /// If there are no ready threads, return Option::None /// /// Thread is removed from the ready list. /// /// **return** Thread thread to be scheduled pub fn find_next_to_run(&mut self) -> Option<Rc<RefCell<Thread>>> { self.ready_list.pop() } /// Dispatch the CPU to next_thread. Save the state of the old thread /// and load the state of the new thread. /// /// We assume the state of the previously running thread has already been changed from running to blocked or ready. /// /// Global variable g_current_thread become next_thread /// /// ## Parameter /// /// **next_thread** thread to dispatch to the CPU pub fn switch_to(&mut self, next_thread: Rc<RefCell<Thread>>) { if let Some(tm) = &self.thread_manager { let rc = Rc::clone(&tm); if let Some(old_thread) = tm.borrow_mut().get_g_current_thread() { rc.borrow_mut().thread_save_processor_state(Rc::clone(&old_thread)); // old_thread.save_simulator_state(); if old_thread != &next_thread { rc.borrow_mut().thread_restore_processor_state(Rc::clone(&next_thread)); // next_thread.restore_simulator_state(); rc.borrow_mut().set_g_current_thread(Option::Some(next_thread)); } } } else { panic!("thread manager shouldn't be none"); } } }