diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 1988e43..67a43cb 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,6 +1,5 @@ mod process; pub mod thread; -pub mod scheduler; pub mod mgerror; pub mod system; mod ucontext; diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs deleted file mode 100644 index 7071fbb..0000000 --- a/src/kernel/scheduler.rs +++ /dev/null @@ -1,74 +0,0 @@ -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>>, - pub thread_manager: Option>> -} - -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>) { - 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>> { - 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>) { - 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"); - } - } -} \ No newline at end of file diff --git a/src/kernel/synch.rs b/src/kernel/synch.rs index 027cfce..af3f44e 100644 --- a/src/kernel/synch.rs +++ b/src/kernel/synch.rs @@ -1,3 +1,4 @@ +use crate::kernel::thread_manager; use crate::utility::list::List; use crate::kernel::thread::Thread; use crate::simulator::interrupt::InterruptStatus::InterruptOff; @@ -5,8 +6,6 @@ use crate::simulator::machine::Machine; use std::cell::RefCell; use std::rc::Rc; - -use super::scheduler::Scheduler; use super::system::System; use super::thread_manager::ThreadManager; @@ -17,8 +16,6 @@ pub struct Semaphore { counter:i32, /// QUeue of Semaphore waiting to be exucated waiting_queue:List>>, - /// Thread manager which managing threads - thread_manager: Rc> } @@ -29,8 +26,8 @@ impl Semaphore { /// ### Parameters /// - *counter* initial value of counter /// - *thread_manager* Thread manager which managing threads - pub fn new(counter: i32, thread_manager: Rc>) -> Semaphore{ - Semaphore { counter, waiting_queue: List::new(), thread_manager} + pub fn new(counter: i32) -> Semaphore{ + Semaphore { counter, waiting_queue: List::default() } } /// Decrement the value, and wait if it becomes < 0. Checking the @@ -40,17 +37,24 @@ impl Semaphore { /// Note that thread_manager::thread_sleep assumes that interrupts are disabled /// when it is called. /// - /// ### Parameters + /// ### Parameters TODO Refaire /// - *current_thread* the current thread /// - *machine* the machine where the threads are executed - pub fn p(&mut self, current_thread: Rc>, system: Rc>) { - let old_status = system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(InterruptOff); + pub fn p(&mut self, machine: &mut Machine, thread_manager: &mut ThreadManager) { + let old_status = machine.interrupt.set_status(InterruptOff); self.counter -= 1; if self.counter < 0 { - self.waiting_queue.push(Rc::clone(¤t_thread)); - self.thread_manager.borrow_mut().thread_sleep(current_thread); + match thread_manager.get_g_current_thread() { + Some(thread) => { + let rc1_thread = Rc::clone(thread); + let rc2_thread = Rc::clone(thread); + self.waiting_queue.push(rc1_thread); + thread_manager.thread_sleep(machine, rc2_thread); + }, + None => unreachable!("Current thread should not be None") + } } - system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(old_status); + machine.interrupt.set_status(old_status); } /// Increment semaphore value, waking up a waiting thread if any. @@ -63,13 +67,13 @@ impl Semaphore { /// ### Parameters /// - **machine** the machine where the threads are executed /// - **scheduler** the scheduler which determine which thread to execute - pub fn v(&mut self, system: Rc>){ - let old_status = system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(InterruptOff); + pub fn v(&mut self, machine: &mut Machine, thread_manager: &mut ThreadManager){ + let old_status = machine.interrupt.set_status(InterruptOff); self.counter += 1; if self.waiting_queue.peek() != None { - system.borrow_mut().get_thread_manager().borrow_mut().g_scheduler.ready_to_run(self.waiting_queue.pop().unwrap()); + thread_manager.ready_to_run(self.waiting_queue.pop().unwrap()); } - system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(old_status); + machine.interrupt.set_status(old_status); } } @@ -82,8 +86,6 @@ pub struct Lock{ owner: Option>>, /// The queue of threads waiting for execution waiting_queue:List>>, - /// Thread manager which managing threads - thread_manager: Rc>, /// A boolean definig if the lock is free or not free: bool @@ -96,8 +98,8 @@ impl Lock { /// /// ### Parameters /// - **thread_manager** Thread manager which managing threads - pub fn new(thread_manager: Rc>) -> Lock { - Lock { owner: None, waiting_queue: List::new(), thread_manager, free: true } + pub fn new() -> Lock { + Lock { owner: None, waiting_queue: List::default(), free: true } } /// Wait until the lock become free. Checking the @@ -111,23 +113,28 @@ impl Lock { /// ### Parameters /// - **current_thread** the current thread /// - **machine** the machine where the threads are executed - pub fn acquire(&mut self, current_thread: Option>>, system: Rc>) { - let old_status = system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(InterruptOff); - + pub fn acquire(&mut self, machine: &mut Machine, thread_manager: &mut ThreadManager) { + let old_status = machine.interrupt.set_status(InterruptOff); if self.free { self.free = false; - self.owner = current_thread; - } else { - match current_thread { - Some(x) => { - self.waiting_queue.push(Rc::clone(&x)); - self.thread_manager.borrow_mut().thread_sleep(x) + self.owner = Option::Some(match thread_manager.get_g_current_thread() { + Some(th) => { + Rc::clone(&th) }, - None => () + None => unreachable!() + }); + } else { + match thread_manager.get_g_current_thread() { + Some(x) => { + let x = Rc::clone(&x); + self.waiting_queue.push(Rc::clone(&x)); + thread_manager.thread_sleep(machine, Rc::clone(&x)); + }, + None => unreachable!("Current thread should not be None") } } - system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(old_status); + machine.interrupt.set_status(old_status); } /// Wake up a waiter if necessary, or release it if no thread is waiting. @@ -139,31 +146,37 @@ impl Lock { /// ### Parameters /// - **machine** the machine where the code is executed /// - **scheduler** the scheduler which determine which thread to execute - pub fn release(&mut self, system: Rc>, current_thread: Rc>) { - let old_status = system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(InterruptOff); + pub fn release(&mut self, machine: &mut Machine, thread_manager: &mut ThreadManager) { + let old_status = machine.interrupt.set_status(InterruptOff); - if self.held_by_current_thread(current_thread) { - if self.waiting_queue.peek() != None { - self.owner = Some(self.waiting_queue.pop().unwrap()); - let sys = system.borrow_mut(); - let tm = sys.get_thread_manager(); - let scheduler = &mut tm.borrow_mut().g_scheduler; - match &self.owner { - Some(x) => scheduler.ready_to_run(Rc::clone(&x)), - None => () + match thread_manager.get_g_current_thread() { + Some(thread) => { + if self.held_by_current_thread(thread_manager) { + if self.waiting_queue.peek() != None { + self.owner = Some(self.waiting_queue.pop().unwrap()); + match &self.owner { + Some(x) => thread_manager.ready_to_run(Rc::clone(&x)), + None => () + } + } else { + self.free = true; + self.owner = None; + } } - } else { - self.free = true; - self.owner = None; } + None => () } - system.borrow_mut().get_g_machine().borrow_mut().interrupt.set_status(old_status); + machine.interrupt.set_status(old_status); } - pub fn held_by_current_thread(&mut self, current_thread: Rc>) -> bool { + pub fn held_by_current_thread(&mut self, thread_manager: &mut ThreadManager) -> bool { match &self.owner { - Some(x) => Rc::ptr_eq(&x, ¤t_thread), + Some(x) => + match thread_manager.get_g_current_thread() { + Some(thread) => Rc::ptr_eq(&x, &thread), + None => false + } None => false } } @@ -174,8 +187,6 @@ pub struct Condition{ /// The queue of threads waiting for execution waiting_queue:List>>, - /// Thread manager which managing threads - thread_manager: Rc>, } @@ -185,8 +196,8 @@ impl Condition { /// /// ### Parameters /// - *thread_manager* Thread manager which managing threads - pub fn new(thread_manager: Rc>) -> Condition { - Condition{ waiting_queue: List::new(), thread_manager } + pub fn new() -> Condition { + Condition{ waiting_queue: List::default()} } /// Block the calling thread (put it in the wait queue). @@ -195,11 +206,17 @@ impl Condition { /// ### Parameters /// - **current_thread** the current thread /// - **machine** the machine where threads are executed - pub fn wait(&mut self, current_thread: Rc>, machine: &mut Machine) { + pub fn wait(&mut self, machine: &mut Machine, thread_manager: &mut ThreadManager) { let old_status = machine.interrupt.set_status(InterruptOff); - - self.waiting_queue.push(Rc::clone(¤t_thread)); - self.thread_manager.borrow_mut().thread_sleep(current_thread); + match thread_manager.get_g_current_thread() { + Some(thread) => { + let rc1 = Rc::clone(thread); + let rc2 = Rc::clone(thread); + self.waiting_queue.push(rc1); + thread_manager.thread_sleep(machine, rc2); + }, + None => unreachable!() + } machine.interrupt.set_status(old_status); } @@ -210,14 +227,14 @@ impl Condition { /// ### Parameters /// - **machine** the machine where the code is executed /// - **scheduler** the scheduler which determine which thread to execute - pub fn signal(&mut self, machine: &mut Machine, scheduler: &mut Scheduler) { - let old_status = machine.interrupt.set_status(InterruptOff); + pub fn signal(&mut self, system: &mut System) { + let old_status = system.get_machine().interrupt.set_status(InterruptOff); if self.waiting_queue.peek() != None { - scheduler.ready_to_run(self.waiting_queue.pop().unwrap()); + system.get_thread_manager().ready_to_run(self.waiting_queue.pop().unwrap()); } - machine.interrupt.set_status(old_status); + system.get_machine().interrupt.set_status(old_status); } @@ -227,13 +244,13 @@ impl Condition { /// ### Parameters /// - **machine** the machine where the code is executed /// - **scheduler** the scheduler which determine which thread to execute - pub fn broadcast(&mut self, machine: &mut Machine, scheduler: &mut Scheduler) { - let old_status = machine.interrupt.set_status(InterruptOff); + pub fn broadcast(&mut self, system: &mut System) { + let old_status = system.get_machine().interrupt.set_status(InterruptOff); while self.waiting_queue.peek() != None { - scheduler.ready_to_run(self.waiting_queue.pop().unwrap()); + system.get_thread_manager().ready_to_run(self.waiting_queue.pop().unwrap()); } - machine.interrupt.set_status(old_status); + system.get_machine().interrupt.set_status(old_status); } @@ -243,66 +260,68 @@ impl Condition { mod test { use std::{rc::Rc, cell::RefCell}; - use crate::{kernel::{thread::Thread, synch::{Semaphore, Lock}}, init_system, simulator::machine::Machine}; + use crate::{kernel::{thread::Thread, synch::{Semaphore, Lock}, thread_manager::ThreadManager}, init_system, simulator::machine::Machine}; #[test] fn test_semaphore_single() { // Init - let system = init_system!(); - let mut semaphore = Semaphore::new(1, Rc::clone(&system.borrow_mut().get_thread_manager())); + let mut machine = Machine::init_machine(); + let mut thread_manager = ThreadManager::new(); + let mut semaphore = Semaphore::new(1); let thread = Rc::new(RefCell::new(Thread::new("test_semaphore"))); + thread_manager.ready_to_run(Rc::clone(&thread)); + thread_manager.set_g_current_thread(Some(thread)); // P - semaphore.p(thread, Rc::clone(&system)); + semaphore.p(&mut machine, &mut thread_manager); assert_eq!(semaphore.counter, 0); assert!(semaphore.waiting_queue.is_empty()); // V - semaphore.v(Rc::clone(&system)); + semaphore.v(&mut machine, &mut thread_manager); assert_eq!(semaphore.counter, 1); assert!(semaphore.waiting_queue.is_empty()); } #[test] - #[ignore] fn test_semaphore_multiple() { // Init - let system = init_system!(); - let tm = system.borrow_mut().get_thread_manager(); - let mut semaphore = Semaphore::new(2, Rc::clone(&tm)); + let mut tm = ThreadManager::new(); + let mut machine = Machine::init_machine(); + let mut semaphore = Semaphore::new(2); let thread1 = Rc::new(RefCell::new(Thread::new("test_semaphore_1"))); let thread2 = Rc::new(RefCell::new(Thread::new("test_semaphore_2"))); let thread3 = Rc::new(RefCell::new(Thread::new("test_semaphore_3"))); - let mut borrow_tm = tm.borrow_mut(); - let scheduler = &mut borrow_tm.g_scheduler; - scheduler.ready_to_run(Rc::clone(&thread1)); - scheduler.ready_to_run(Rc::clone(&thread2)); - scheduler.ready_to_run(Rc::clone(&thread3)); + // let mut borrow_tm = tm.borrow_mut(); + // let scheduler = &mut tm.g_scheduler; + tm.ready_to_run(Rc::clone(&thread1)); + tm.ready_to_run(Rc::clone(&thread2)); + tm.ready_to_run(Rc::clone(&thread3)); // P - borrow_tm.set_g_current_thread(Some(Rc::clone(&thread1))); - semaphore.p(thread1, Rc::clone(&system)); + tm.set_g_current_thread(Some(Rc::clone(&thread1))); + semaphore.p(&mut machine, &mut tm); assert_eq!(semaphore.counter, 1); assert!(semaphore.waiting_queue.is_empty()); - borrow_tm.set_g_current_thread(Some(Rc::clone(&thread2))); - semaphore.p(thread2, Rc::clone(&system)); + tm.set_g_current_thread(Some(Rc::clone(&thread2))); + semaphore.p(&mut machine, &mut tm); assert_eq!(semaphore.counter, 0); assert!(semaphore.waiting_queue.is_empty()); - borrow_tm.set_g_current_thread(Some(Rc::clone(&thread3))); - semaphore.p(thread3, Rc::clone(&system)); + tm.set_g_current_thread(Some(Rc::clone(&thread3))); + semaphore.p(&mut machine, &mut tm); assert_eq!(semaphore.counter, -1); assert!(semaphore.waiting_queue.iter().count() == 1); // V - semaphore.v(Rc::clone(&system)); + semaphore.v(&mut machine, &mut tm); assert_eq!(semaphore.counter, 0); assert!(semaphore.waiting_queue.is_empty()); - semaphore.v(Rc::clone(&system)); + semaphore.v(&mut machine, &mut tm); assert_eq!(semaphore.counter, 1); assert!(semaphore.waiting_queue.is_empty()); - semaphore.v(Rc::clone(&system)); + semaphore.v(&mut machine, &mut tm); assert_eq!(semaphore.counter, 2); assert!(semaphore.waiting_queue.is_empty()); } @@ -310,61 +329,61 @@ mod test { #[test] - #[ignore] fn test_lock_simple() { - let system = init_system!(); - let sys = system.borrow_mut(); - let tm = sys.get_thread_manager(); + let mut machine = Machine::init_machine(); + let mut tm = ThreadManager::new(); let thread = Rc::new(RefCell::new(Thread::new("test_lock"))); - tm.borrow_mut().set_g_current_thread(Some(Rc::clone(&thread))); - let mut lock = Lock::new(Rc::clone(&tm)); + tm.ready_to_run(Rc::clone(&thread)); + tm.set_g_current_thread(Some(Rc::clone(&thread))); + let mut lock = Lock::new(); assert!(lock.free); - lock.acquire(Some(Rc::clone(&thread)), Rc::clone(&system)); - assert!(lock.held_by_current_thread(Rc::clone(&thread))); + lock.acquire(&mut machine, &mut tm); + assert!(lock.held_by_current_thread(&mut tm)); assert!(!lock.free); - lock.release(Rc::clone(&system), Rc::clone(&thread)); - assert!(!lock.held_by_current_thread(thread)); + lock.release(&mut machine, &mut tm); + assert!(!lock.held_by_current_thread(&mut tm)); assert!(lock.free); } #[test] - #[ignore] fn test_lock_multiple() { - let system = init_system!(); let thread1 = Rc::new(RefCell::new(Thread::new("test_lock1"))); let thread2 = Rc::new(RefCell::new(Thread::new("test_lock2"))); - let thread3 = Rc::new(RefCell::new(Thread::new("test_lock3"))); - let tm = system.borrow_mut().get_thread_manager(); - tm.borrow_mut().set_g_current_thread(Some(Rc::clone(&thread1))); - let mut lock = Lock::new(Rc::clone(&tm)); + let mut machine = Machine::init_machine(); + let mut tm = ThreadManager::new(); + + tm.ready_to_run(Rc::clone(&thread1)); + tm.ready_to_run(Rc::clone(&thread2)); + + tm.set_g_current_thread(Some(Rc::clone(&thread1))); + let mut lock = Lock::new(); assert!(lock.free); - lock.acquire(Some(Rc::clone(&thread1)), Rc::clone(&system)); - assert!(lock.held_by_current_thread(Rc::clone(&thread1))); + lock.acquire(&mut machine, &mut tm); + assert!(lock.held_by_current_thread(&mut tm)); assert!(!lock.free); - tm.borrow_mut().set_g_current_thread(Some(Rc::clone(&thread2))); - lock.acquire(Some(Rc::clone(&thread2)), Rc::clone(&system)); - tm.borrow_mut().set_g_current_thread(Some(Rc::clone(&thread1))); - + tm.set_g_current_thread(Some(Rc::clone(&thread2))); + lock.acquire(&mut machine, &mut tm); - assert!(lock.held_by_current_thread(Rc::clone(&thread1))); + + tm.set_g_current_thread(Some(Rc::clone(&thread1))); + assert!(lock.held_by_current_thread(&mut tm)); assert!(lock.waiting_queue.iter().count() == 1); assert!(!lock.free); - lock.release(Rc::clone(&system), Rc::clone(&thread1)); - assert!(!lock.held_by_current_thread(thread1)); - assert!(lock.held_by_current_thread(Rc::clone(&thread2))); + lock.release(&mut machine, &mut tm); + assert!(!lock.held_by_current_thread(&mut tm)); + + tm.set_g_current_thread(Some(Rc::clone(&thread2))); + assert!(lock.held_by_current_thread(&mut tm)); assert!(!lock.free); - tm.borrow_mut().set_g_current_thread(Some(Rc::clone(&thread2))); - - - lock.release(Rc::clone(&system), Rc::clone(&thread2)); - assert!(!lock.held_by_current_thread(thread2)); + lock.release(&mut machine, &mut tm); + assert!(!lock.held_by_current_thread(&mut tm)); assert!(lock.free); } } \ No newline at end of file diff --git a/src/kernel/system.rs b/src/kernel/system.rs index c7748e7..5bda557 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -2,11 +2,9 @@ //! //! Module containing structs and methods pertaining to the state of the operating system -use std::{cell::RefCell, rc::Rc}; - use crate::simulator::machine::Machine; -use super::thread_manager::ThreadManager; +use super::{thread_manager::ThreadManager}; /// This macro properly initializes the system #[macro_export] @@ -16,10 +14,7 @@ macro_rules! init_system { init_system!(m) }}; ($a:expr) => {{ - let sys = std::rc::Rc::new(std::cell::RefCell::new(crate::System::new($a))); - crate::System::freeze(std::rc::Rc::clone(&sys)); - sys - + $crate::System::new($a) }}; } @@ -35,8 +30,8 @@ macro_rules! init_system { /// - The scheduler which acts upon these threads #[derive(PartialEq)] pub struct System { - g_machine: RefCell, - thread_manager: Rc> + machine: Machine, + thread_manager: ThreadManager } impl System { @@ -44,37 +39,29 @@ impl System { /// System constructor pub fn new(machine: Machine) -> System { Self { - g_machine: RefCell::new(machine), - thread_manager: Rc::new(RefCell::new(ThreadManager::new())) + machine, + thread_manager: ThreadManager::new() } } - /// use thread_manager setter to send it system instance - pub fn freeze(this: Rc>) { - let copy = Rc::clone(&this); - let tm = &this.borrow_mut().thread_manager; - tm.borrow_mut().system = Option::Some(copy); - ThreadManager::freeze(tm); - } - // GETTERS /// Returns the Machine /// /// Useful to access RAM, devices, ... - pub fn get_g_machine(&self) -> &RefCell { - &self.g_machine + pub fn get_machine(&mut self) -> &mut Machine { + &mut self.machine } - pub fn get_thread_manager(&self) -> Rc> { - Rc::clone(&self.thread_manager) + pub fn get_thread_manager(&mut self) -> &mut ThreadManager { + &mut self.thread_manager } // Setters - /// Assign a machine to the system - pub fn set_g_machine(&mut self, machine: RefCell) { - self.g_machine = machine + /// Assign a machine to the system + pub fn set_machine(&mut self, machine: Machine) { + self.machine = machine } } @@ -92,7 +79,7 @@ pub enum ObjectType { #[cfg(test)] mod tests { - use crate::{System, Machine}; + use crate::Machine; #[test] fn test_init_system() { diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 43e9776..f5368cf 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -1,8 +1,8 @@ -use std::{rc::Rc, cell::{RefCell, RefMut, Ref}}; +use std::{rc::Rc, cell::{RefCell, Ref}}; -use crate::{utility::list::List, simulator::{machine::{NUM_INT_REGS, NUM_FP_REGS}, interrupt::InterruptStatus}}; +use crate::{utility::list::List, simulator::{machine::{NUM_INT_REGS, NUM_FP_REGS, Machine}, interrupt::InterruptStatus}}; -use super::{scheduler::Scheduler, thread::Thread, system::System, mgerror::ErrorCode, process::Process}; +use super::{thread::Thread, mgerror::ErrorCode, process::Process}; pub const SIMULATORSTACKSIZE: usize = 32 * 1024; @@ -17,10 +17,8 @@ pub struct ThreadManager { pub g_thread_to_be_destroyed: Option>>, /// The list of alive threads pub g_alive: List>>, - /// The thread scheduler - pub g_scheduler: Scheduler, - /// The system owning the thread manager - pub system: Option>> + /// Thread in ready state waiting to become active + ready_list: List>>, } impl ThreadManager { @@ -30,15 +28,59 @@ impl ThreadManager { Self { g_current_thread: Option::None, g_thread_to_be_destroyed: Option::None, - g_alive: List::new(), - g_scheduler: Scheduler::new(), - system: Option::None + g_alive: List::default(), + ready_list: List::default(), } } - pub fn freeze(this: &Rc>) { - let copy = Rc::clone(this); - this.borrow_mut().g_scheduler.thread_manager = Option::Some(copy); + /// 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>) { + 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>> { + 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, machine: &mut Machine, next_thread: Rc>) { + match self.get_g_current_thread() { + Some(old) => { + let old1 = Rc::clone(old); + let old2 = Rc::clone(old); + self.thread_save_processor_state(machine, old1); + // old_thread.save_simulator_state(); + if old2 != next_thread { + self.thread_restore_processor_state(machine, Rc::clone(&next_thread)); + // next_thread.restore_simulator_state(); + self.set_g_current_thread(Some(next_thread)); + } + }, + None => { + + } + } } /// Start a thread, attaching it to a process @@ -52,111 +94,84 @@ impl ThreadManager { thread_m.init_simulator_context(base_stack_addr); thread_m.process.as_mut().unwrap().num_thread += 1; self.get_g_alive().push(Rc::clone(&thread)); - self.g_scheduler.ready_to_run(Rc::clone(&thread)); + self.ready_to_run(Rc::clone(&thread)); Result::Ok(()) } /// Wait for another thread to finish its execution - pub fn thread_join(&mut self, id_thread: Rc>) { + pub fn thread_join(&mut self, machine: &mut Machine, id_thread: Rc>) { while self.get_g_alive().contains(&Rc::clone(&id_thread)) { - self.thread_yield(Rc::clone(&id_thread)); + self.thread_yield(machine, Rc::clone(&id_thread)); } } /// Relinquish the CPU if any other thread is runnable. /// /// Cannot use yield as a function name -> reserved name in rust - pub fn thread_yield(&mut self, thread: Rc>) { - if let Some(system) = &self.system { - let sys = system.borrow_mut(); - let mut machine = sys.get_g_machine().borrow_mut(); - let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff); + pub fn thread_yield(&mut self, machine: &mut Machine, thread: Rc>) { + let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff); - assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread); - let next_thread = self.g_scheduler.find_next_to_run(); - if let Some(next_thread) = next_thread { - let scheduler = &mut self.g_scheduler; - scheduler.ready_to_run(thread); - scheduler.switch_to(next_thread); - } - machine.interrupt.set_status(old_status); + assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread); + let next_thread = self.find_next_to_run(); + if let Some(next_thread) = next_thread { + self.ready_to_run(thread); + self.switch_to(machine, next_thread); } + machine.interrupt.set_status(old_status); } /// Put the thread to sleep and relinquish the processor - pub fn thread_sleep(&mut self, thread: Rc>) { - + pub fn thread_sleep(&mut self, machine: &mut Machine, thread: Rc>) { assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread); - if let Some(system) = &self.system { - let sys = system.borrow_mut(); - let machine = sys.get_g_machine().borrow_mut(); - assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff); + assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff); - let mut next_thread = self.g_scheduler.find_next_to_run(); - while next_thread.is_none() { - eprintln!("Nobody to run => idle"); - machine.interrupt.idle(); - next_thread = self.g_scheduler.find_next_to_run(); - } - self.g_scheduler.switch_to(Rc::clone(&next_thread.unwrap())); - + let mut next_thread = self.find_next_to_run(); + while next_thread.is_none() { + eprintln!("Nobody to run => idle"); + machine.interrupt.idle(); + next_thread = self.find_next_to_run(); } + self.switch_to(machine, Rc::clone(&next_thread.unwrap())); + } /// Finish the execution of the thread and prepare its deallocation - pub fn thread_finish(&mut self, thread: Rc>) { - if let Some(system) = &self.system { - let sys = Rc::clone(system); - let sys = sys.borrow_mut(); - let mut machine = sys.get_g_machine().borrow_mut(); - let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff); - self.g_thread_to_be_destroyed = Option::Some(Rc::clone(&thread)); - self.g_alive.remove(Rc::clone(&thread)); - // g_objets_addrs->removeObject(self.thread) // a ajouté plus tard - self.thread_sleep(Rc::clone(&thread)); - machine.interrupt.set_status(old_status); + pub fn thread_finish(&mut self, machine: &mut Machine, thread: Rc>) { + let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff); + self.g_thread_to_be_destroyed = Option::Some(Rc::clone(&thread)); + self.g_alive.remove(Rc::clone(&thread)); + // g_objets_addrs->removeObject(self.thread) // a ajouté plus tard + self.thread_sleep(machine, Rc::clone(&thread)); + machine.interrupt.set_status(old_status); + } + + pub fn thread_save_processor_state(&mut self, machine: &mut Machine, thread: Rc>) { + let mut t = thread.borrow_mut(); + for i in 0..NUM_INT_REGS { + t.thread_context.int_registers[i] = machine.read_int_register(i); + } + for i in 0..NUM_FP_REGS { + t.thread_context.float_registers[i] = machine.read_fp_register(i); } } - pub fn thread_save_processor_state(&mut self, thread: Rc>) { - if let Some(system) = &self.system { - let mut t: RefMut<_> = thread.borrow_mut(); - let system = system.borrow_mut(); - for i in 0..NUM_INT_REGS { - t.thread_context.int_registers[i] = system.get_g_machine().borrow().read_int_register(i); - } - for i in 0..NUM_FP_REGS { - t.thread_context.float_registers[i] = system.get_g_machine().borrow().read_fp_register(i); - } - } else { - unreachable!("System is None") - } - } - - pub fn thread_restore_processor_state(&self, thread: Rc>) { - if let Some(system) = &self.system { - let system = system.borrow_mut(); - let t: Ref<_> = thread.borrow(); - for i in 0..NUM_INT_REGS { - let machine = system.get_g_machine(); - let mut machine = machine.borrow_mut(); - machine.write_int_register(i, t.thread_context.int_registers[i]); - } - } else { - unreachable!("System is None") + pub fn thread_restore_processor_state(&self, machine: &mut Machine, thread: Rc>) { + let t: Ref<_> = thread.borrow(); + for i in 0..NUM_INT_REGS { + machine.write_int_register(i, t.thread_context.int_registers[i]); } } /// Currently running thread - pub fn get_g_current_thread(&mut self) -> &mut Option>> { - &mut self.g_current_thread + pub fn get_g_current_thread(&mut self) -> &Option>> { + &self.g_current_thread } /// Thread to be destroyed by [...] /// /// TODO: Finish the comment with the relevant value - pub fn get_g_thread_to_be_destroyed(&mut self) -> &mut Option>> { - &mut self.g_thread_to_be_destroyed + pub fn get_g_thread_to_be_destroyed(&mut self) -> &Option>> { + &self.g_thread_to_be_destroyed } /// List of alive threads diff --git a/src/main.rs b/src/main.rs index e556b8e..b35b860 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,4 @@ use simulator::machine::Machine; fn main() { let machine = Machine::init_machine(); let system = Rc::new(RefCell::new(System::new(machine))); - - System::freeze(system); } diff --git a/src/utility/list.rs b/src/utility/list.rs index bfb3207..801a74e 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -1,62 +1,88 @@ //! Data structure and definition of a genericsingle-linked LIFO list. +use std::ptr; + #[derive(PartialEq)] pub struct List { head: Link, + tail: *mut Node, } +type Link = *mut Node; -type Link = Option>>; #[derive(PartialEq)] struct Node { elem: T, next: Link, } +/// Iterator structure for use in a for loop, pop elements before returning it +pub struct IntoIter(List); + +/// Iterator structure for use in a for loop, dereference before returning it +pub struct Iter<'a, T> { + next: Option<&'a Node>, +} + +/// Same as Iter structure, returned item are mutable +pub struct IterMut<'a, T> { + next: Option<&'a mut Node>, +} impl List { - /// Create an empty list - pub fn new() -> Self { - List { head: None } - } - /// Push an item at the end of the list pub fn push(&mut self, elem: T) { - let new_node = Box::new(Node { - elem: elem, - next: self.head.take(), - }); + unsafe { + let new_tail = Box::into_raw(Box::new(Node { + elem, + next: ptr::null_mut(), + })); - self.head = Some(new_node); + if !self.tail.is_null() { + (*self.tail).next = new_tail; + } else { + self.head = new_tail; + } + + self.tail = new_tail; + } } - /// Retrieve and remove the item at the end of the list. + /// Retrieve and remove the item at the head of the list. /// /// Return None if list is empty pub fn pop(&mut self) -> Option { - self.head.take().map(|node| { - self.head = node.next; - node.elem - }) + unsafe { + if self.head.is_null() { + None + } else { + let head = Box::from_raw(self.head); + self.head = head.next; + if self.head.is_null() { + self.tail = ptr::null_mut(); + } + Some(head.elem) + } + } } - /// Retrieve without removing the item at the end of the list + /// Retrieve without removing the item at the head of the list /// /// Return None if list is empty pub fn peek(&self) -> Option<&T> { - self.head.as_ref().map(|node| { - &node.elem - }) + unsafe { + self.head.as_ref().map(|node| &node.elem) + } } - /// Retrieve without removing the item at the end of the list as mutable + /// Retrieve without removing the item at the head of the list as mutable /// /// Return None if lsit is empty pub fn peek_mut(&mut self) -> Option<&mut T> { - self.head.as_mut().map(|node| { - &mut node.elem - }) + unsafe { + self.head.as_mut().map(|node| &mut node.elem) + } } /// Search for an element in the list @@ -66,10 +92,12 @@ impl List { /// Worst case complexity of this function is O(n) pub fn contains(&self, elem: &T) -> bool { let mut iter = self.iter(); - let element = iter.next(); + let mut element = iter.next(); while element.is_some() { if element.unwrap() == elem { return true; + } else { + element = iter.next(); } } false @@ -81,26 +109,26 @@ impl List { /// /// Worst-case complexity is O(n) pub fn remove(&mut self, item: T)-> bool { - let mut found = false; - let mut tmp_list: List = List::new(); - while !self.is_empty() { - let current = self.pop().unwrap(); - if current != item { - tmp_list.push(current); - } else { - found = true; - break; + unsafe { + let mut current: *mut Node = self.head; + let mut previous: *mut Node = ptr::null_mut(); + while !current.is_null() { + if (*current).elem == item { + (*previous).next = (*current).next; + drop(Box::from_raw(current).elem); + return true; + } else { + previous = current; + current = (*current).next; + } } } - while !tmp_list.is_empty() { - self.push(tmp_list.pop().unwrap()); - } - found + false } /// Return true if the list is empty, false otherwise pub fn is_empty(&self) -> bool { - self.head.is_none() + self.head.is_null() } /// Turn the list into an iterator for use in a for loop per example. @@ -114,27 +142,34 @@ impl List { /// /// When you iter using this method, elements are dereferenced pub fn iter(&self) -> Iter<'_, T> { - Iter { next: self.head.as_deref() } + unsafe { + Iter { next: self.head.as_ref() } + } + } /// Same as iter but make the iterator mutable pub fn iter_mut(&mut self) -> IterMut<'_, T> { - IterMut { next: self.head.as_deref_mut() } + unsafe { + IterMut { next: self.head.as_mut() } + } + + } +} + +impl Default for List { + /// Create an empty list + fn default() -> Self { + Self { head: ptr::null_mut(), tail: ptr::null_mut() } } } impl Drop for List { fn drop(&mut self) { - let mut cur_link = self.head.take(); - while let Some(mut boxed_node) = cur_link { - cur_link = boxed_node.next.take(); - } + while self.pop().is_some() {} // removing every item from list (necessary as we using unsafe function) } } -/// Iterator structure for use in a for loop, pop elements before returning it -pub struct IntoIter(List); - impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { @@ -143,34 +178,31 @@ impl Iterator for IntoIter { } } -/// Iterator structure for use in a for loop, dereference before returning it -pub struct Iter<'a, T> { - next: Option<&'a Node>, -} impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; - fn next(&mut self) -> Option { - self.next.map(|node| { - self.next = node.next.as_deref(); - &node.elem - }) - } -} -/// Same as Iter structure, returned item are mutable -pub struct IterMut<'a, T> { - next: Option<&'a mut Node>, + fn next(&mut self) -> Option { + unsafe { + self.next.map(|node| { + self.next = node.next.as_ref(); + &node.elem + }) + } + } } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; fn next(&mut self) -> Option { - self.next.take().map(|node| { - self.next = node.next.as_deref_mut(); - &mut node.elem - }) + unsafe { + self.next.take().map(|node| { + self.next = node.next.as_mut(); + &mut node.elem + }) + } + } } @@ -180,7 +212,7 @@ mod test { #[test] fn basics() { - let mut list = List::new(); + let mut list = List::default(); // Check empty list behaves right assert_eq!(list.pop(), None); @@ -191,7 +223,7 @@ mod test { list.push(3); // Check normal removal - assert_eq!(list.pop(), Some(3)); + assert_eq!(list.pop(), Some(1)); assert_eq!(list.pop(), Some(2)); // Push some more just to make sure nothing's corrupted @@ -199,63 +231,128 @@ mod test { list.push(5); // Check normal removal - assert_eq!(list.pop(), Some(5)); + assert_eq!(list.pop(), Some(3)); assert_eq!(list.pop(), Some(4)); // Check exhaustion - assert_eq!(list.pop(), Some(1)); + assert_eq!(list.pop(), Some(5)); assert_eq!(list.pop(), None); } #[test] fn peek() { - let mut list = List::new(); + let mut list = List::default(); assert_eq!(list.peek(), None); assert_eq!(list.peek_mut(), None); - list.push(1); list.push(2); list.push(3); + list.push(1); + list.push(2); + list.push(3); - assert_eq!(list.peek(), Some(&3)); - assert_eq!(list.peek_mut(), Some(&mut 3)); - - list.peek_mut().map(|value| { - *value = 42 - }); - - assert_eq!(list.peek(), Some(&42)); - assert_eq!(list.pop(), Some(42)); + assert_eq!(list.peek(), Some(&1)); + assert_eq!(list.peek_mut(), Some(&mut 1)); } #[test] fn into_iter() { - let mut list = List::new(); - list.push(1); list.push(2); list.push(3); + let mut list = List::default(); + list.push(1); + list.push(2); + list.push(3); let mut iter = list.into_iter(); - assert_eq!(iter.next(), Some(3)); - assert_eq!(iter.next(), Some(2)); assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(3)); assert_eq!(iter.next(), None); } #[test] fn iter() { - let mut list = List::new(); - list.push(1); list.push(2); list.push(3); + let mut list = List::default(); + list.push(1); + list.push(2); + list.push(3); let mut iter = list.iter(); - assert_eq!(iter.next(), Some(&3)); - assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), Some(&1)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&3)); } #[test] fn iter_mut() { - let mut list = List::new(); - list.push(1); list.push(2); list.push(3); + let mut list = List::default(); + list.push(1); + list.push(2); + list.push(3); let mut iter = list.iter_mut(); - assert_eq!(iter.next(), Some(&mut 3)); - assert_eq!(iter.next(), Some(&mut 2)); assert_eq!(iter.next(), Some(&mut 1)); + assert_eq!(iter.next(), Some(&mut 2)); + assert_eq!(iter.next(), Some(&mut 3)); + } + + #[test] + fn contains_test() { + let mut list = List::default(); + assert_eq!(list.peek(), None); + list.push(1); + list.push(2); + list.push(3); + + assert_eq!(list.contains(&1), true); + assert_eq!(list.contains(&4), false); + } + + #[test] + fn remove_test() { + let mut list = List::default(); + assert_eq!(list.peek(), None); + list.push(1); + list.push(2); + list.push(3); + + assert_eq!(list.contains(&2), true); + list.remove(2); + assert_eq!(list.contains(&2), false); + assert_eq!(list.pop(), Option::Some(1)); + assert_eq!(list.pop(), Option::Some(3)); + assert_eq!(list.peek(), Option::None); + } + + #[test] + fn miri_test() { + let mut list = List::default(); + + list.push(1); + list.push(2); + list.push(3); + + assert!(list.pop() == Some(1)); + list.push(4); + assert!(list.pop() == Some(2)); + list.push(5); + + assert!(list.peek() == Some(&3)); + list.push(6); + list.peek_mut().map(|x| *x *= 10); + assert!(list.peek() == Some(&30)); + assert!(list.pop() == Some(30)); + + for elem in list.iter_mut() { + *elem *= 100; + } + + let mut iter = list.iter(); + assert_eq!(iter.next(), Some(&400)); + assert_eq!(iter.next(), Some(&500)); + assert_eq!(iter.next(), Some(&600)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next(), None); + + assert!(list.pop() == Some(400)); + list.peek_mut().map(|x| *x *= 10); + assert!(list.peek() == Some(&5000)); + list.push(7); } } \ No newline at end of file