use std::{rc::Rc, cell::{Cell, RefCell, RefMut, Ref}}; use crate::{utility::list::List, simulator::machine::{NUM_INT_REGS, NUM_FP_REGS}}; use super::{scheduler::Scheduler, thread::Thread, system::System, mgerror::ErrorCode, process::Process}; pub const SIMULATORSTACKSIZE: usize = 32 * 1024; #[derive(PartialEq)] pub struct ThreadManager<'a> { pub g_current_thread: Option, pub g_thread_to_be_destroyed: Option, pub g_alive: List>, pub g_scheduler: Scheduler, pub system: Cell>> } impl<'a> ThreadManager<'a> { pub fn new() -> Self { Self { g_current_thread: Option::None, g_thread_to_be_destroyed: Option::None, g_alive: List::new(), g_scheduler: Scheduler::new(), system: Cell::new(None) } } /// Start a thread, attaching it to a process pub fn start_thread(&mut self, mut thread: Thread, owner: Process, func_pc: i64, argument: i64) -> Result<(), ErrorCode> { thread.process = Option::Some(owner); let ptr = 0; // todo addrspace thread.init_thread_context(func_pc, ptr, argument); let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray thread.init_simulator_context(base_stack_addr); thread.process.as_mut().unwrap().num_thread += 1; let thread_m = Rc::new(thread); self.get_g_alive().push(Rc::clone(&thread_m)); self.g_scheduler().ready_to_run(Rc::clone(&thread_m)); Result::Ok(()) } /// Wait for another thread to finish its execution pub fn thread_join(&mut self, id_thread: Rc) { while self.get_g_alive().contains(&Rc::clone(&id_thread)) { self.thread_yield(Rc::clone(&id_thread)); } } /// Relinquish the CPU if any other thread is runnable. /// /// Cannot use yield as a function name -> reserved name in rust pub fn thread_yield(&mut self, thread: Rc) { todo!(); } /// Put the thread to sleep and relinquish the processor pub fn thread_sleep(&mut self, thread: Rc) { todo!(); } /// Finish the execution of the thread and prepare its deallocation pub fn thread_finish(&self, thread: Rc) { todo!(); } pub fn thread_save_processor_state(&mut self, thread: Rc>) { if let Some(system) = self.system.get() { let mut t: RefMut<_> = thread.borrow_mut(); for i in 0..NUM_INT_REGS { t.thread_context.int_registers[i] = system.get_g_machine().borrow().read_int_register(i); } for i in 0..NUM_FP_REGS { t.thread_context.float_registers[i] = system.get_g_machine().borrow().read_fp_register(i); } } else { unreachable!("System is None") } } pub fn thread_restore_processor_state(&self, thread: Rc>) { if let Some(system) = self.system.get() { let t: Ref<_> = thread.borrow(); for i in 0..NUM_INT_REGS { let machine = system.get_g_machine(); let mut machine = machine.borrow_mut(); machine.write_int_register(i, t.thread_context.int_registers[i]); } } else { unreachable!("System is None") } } /// Currently running thread pub fn get_g_current_thread(&mut self) -> &mut Option { &mut self.g_current_thread } /// Thread to be destroyed by [...] /// /// TODO: Finish the comment with the relevant value pub fn get_g_thread_to_be_destroyed(&mut self) -> &mut Option { &mut self.g_thread_to_be_destroyed } /// List of alive threads pub fn get_g_alive(&mut self) -> &mut List> { &mut self.g_alive } /// Current scheduler pub fn g_scheduler(&mut self) -> &mut Scheduler { &mut self.g_scheduler } /// Set currently running thread pub fn set_g_current_thread(&mut self, thread: Option) { self.g_current_thread = thread } /// Set thread to be destroyed next pub fn set_g_thread_to_be_destroyed(&mut self, thread: Option) { self.g_thread_to_be_destroyed = thread } /// Set Scheduler which will manage the threads pub fn set_g_scheduler(&mut self, scheduler: Scheduler) { self.g_scheduler = scheduler } }