use std::{rc::Rc, cell::RefCell}; use super::process::Process; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; const STACK_FENCEPOST: u32 = 0xdeadbeef; /// Polymorphic macro to get thread without passing a name by default #[macro_export] macro_rules! get_new_thread { () => { Thread::new(DEFAULT_THREAD_NAME) }; ($a:literal) => { Thread::new(&$a.to_string()) }; } #[derive(PartialEq, Debug)] pub struct ThreadContext { pub int_registers: [i64; NUM_INT_REGS], pub float_registers: [f32; NUM_FP_REGS], pub pc: u64, } #[derive(PartialEq, Debug)] pub struct Thread { name: String, pub process: Option>>, pub thread_context: ThreadContext, pub stack_pointer: i32, } impl Thread { /// Thread constructor pub fn new(name: &str) -> Self { Self { name: String::from(name), process: None, // simulation_context: UContextT::new(), thread_context: ThreadContext { int_registers: [0; NUM_INT_REGS], float_registers: [0f32; NUM_FP_REGS], pc: 0 }, stack_pointer: 0, } } pub fn init_thread_context(&mut self, initial_pc_reg: u64, initial_sp: u64, arg: i64) { self.thread_context.pc = initial_pc_reg; self.thread_context.int_registers[10] = arg; self.thread_context.int_registers[STACK_REG] = initial_sp as i64; } /// Check if a thread has overflowed its stack /// /// This assertion doesn't catch all stack overflow conditions and your program may still crash because of an overflow. /// pub fn check_overflow(&self) { // if self.simulator_context.stackBottom != STACK_FENCEPOST { // panic!("thread {} has overflowed", self.get_name()) // } } pub fn get_name(&self) -> String { self.name.clone() } /// Return reference to an optional Process /// can be None if Thread hasn't been initialize pub fn get_process_owner(&self) -> &Option>> { &self.process } } #[cfg(test)] mod test { use super::{Thread, ThreadContext, NUM_INT_REGS, NUM_FP_REGS}; const DEFAULT_THREAD_NAME: &str = "test_thread"; /// This macro allows for getting a Thread for which we've ensured proper initial state /// in case a commit further down the line changes the initial state of threads generated /// from Thread::new macro_rules! expected_initial_state { () => { expected_initial_state!(DEFAULT_THREAD_NAME) }; ($a:expr) => { { let mut x = Thread::new($a); x.name = $a.to_string(); x.process = Option::None; x.thread_context = ThreadContext { int_registers: [0; NUM_INT_REGS], float_registers: [0f32; NUM_FP_REGS], pc: 0 }; x.stack_pointer = 0; x } }; } #[test] fn test_macro() { let t = get_new_thread!("hello"); assert_eq!(t.get_name(), "hello"); let t = get_new_thread!(1); assert_eq!(t.get_name(), "1"); } #[test] fn check_init() { let t = get_new_thread!(); let expected_state = expected_initial_state!(); assert_eq!(t, expected_state) } }