From d392c69535f4b787f2a75b8f8834e01998799b79 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Thu, 9 Mar 2023 12:08:33 +0100 Subject: [PATCH] Add thread save and restore processor context --- src/kernel/system.rs | 12 +++++---- src/kernel/thread.rs | 38 +++++++++++------------------ src/kernel/thread_manager.rs | 47 ++++++++++++++++++++++++++++++++---- src/kernel/ucontext.rs | 7 +++--- src/simulator/machine.rs | 16 ++++++++++++ 5 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/kernel/system.rs b/src/kernel/system.rs index 863bdc2..319be5c 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -1,3 +1,5 @@ +use std::cell::RefCell; + use crate::simulator::machine::Machine; use super::thread_manager::ThreadManager; @@ -14,7 +16,7 @@ use super::thread_manager::ThreadManager; /// - The scheduler which acts upon these threads #[derive(PartialEq)] pub struct System<'a> { - g_machine: Machine, + g_machine: RefCell, thread_manager: ThreadManager<'a> } @@ -23,7 +25,7 @@ impl<'a> System<'a> { /// System constructor pub fn new(machine: Machine) -> System<'a> { Self { - g_machine: machine, + g_machine: RefCell::new(machine), thread_manager: ThreadManager::new() } } @@ -37,14 +39,14 @@ impl<'a> System<'a> { /// Returns the Machine /// /// Useful to access RAM, devices, ... - pub fn get_g_machine(&mut self) -> &mut Machine { - &mut self.g_machine + pub fn get_g_machine(&self) -> &RefCell { + &self.g_machine } // Setters /// Assign a machine to the system - pub fn set_g_machine(&mut self, machine: Machine) { + pub fn set_g_machine(&mut self, machine: RefCell) { self.g_machine = machine } diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 68bc7c9..326bb9c 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,13 +1,12 @@ -use super::{process::Process, system::ObjectType}; +use super::{process::Process, system::ObjectType, thread_manager::SIMULATORSTACKSIZE}; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; -const SIMULATORSTACKSIZE: usize = 32 * 1024; const STACK_FENCEPOST: u32 = 0xdeadbeef; #[derive(PartialEq)] -struct ThreadContext { +pub struct ThreadContext { pub int_registers: [i64; NUM_INT_REGS], - pub float_registers: [i64; NUM_FP_REGS], + pub float_registers: [f32; NUM_FP_REGS], pc: i64, } @@ -16,8 +15,8 @@ pub struct Thread { name: String, pub process: Option, // simulation_context: UContextT, - thread_context: ThreadContext, - stack_pointer: i32, + pub thread_context: ThreadContext, + pub stack_pointer: i32, object_type: ObjectType } @@ -31,7 +30,7 @@ impl Thread { // simulation_context: UContextT::new(), thread_context: ThreadContext { int_registers: [0; NUM_INT_REGS], - float_registers: [0; NUM_FP_REGS], + float_registers: [0f32; NUM_FP_REGS], pc: 0 }, stack_pointer: 0, @@ -59,28 +58,19 @@ impl Thread { // self.simulation_context.stackBottom = base_stack_addr.to_vec(); // self.simulation_context.stackBottom[0] = STACK_FENCEPOST; } - - /// Put the thread to sleep and relinquish the processor - pub fn sleep(&self) { - todo!(); - } - - /// Finish the execution of the thread and prepare its deallocation - pub fn finish(&self) { - todo!(); - } /// 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) { - todo!(); + // if self.simulator_context.stackBottom != STACK_FENCEPOST { + // panic!("thread {} has overflowed", self.get_name()) + // } } - pub fn save_processor_state(&self) { - todo!(); - } - - pub fn restore_processor_state(&self) { - todo!(); + pub fn sleep(&self) { + unreachable!("Has been moved to thread manager"); } pub fn save_simulator_state(&self) { diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 466d14e..39a7f81 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -1,10 +1,10 @@ -use std::{rc::Rc, cell::Cell}; +use std::{rc::Rc, cell::{Cell, RefCell, RefMut, Ref}}; -use crate::utility::list::List; +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}; -const SIMULATORSTACKSIZE: usize = 32 * 1024; +pub const SIMULATORSTACKSIZE: usize = 32 * 1024; #[derive(PartialEq)] pub struct ThreadManager<'a> { @@ -44,17 +44,54 @@ impl<'a> ThreadManager<'a> { /// 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(); + 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) { + 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 diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs index 567d144..1ffee6f 100644 --- a/src/kernel/ucontext.rs +++ b/src/kernel/ucontext.rs @@ -1,5 +1,5 @@ -// use std::mem::MaybeUninit; +use std::mem::MaybeUninit; /// Safe wrapper for ucontext_t struct of linux-gnu libc /// @@ -12,10 +12,11 @@ pub struct UContextT { #[cfg(not(target_os = "windows"))] // struct non disponible sur la libc sur windows pub buf: libc::ucontext_t, - pub stackBottom: Vec + pub stack_bottom: Vec } #[cfg(not(target_os = "windows"))] +#[allow(unused)] // Temporary as we currently doesn't use this structure (this structure may disapear in a near future) impl UContextT { pub fn new() -> Self { @@ -23,7 +24,7 @@ impl UContextT { unsafe { libc::getcontext(context.as_mut_ptr()) }; Self { buf: unsafe { context.assume_init() }, - stackBottom: Vec::default(), + stack_bottom: Vec::default(), } } diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 73dc8b5..228fbf6 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -616,6 +616,22 @@ impl Machine { machine.pc += 8; } + + pub fn read_int_register(&self, index: usize) -> i64 { + self.int_reg.get_reg(index) + } + + pub fn read_fp_register(&self, index: usize) -> f32 { + self.fp_reg.get_reg(index) + } + + pub fn write_int_register(&mut self, index: usize, value: i64) { + self.int_reg.set_reg(index, value); + } + + pub fn write_fp_register(&mut self, index: usize, value: f32) { + self.fp_reg.set_reg(index, value); + } } #[cfg(test)]