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{
|
pub fn new(counter: i32) -> Semaphore{
|
||||||
Semaphore { counter, waiting_queue: List::default() }
|
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
|
/// Lock used for synchronisation, can be interpreted has a Semaphore with a
|
||||||
@ -267,71 +221,7 @@ impl Condition {
|
|||||||
mod test {
|
mod test {
|
||||||
use std::{rc::Rc, cell::RefCell};
|
use std::{rc::Rc, cell::RefCell};
|
||||||
|
|
||||||
use crate::{kernel::{thread::Thread, synch::{Semaphore, Lock}, thread_manager::ThreadManager}, simulator::machine::Machine};
|
use crate::{kernel::{thread::Thread, synch::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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,6 +173,16 @@ impl ThreadManager {
|
|||||||
machine.pc = t.thread_context.pc;
|
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> {
|
pub fn sem_p(&mut self, id_sema: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> {
|
||||||
match self.get_g_current_thread() {
|
match self.get_g_current_thread() {
|
||||||
Some(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> {
|
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);
|
let sema = self.get_obj_addrs().search_semaphore(id_sema as i32);
|
||||||
match sema {
|
match sema {
|
||||||
@ -253,7 +273,7 @@ impl ThreadManager {
|
|||||||
mod test {
|
mod test {
|
||||||
use std::{rc::Rc, cell::RefCell};
|
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]
|
#[test]
|
||||||
fn test_thread_context() {
|
fn test_thread_context() {
|
||||||
@ -283,4 +303,95 @@ mod test {
|
|||||||
machine.run(system);
|
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)
|
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> {
|
pub fn remove_lock(&mut self, id:i32) -> Option<Lock> {
|
||||||
self.locks.remove(&id)
|
self.locks.remove(&id)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user