Documentation for different functions of synch.rs

This commit is contained in:
Rémi Rativel 2023-03-13 23:38:45 +01:00
parent 5a6a70f1b7
commit 5b7a12ab0f

View File

@ -9,6 +9,7 @@ use std::rc::Rc;
use super::scheduler::Scheduler; use super::scheduler::Scheduler;
use super::thread_manager::ThreadManager; use super::thread_manager::ThreadManager;
/// Structure of a Semaphore used for synchronisation
pub struct Semaphore<'t> { pub struct Semaphore<'t> {
counter:i32, counter:i32,
@ -19,6 +20,16 @@ pub struct Semaphore<'t> {
impl<'t> Semaphore<'_> { impl<'t> Semaphore<'_> {
/// 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
/// - *current_thread* the current thread
/// - *machine* the machine where the threads are executed
pub fn p(&mut self, current_thread: Rc<RefCell<Thread>>, machine: &mut Machine){ pub fn p(&mut self, current_thread: Rc<RefCell<Thread>>, machine: &mut Machine){
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
self.counter -= 1; self.counter -= 1;
@ -29,6 +40,16 @@ impl<'t> Semaphore<'_> {
machine.interrupt.set_status(old_status); 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, scheduler: &mut Scheduler){ pub fn v(&mut self, machine: &mut Machine, scheduler: &mut Scheduler){
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
self.counter -= 1; self.counter -= 1;
@ -39,6 +60,9 @@ impl<'t> Semaphore<'_> {
} }
} }
/// Lock used for synchronisation, can be interpreted has a Semaphore with a
/// counter of 1
/// It's used for critical parts
pub struct Lock<'t>{ pub struct Lock<'t>{
owner: Rc<RefCell<Thread>>, owner: Rc<RefCell<Thread>>,
@ -49,7 +73,19 @@ pub struct Lock<'t>{
} }
impl<'t> Lock<'_> { impl<'t> Lock<'_> {
pub fn acquire(&mut self, machine: &mut Machine, current_thread: Rc<RefCell<Thread>>) {
/// Wait until the lock become free. Checking the
/// state of the lock (free or busy) and modify it must be done
/// atomically, so we need to disable interrupts before checking
/// the value of free.
///
/// Note that thread_manager::thread_seep assumes that interrupts are disabled
/// when it is called.
///
/// ### Parameters
/// - **current_thread** the current thread
/// - **machine** the machine where the threads are executed
pub fn acquire(&mut self, current_thread: Rc<RefCell<Thread>>, machine: &mut Machine) {
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
if self.free { if self.free {
@ -63,10 +99,19 @@ impl<'t> Lock<'_> {
machine.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.
/// We check that the lock is held by the g_current_thread.
/// As with Acquire, this operation must be atomic, so we need to disable
/// interrupts. scheduler::ready_to_run() assumes that threads
/// are disabled when it is called.
///
/// ### Parameters
/// - **machine** the machine where the code is executed
/// - **scheduler** the scheduler which determine which thread to execute
pub fn release(&mut self, machine: &mut Machine, scheduler: &mut Scheduler, current_thread: Rc<RefCell<Thread>>) { pub fn release(&mut self, machine: &mut Machine, scheduler: &mut Scheduler, current_thread: Rc<RefCell<Thread>>) {
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
if self.is_held_by_current_thread(current_thread) { if self.held_by_current_thread(current_thread) {
if self.waiting_queue.peek() != None { if self.waiting_queue.peek() != None {
self.owner = self.waiting_queue.pop().unwrap(); self.owner = self.waiting_queue.pop().unwrap();
scheduler.ready_to_run(Rc::clone(&self.owner)); scheduler.ready_to_run(Rc::clone(&self.owner));
@ -78,11 +123,12 @@ impl<'t> Lock<'_> {
machine.interrupt.set_status(old_status); machine.interrupt.set_status(old_status);
} }
pub fn is_held_by_current_thread(&mut self, current_thread: Rc<RefCell<Thread>>) -> bool { pub fn held_by_current_thread(&mut self, current_thread: Rc<RefCell<Thread>>) -> bool {
Rc::ptr_eq(&self.owner, &current_thread) Rc::ptr_eq(&self.owner, &current_thread)
} }
} }
/// Structure of a condition used for synchronisation
pub struct Condition<'t>{ pub struct Condition<'t>{
waiting_queue:List<Rc<RefCell<Thread>>>, waiting_queue:List<Rc<RefCell<Thread>>>,
@ -91,8 +137,14 @@ pub struct Condition<'t>{
} }
impl<'t> Condition<'_> { impl<'t> Condition<'_> {
pub fn wait(&mut self, machine: &mut Machine, current_thread: Rc<RefCell<Thread>>) { /// Block the calling thread (put it in the wait queue).
/// This operation must be atomic, so we need to disable interrupts.
///
/// ### Parameters
/// - **current_thread** the current thread
/// - **machine** the machine where threads are executed
pub fn wait(&mut self, current_thread: Rc<RefCell<Thread>>, machine: &mut Machine) {
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
self.waiting_queue.push(Rc::clone(&current_thread)); self.waiting_queue.push(Rc::clone(&current_thread));
@ -101,6 +153,12 @@ impl<'t> Condition<'_> {
machine.interrupt.set_status(old_status); machine.interrupt.set_status(old_status);
} }
/// Wake up the first thread of the wait queue (if any).
/// This operation must be atomic, so we need to disable interrupts.
///
/// ### 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) { pub fn signal(&mut self, machine: &mut Machine, scheduler: &mut Scheduler) {
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);
@ -112,6 +170,12 @@ impl<'t> Condition<'_> {
} }
/// Wake up all threads waiting in the waitqueue of the condition
/// This operation must be atomic, so we need to disable interrupts.
///
/// ### 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) { pub fn broadcast(&mut self, machine: &mut Machine, scheduler: &mut Scheduler) {
let old_status = machine.interrupt.set_status(InterruptOff); let old_status = machine.interrupt.set_status(InterruptOff);