diff --git a/src/kernel/synch.rs b/src/kernel/synch.rs index e4600ac..bd63803 100644 --- a/src/kernel/synch.rs +++ b/src/kernel/synch.rs @@ -27,53 +27,7 @@ impl Semaphore { pub fn new(counter: i32) -> Semaphore{ Semaphore { counter, waiting_queue: List::default() } } - - /// Decrement the value, and wait if it becomes < 0. Checking the - /// value and decrementing must be done atomically, so we - /// need to disable interrupts before checking the value. - /// - /// Note that thread_manager::thread_sleep assumes that interrupts are disabled - /// when it is called. - /// - /// ### Parameters TODO Refaire - /// - *current_thread* the current thread - /// - *machine* the machine where the threads are executed - 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 { - 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") - } - } - machine.interrupt.set_status(old_status); - } - - /// Increment semaphore value, waking up a waiting thread if any. - /// As with P(), this operation must be atomic, so we need to disable - /// interrupts. - /// - /// scheduler::ready_to_run() assumes that interrupts - /// are disabled when it is called. - /// - /// ### Parameters - /// - **machine** the machine where the threads are executed - /// - **scheduler** the scheduler which determine which thread to execute - pub fn v(&mut self, machine: &mut Machine, thread_manager: &mut ThreadManager){ - let old_status = machine.interrupt.set_status(InterruptOff); - self.counter += 1; - match self.waiting_queue.pop() { - Some(thread) => thread_manager.ready_to_run(thread), - None => () - } - machine.interrupt.set_status(old_status); - } + } /// Lock used for synchronisation, can be interpreted has a Semaphore with a @@ -267,71 +221,7 @@ impl Condition { mod test { use std::{rc::Rc, cell::RefCell}; - use crate::{kernel::{thread::Thread, synch::{Semaphore, Lock}, thread_manager::ThreadManager}, simulator::machine::Machine}; - - #[test] - fn test_semaphore_single() { - // Init - let mut machine = Machine::new(true); - 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(&mut machine, &mut thread_manager); - assert_eq!(semaphore.counter, 0); - assert!(semaphore.waiting_queue.is_empty()); - // V - semaphore.v(&mut machine, &mut thread_manager); - assert_eq!(semaphore.counter, 1); - assert!(semaphore.waiting_queue.is_empty()); - } - - #[test] - fn test_semaphore_multiple() { - // Init - let mut tm = ThreadManager::new(); - let mut machine = Machine::new(true); - 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 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 - 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()); - - 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()); - - 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(&mut machine, &mut tm); - assert_eq!(semaphore.counter, 0); - assert!(semaphore.waiting_queue.is_empty()); - - semaphore.v(&mut machine, &mut tm); - assert_eq!(semaphore.counter, 1); - assert!(semaphore.waiting_queue.is_empty()); - - semaphore.v(&mut machine, &mut tm); - assert_eq!(semaphore.counter, 2); - assert!(semaphore.waiting_queue.is_empty()); - } + use crate::{kernel::{thread::Thread, synch::Lock, thread_manager::ThreadManager}, simulator::machine::Machine}; diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index b388163..38205a7 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -173,6 +173,16 @@ impl ThreadManager { machine.pc = t.thread_context.pc; } + /// Decrement the value, and wait if it becomes < 0. Checking the + /// value and decrementing must be done atomically, so we + /// need to disable interrupts before checking the value. + /// + /// Note that thread_manager::thread_sleep assumes that interrupts are disabled + /// when it is called. + /// + /// ### Parameters + /// - *id_sema* id of the semaphore, stored in [`ObjAddr`], id given by user program thought exceptions + /// - *machine* Current state of the machine pub fn sem_p(&mut self, id_sema: i32, machine: &mut Machine) -> Result { match self.get_g_current_thread() { Some(thread) => { @@ -196,6 +206,16 @@ impl ThreadManager { } } + /// Increment semaphore value, waking up a waiting thread if any. + /// As with P(), this operation must be atomic, so we need to disable + /// interrupts. + /// + /// scheduler::ready_to_run() assumes that interrupts + /// are disabled when it is called. + /// + /// ### Parameters + /// - *id_sema* id of the semaphore, stored in [`ObjAddr`], id given by user program thought exceptions + /// - **machine** the machine where the threads are executed pub fn sem_v(&mut self, id_sema: i32, machine: &mut Machine) -> Result { let sema = self.get_obj_addrs().search_semaphore(id_sema as i32); match sema { @@ -253,7 +273,7 @@ impl ThreadManager { mod test { use std::{rc::Rc, cell::RefCell}; - use crate::{simulator::{machine::Machine, loader}, kernel::{system::System, thread::Thread, process::Process}}; + use crate::{simulator::{machine::Machine, loader}, kernel::{system::System, thread::Thread, process::Process, thread_manager::{ThreadManager, self}, synch::Semaphore}}; #[test] fn test_thread_context() { @@ -283,4 +303,95 @@ mod test { machine.run(system); } + #[test] + fn test_semaphore_single() { + // Init + let mut machine = Machine::new(true); + let mut thread_manager = ThreadManager::new(); + let semaphore = Semaphore::new(1); + let sema_id = thread_manager.get_obj_addrs().add_semaphore(semaphore); + 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 + thread_manager.sem_p(sema_id, &mut machine).expect("semaphore P return an error: "); + { + let semaphore = thread_manager.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 0); + assert!(semaphore.waiting_queue.is_empty()); + } + // V + thread_manager.sem_v(sema_id, &mut machine).expect("semaphore V return an error: "); + { + let semaphore = thread_manager.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 1); + assert!(semaphore.waiting_queue.is_empty()); + } + } + + #[test] + fn test_semaphore_multiple() { + // Init + let mut tm = ThreadManager::new(); + let mut machine = Machine::new(true); + let mut semaphore = Semaphore::new(2); + let sema_id = tm.get_obj_addrs().add_semaphore(semaphore); + 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 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 + tm.set_g_current_thread(Some(Rc::clone(&thread1))); + tm.sem_p(sema_id, &mut machine).expect("semaphore P return an error: "); + { + let semaphore = tm.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 1); + assert!(semaphore.waiting_queue.is_empty()); + } + + tm.set_g_current_thread(Some(Rc::clone(&thread2))); + tm.sem_p(sema_id, &mut machine).expect("semaphore P return an error: "); + { + let semaphore = tm.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 0); + assert!(semaphore.waiting_queue.is_empty()); + } + + tm.set_g_current_thread(Some(Rc::clone(&thread3))); + tm.sem_p( sema_id, &mut machine).expect("semaphore P return an error: "); + { + let semaphore = tm.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, -1); + assert!(semaphore.waiting_queue.iter().count() == 1); + } + + // V + tm.sem_v(sema_id, &mut machine).expect("semaphore V return an error: "); + { + let semaphore = tm.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 0); + assert!(semaphore.waiting_queue.is_empty()); + } + + tm.sem_v(sema_id, &mut machine).expect("semaphore V return an error: "); + { + let semaphore = tm.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 1); + assert!(semaphore.waiting_queue.is_empty()); + } + + tm.sem_v(sema_id, &mut machine).expect("semaphore V return an error: "); + { + let semaphore = tm.get_obj_addrs().search_semaphore(sema_id).unwrap(); + assert_eq!(semaphore.counter, 2); + assert!(semaphore.waiting_queue.is_empty()); + } + + } + } \ No newline at end of file diff --git a/src/utility/objaddr.rs b/src/utility/objaddr.rs index 92769aa..4290df3 100644 --- a/src/utility/objaddr.rs +++ b/src/utility/objaddr.rs @@ -62,6 +62,7 @@ impl ObjAddr { self.semaphores.remove(&id) } + /// Remove the object of id **id** from self if it exists pub fn remove_lock(&mut self, id:i32) -> Option { self.locks.remove(&id) }