📝 Added module documentation for thread_manager
This commit is contained in:
parent
5c66577989
commit
780ed4b461
@ -1,3 +1,71 @@
|
|||||||
|
//! # Thread manager
|
||||||
|
//!
|
||||||
|
//! This module describes the data structure and the methods used for thread scheduling
|
||||||
|
//! in the BurritOS operating system. A struct named `ThreadManager` holds the list of
|
||||||
|
//! all existing threads and synchronization objects, such as `Locks`, `Semaphores` and
|
||||||
|
//! `Conditions`.
|
||||||
|
//!
|
||||||
|
//! ## Purpose
|
||||||
|
//!
|
||||||
|
//! `ThreadManager` holds the state of the system processes using the following subcomponents:
|
||||||
|
//!
|
||||||
|
//! ### Two lists of threads
|
||||||
|
//!
|
||||||
|
//! - **ready_list**: The list of threads ready to be executed
|
||||||
|
//! - **g_alive**: The list of currently executing threads
|
||||||
|
//!
|
||||||
|
//! The difference between the two above lists lies in the state of the threads in question.
|
||||||
|
//! Ready threads have just been enqueued. They are not being executed yet. The second list is
|
||||||
|
//! needed because many threads may be executing at a given time. However, only a single thread
|
||||||
|
//! can be handled by the machine at a time. The system thus needs to keep in memory the alive
|
||||||
|
//! threads in case the currently running thread finishes or gets rescheduled.
|
||||||
|
//!
|
||||||
|
//! ### A list of synchronization objects
|
||||||
|
//!
|
||||||
|
//! Locks, Semaphores and Conditions allow resource sharing among running threads. Since resources
|
||||||
|
//! can only be accessed by a single thread at a time, we need data structures to signal other
|
||||||
|
//! threads that a resource may be busy or unavailable; say for example that thread **A** wants to
|
||||||
|
//! write to a file while **B** is currently reading said file. Thread **A** mutating the state of
|
||||||
|
//! the file could cause issues for **B**. Therefore **B** needs to lock the file in question to
|
||||||
|
//! avoid such issues. Thread **A** will have to wait for **B** to finish reading the file.
|
||||||
|
//!
|
||||||
|
//! These synchronization objects are held in an instance of the ObjAddr structure held by
|
||||||
|
//! ThreadManager. Their state is mutated depending on the actions of the currently running thread
|
||||||
|
//! through methods such as `ThreadManager::sem_p`.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! `ThreadManager` is thought as a subcomponent of the `System` struct. Instanciating
|
||||||
|
//! `System` will automatically instanciate a `ThreadManager`
|
||||||
|
//!
|
||||||
|
//! Manually loading a Thread into ThreadManager to execute a program with BurritOS could look like
|
||||||
|
//! this:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! fn load_thread_manually(args: ...) {
|
||||||
|
//! let mut system = System::new(args.debug);
|
||||||
|
//!
|
||||||
|
//! let thread_exec = Thread::new(args.executable.as_str());
|
||||||
|
//! let thread_exec = Rc::new(RefCell::new(thread_exec));
|
||||||
|
//! system.get_thread_manager().get_g_alive().push(Rc::clone(&thread_exec));
|
||||||
|
//!
|
||||||
|
//! let owner1 = Process { num_thread: 0 };
|
||||||
|
//! let owner1 = Rc::new(RefCell::new(owner1));
|
||||||
|
//! system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, ptr, -1);
|
||||||
|
//!
|
||||||
|
//! let to_run = system.get_thread_manager().find_next_to_run().unwrap();
|
||||||
|
//! system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));
|
||||||
|
//!
|
||||||
|
//! machine.run(&mut system);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Imports
|
||||||
|
//!
|
||||||
|
//! The `List` and `ObjAddr` submodules used in this module are defined in the utility
|
||||||
|
//! module. The source code of ObjAddr has been decoupled from thread_manager in an effort
|
||||||
|
//! to keep this module concise.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
cell::{
|
cell::{
|
||||||
@ -190,11 +258,11 @@ impl ThreadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decrement the value, and wait if it becomes < 0. Checking the
|
/// Decrement the value, and wait if it becomes < 0. Checking the
|
||||||
/// value and decrementing must be done atomically, so we
|
/// value and decrementing must be done atomically, so we
|
||||||
/// need to disable interrupts before checking the value.
|
/// need to disable interrupts before checking the value.
|
||||||
///
|
///
|
||||||
/// Note that thread_manager::thread_sleep assumes that interrupts are disabled
|
/// Note that thread_manager::thread_sleep assumes that interrupts are disabled
|
||||||
/// when it is called.
|
/// when it is called.
|
||||||
///
|
///
|
||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
/// - *id_sema* id of the semaphore, stored in [`ObjAddr`], id given by user program thought exceptions
|
/// - *id_sema* id of the semaphore, stored in [`ObjAddr`], id given by user program thought exceptions
|
||||||
@ -244,12 +312,12 @@ impl ThreadManager {
|
|||||||
|
|
||||||
|
|
||||||
/// Wait until the lock become free. Checking the
|
/// Wait until the lock become free. Checking the
|
||||||
/// state of the lock (free or busy) and modify it must be done
|
/// state of the lock (free or busy) and modify it must be done
|
||||||
/// atomically, so we need to disable interrupts before checking
|
/// atomically, so we need to disable interrupts before checking
|
||||||
/// the value of free.
|
/// the value of free.
|
||||||
///
|
///
|
||||||
/// Note that thread_manager::thread_seep assumes that interrupts are disabled
|
/// Note that thread_manager::thread_seep assumes that interrupts are disabled
|
||||||
/// when it is called.
|
/// when it is called.
|
||||||
///
|
///
|
||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
/// - **id** id of the lock, stored in [`ObjAddr`], id given by user program thought exceptions
|
/// - **id** id of the lock, stored in [`ObjAddr`], id given by user program thought exceptions
|
||||||
@ -278,7 +346,7 @@ impl ThreadManager {
|
|||||||
/// Wake up a waiter if necessary, or release it if no thread is waiting.
|
/// Wake up a waiter if necessary, or release it if no thread is waiting.
|
||||||
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 current_thread = match self.get_g_current_thread() {
|
let current_thread = match self.get_g_current_thread() {
|
||||||
Some(thread) => Rc::clone(&thread),
|
Some(thread) => Rc::clone(thread),
|
||||||
None => Err(String::from("lock_release error: current_thread should not be None."))?
|
None => Err(String::from("lock_release error: current_thread should not be None."))?
|
||||||
};
|
};
|
||||||
let mut lock = match self.get_obj_addrs().search_lock(id).cloned() {
|
let mut lock = match self.get_obj_addrs().search_lock(id).cloned() {
|
||||||
|
Loading…
Reference in New Issue
Block a user