Remove old P and V semaphore function and moved tests
This commit is contained in:
parent
21f3a72a3d
commit
752b70e448
@ -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};
|
||||
|
||||
|
||||
|
||||
|
@ -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<MachineOk, MachineError> {
|
||||
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<MachineOk, MachineError> {
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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<Lock> {
|
||||
self.locks.remove(&id)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user