Merge branch 'doc' into 'main'
Add comments to thread_manager See merge request simpleos/burritos!27
This commit is contained in:
commit
905e647dda
@ -119,6 +119,9 @@ pub struct ThreadManager {
|
|||||||
obj_addrs: ObjAddr,
|
obj_addrs: ObjAddr,
|
||||||
/// If true, enables debug mode
|
/// If true, enables debug mode
|
||||||
debug: bool,
|
debug: bool,
|
||||||
|
/// Temporary field, to be removed when virtual memory will be available to use.
|
||||||
|
///
|
||||||
|
/// A value to know where the next starting thread should have its stack pointer
|
||||||
sp_max: u64,
|
sp_max: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,19 +139,19 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark a thread as aready, but not necessarily running yet.
|
/// Mark `thread` as ready, but not necessarily running yet.
|
||||||
///
|
///
|
||||||
/// Put it in the ready list, for later scheduling onto the CPU.
|
/// Put it in the ready list, for later scheduling onto the CPU.
|
||||||
///
|
///
|
||||||
/// ## Pamameter
|
/// ## Pamameter
|
||||||
///
|
///
|
||||||
/// **thread** is the thread to be put on the read list
|
/// **thread** is the thread to be put on the ready list
|
||||||
pub fn ready_to_run(&mut self, thread: ThreadRef) {
|
pub fn ready_to_run(&mut self, thread: ThreadRef) {
|
||||||
self.ready_list.push(thread);
|
self.ready_list.push(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the next thread to be scheduled onto the CPU.
|
/// Return the next thread to be scheduled onto the CPU.
|
||||||
/// If there are no ready threads, return Option::None
|
/// If there are no ready threads, return `Option::None`
|
||||||
///
|
///
|
||||||
/// Thread is removed from the ready list.
|
/// Thread is removed from the ready list.
|
||||||
///
|
///
|
||||||
@ -157,12 +160,12 @@ impl ThreadManager {
|
|||||||
self.ready_list.pop()
|
self.ready_list.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch the CPU to next_thread. Save the state of the old thread
|
/// Dispatch the CPU to `next_thread`. Save the state of the old thread
|
||||||
/// and load the state of the new 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.
|
/// 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
|
/// Variable `g_current_thread` become next_thread
|
||||||
///
|
///
|
||||||
/// ## Parameter
|
/// ## Parameter
|
||||||
///
|
///
|
||||||
@ -187,6 +190,14 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start a thread, attaching it to a process
|
/// Start a thread, attaching it to a process
|
||||||
|
///
|
||||||
|
/// ## Parameter
|
||||||
|
///
|
||||||
|
/// **thread** thread to start
|
||||||
|
/// **owner** process owner of thread (after the execution of this method)
|
||||||
|
/// **func_pc** pc the thread
|
||||||
|
/// **sp_loc** stack pointer of the thread, to remove (or move) when mmu will be completed
|
||||||
|
/// **argument** value to be place on register[10]
|
||||||
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
|
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
|
||||||
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
|
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
|
||||||
|
|
||||||
@ -201,6 +212,11 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for another thread to finish its execution
|
/// Wait for another thread to finish its execution
|
||||||
|
///
|
||||||
|
/// If the thread you want to wait doesn't exist (isn't alive), execution will resume.
|
||||||
|
/// Otherwise, CPU is dispatch to next alive thread if any.
|
||||||
|
///
|
||||||
|
/// When the thread you want to join finish, it place the waiting thread (self) in ready list
|
||||||
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
|
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
|
||||||
let waiting_for = Rc::clone(&waiting_for);
|
let waiting_for = Rc::clone(&waiting_for);
|
||||||
if self.get_g_alive().contains(&waiting_for) {
|
if self.get_g_alive().contains(&waiting_for) {
|
||||||
@ -211,10 +227,19 @@ impl ThreadManager {
|
|||||||
|
|
||||||
/// Relinquish the CPU if any other thread is runnable.
|
/// Relinquish the CPU if any other thread is runnable.
|
||||||
///
|
///
|
||||||
/// Cannot use yield as a function name -> reserved name in rust
|
/// If so, put the current thread at the end of the ready list, so it'll be re-scheduled in the future.
|
||||||
|
///
|
||||||
|
/// **Returns** immediately if there's no other thread ready or return when the current thread has been switched.
|
||||||
|
///
|
||||||
|
/// Interruptions are disabled during the process, so all the process of looking for a next thread and switching to it is atomic,
|
||||||
|
/// and is place at its old status at the end of the method.
|
||||||
|
///
|
||||||
|
/// Cannot use `yield` as a function name -> reserved name in rust
|
||||||
///
|
///
|
||||||
/// ## Parameters
|
/// ## Parameters
|
||||||
///
|
///
|
||||||
|
/// **machine** RISC-V simulator
|
||||||
|
/// **thread** current thread to be relinquish
|
||||||
/// **is_ready** true if **thread** should be readded to ready_to_run list, false otherwise. Typically false when joining per example
|
/// **is_ready** true if **thread** should be readded to ready_to_run list, false otherwise. Typically false when joining per example
|
||||||
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef, is_ready: bool) {
|
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef, is_ready: bool) {
|
||||||
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
|
||||||
@ -231,7 +256,16 @@ impl ThreadManager {
|
|||||||
machine.interrupt.set_status(old_status);
|
machine.interrupt.set_status(old_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Put the thread to sleep and relinquish the processor
|
/// Put the thread to sleep and relinquish the processor because the current thread is blocked (Semaphore, Lock, Condition) or because it finished its execution
|
||||||
|
///
|
||||||
|
/// Another thread will eventually wake it up and put it back to ready list after it has been unblocked.
|
||||||
|
///
|
||||||
|
/// Behavior now: At the moment, disk isn't fully develop and not integrated to burritos, so if there's no ready thread, then we stop the OS.
|
||||||
|
///
|
||||||
|
/// Behaviour in the future: If there are no threads on the ready list, that means there is no thread to run,
|
||||||
|
/// we assume this is because at least one thread is waiting for I/O [`interrupt`](crate::simulator::interrupt::Interrupt) (the only reason a new thread can become ready at this point).
|
||||||
|
///
|
||||||
|
/// We also assume interruption are already disabled, becuase it's called from a synchronization routine for interrupt should be disabled.
|
||||||
pub fn thread_sleep(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_sleep(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
||||||
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
||||||
@ -252,6 +286,12 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the execution of the thread and prepare its deallocation
|
/// Finish the execution of the thread and prepare its deallocation
|
||||||
|
///
|
||||||
|
/// Called by the thread itself when it finish its execution ([`Exit`](super::exception::SC_EXIT) exception).
|
||||||
|
///
|
||||||
|
/// We remove the thread from the alive list, and rustc deallocate the thread itself(behaviour different than Nachos)
|
||||||
|
///
|
||||||
|
/// Interruption are disabled to assume atomicity.
|
||||||
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef, exit_code: i64) {
|
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef, exit_code: i64) {
|
||||||
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
||||||
assert!(self.g_alive.remove(Rc::clone(&thread)));
|
assert!(self.g_alive.remove(Rc::clone(&thread)));
|
||||||
@ -265,6 +305,8 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Save the CPU state of a user program on a context switch.
|
/// Save the CPU state of a user program on a context switch.
|
||||||
|
///
|
||||||
|
/// Save PC and registers
|
||||||
pub fn thread_save_processor_state(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_save_processor_state(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
let mut t = thread.borrow_mut();
|
let mut t = thread.borrow_mut();
|
||||||
for i in 0..NUM_INT_REGS {
|
for i in 0..NUM_INT_REGS {
|
||||||
@ -277,6 +319,8 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the CPU state of a user program on a context switch.
|
/// Restore the CPU state of a user program on a context switch.
|
||||||
|
///
|
||||||
|
/// Restore PC and registers
|
||||||
pub fn thread_restore_processor_state(&self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_restore_processor_state(&self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
let t: Ref<_> = thread.borrow();
|
let t: Ref<_> = thread.borrow();
|
||||||
for i in 0..NUM_INT_REGS {
|
for i in 0..NUM_INT_REGS {
|
||||||
@ -371,7 +415,9 @@ impl ThreadManager {
|
|||||||
Ok(MachineOk::Ok)
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wake up a waiter if necessary, or release it if no thread is waiting.
|
/// Release lock hold by current thread and wake up a waiter if necessary, placing it on ready list, this thread now hold the lock.
|
||||||
|
///
|
||||||
|
/// If no thread is waiting for the lock, the lock is released
|
||||||
pub fn lock_release(&mut self, id: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> {
|
pub fn lock_release(&mut self, id: i32, machine: &mut Machine) -> Result<MachineOk, MachineError> {
|
||||||
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
||||||
let current_thread = match self.get_g_current_thread() {
|
let current_thread = match self.get_g_current_thread() {
|
||||||
@ -402,12 +448,12 @@ impl ThreadManager {
|
|||||||
Ok(MachineOk::Ok)
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Currently running thread
|
/// Return currently running thread
|
||||||
pub fn get_g_current_thread(&mut self) -> &Option<ThreadRef> {
|
pub fn get_g_current_thread(&mut self) -> &Option<ThreadRef> {
|
||||||
&self.g_current_thread
|
&self.g_current_thread
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List of alive threads
|
/// Return list of alive threads
|
||||||
pub fn get_g_alive(&mut self) -> &mut List<ThreadRef> {
|
pub fn get_g_alive(&mut self) -> &mut List<ThreadRef> {
|
||||||
&mut self.g_alive
|
&mut self.g_alive
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user