Add thread save and restore processor context

This commit is contained in:
Quentin Legot 2023-03-09 12:08:33 +01:00 committed by François Autin
parent 0c3af96b78
commit 26b75ffe8d
No known key found for this signature in database
GPG Key ID: 343F5D382E1DD77C
5 changed files with 87 additions and 55 deletions

View File

@ -1,3 +1,5 @@
use std::cell::RefCell;
use crate::simulator::machine::Machine; use crate::simulator::machine::Machine;
use super::thread_manager::ThreadManager; use super::thread_manager::ThreadManager;
@ -14,7 +16,7 @@ use super::thread_manager::ThreadManager;
/// - The scheduler which acts upon these threads /// - The scheduler which acts upon these threads
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct System<'a> { pub struct System<'a> {
g_machine: Machine, g_machine: RefCell<Machine>,
thread_manager: ThreadManager<'a> thread_manager: ThreadManager<'a>
} }
@ -23,7 +25,7 @@ impl<'a> System<'a> {
/// System constructor /// System constructor
pub fn new(machine: Machine) -> System<'a> { pub fn new(machine: Machine) -> System<'a> {
Self { Self {
g_machine: machine, g_machine: RefCell::new(machine),
thread_manager: ThreadManager::new() thread_manager: ThreadManager::new()
} }
} }
@ -37,14 +39,14 @@ impl<'a> System<'a> {
/// Returns the Machine /// Returns the Machine
/// ///
/// Useful to access RAM, devices, ... /// Useful to access RAM, devices, ...
pub fn get_g_machine(&mut self) -> &mut Machine { pub fn get_g_machine(&self) -> &RefCell<Machine> {
&mut self.g_machine &self.g_machine
} }
// Setters // Setters
/// Assign a machine to the system /// Assign a machine to the system
pub fn set_g_machine(&mut self, machine: Machine) { pub fn set_g_machine(&mut self, machine: RefCell<Machine>) {
self.g_machine = machine self.g_machine = machine
} }

View File

@ -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}}; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}};
const SIMULATORSTACKSIZE: usize = 32 * 1024;
const STACK_FENCEPOST: u32 = 0xdeadbeef; const STACK_FENCEPOST: u32 = 0xdeadbeef;
#[derive(PartialEq)] #[derive(PartialEq)]
struct ThreadContext { pub struct ThreadContext {
pub int_registers: [i64; NUM_INT_REGS], pub int_registers: [i64; NUM_INT_REGS],
pub float_registers: [i64; NUM_FP_REGS], pub float_registers: [f32; NUM_FP_REGS],
pc: i64, pc: i64,
} }
@ -16,8 +15,8 @@ pub struct Thread {
name: String, name: String,
pub process: Option<Process>, pub process: Option<Process>,
// simulation_context: UContextT, // simulation_context: UContextT,
thread_context: ThreadContext, pub thread_context: ThreadContext,
stack_pointer: i32, pub stack_pointer: i32,
object_type: ObjectType object_type: ObjectType
} }
@ -31,7 +30,7 @@ impl Thread {
// simulation_context: UContextT::new(), // simulation_context: UContextT::new(),
thread_context: ThreadContext { thread_context: ThreadContext {
int_registers: [0; NUM_INT_REGS], int_registers: [0; NUM_INT_REGS],
float_registers: [0; NUM_FP_REGS], float_registers: [0f32; NUM_FP_REGS],
pc: 0 pc: 0
}, },
stack_pointer: 0, stack_pointer: 0,
@ -60,27 +59,18 @@ impl Thread {
// self.simulation_context.stackBottom[0] = STACK_FENCEPOST; // 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 /// 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) { 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) { pub fn sleep(&self) {
todo!(); unreachable!("Has been moved to thread manager");
}
pub fn restore_processor_state(&self) {
todo!();
} }
pub fn save_simulator_state(&self) { pub fn save_simulator_state(&self) {

View File

@ -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}; 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)] #[derive(PartialEq)]
pub struct ThreadManager<'a> { pub struct ThreadManager<'a> {
@ -44,17 +44,54 @@ impl<'a> ThreadManager<'a> {
/// Wait for another thread to finish its execution /// Wait for another thread to finish its execution
pub fn thread_join(&mut self, id_thread: Rc<Thread>) { pub fn thread_join(&mut self, id_thread: Rc<Thread>) {
while self.get_g_alive().contains(&Rc::clone(&id_thread)) { 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. /// Relinquish the CPU if any other thread is runnable.
/// ///
/// Cannot use yield as a function name -> reserved name in rust /// 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<Thread>) {
todo!(); todo!();
} }
/// Put the thread to sleep and relinquish the processor
pub fn thread_sleep(&mut self, thread: Rc<Thread>) {
todo!();
}
/// Finish the execution of the thread and prepare its deallocation
pub fn thread_finish(&self, thread: Rc<Thread>) {
todo!();
}
pub fn thread_save_processor_state(&mut self, thread: Rc<RefCell<Thread>>) {
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<RefCell<Thread>>) {
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 /// Currently running thread
pub fn get_g_current_thread(&mut self) -> &mut Option<Thread> { pub fn get_g_current_thread(&mut self) -> &mut Option<Thread> {
&mut self.g_current_thread &mut self.g_current_thread

View File

@ -1,5 +1,5 @@
// use std::mem::MaybeUninit; use std::mem::MaybeUninit;
/// Safe wrapper for ucontext_t struct of linux-gnu libc /// Safe wrapper for ucontext_t struct of linux-gnu libc
/// ///
@ -12,10 +12,11 @@
pub struct UContextT { pub struct UContextT {
#[cfg(not(target_os = "windows"))] // struct non disponible sur la libc sur windows #[cfg(not(target_os = "windows"))] // struct non disponible sur la libc sur windows
pub buf: libc::ucontext_t, pub buf: libc::ucontext_t,
pub stackBottom: Vec<i8> pub stack_bottom: Vec<i8>
} }
#[cfg(not(target_os = "windows"))] #[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 { impl UContextT {
pub fn new() -> Self { pub fn new() -> Self {
@ -23,7 +24,7 @@ impl UContextT {
unsafe { libc::getcontext(context.as_mut_ptr()) }; unsafe { libc::getcontext(context.as_mut_ptr()) };
Self { Self {
buf: unsafe { context.assume_init() }, buf: unsafe { context.assume_init() },
stackBottom: Vec::default(), stack_bottom: Vec::default(),
} }
} }

View File

@ -2,7 +2,6 @@ use std::{ops::{Add, Sub}, io::Write};
use crate::simulator::print; use crate::simulator::print;
use super::{decode::{Instruction, decode}};
use super::{decode::{Instruction, decode}, interrupt::Interrupt}; use super::{decode::{Instruction, decode}, interrupt::Interrupt};
use super::global::*; use super::global::*;
use std::fs::File; use std::fs::File;
@ -74,15 +73,10 @@ pub struct Machine {
pub sp: usize, pub sp: usize,
pub int_reg : Register<i64>, pub int_reg : Register<i64>,
pub fp_reg : Register<f32>, pub fp_reg : Register<f32>,
<<<<<<< HEAD
pub main_memory : Vec<u8>,
pub shiftmask : [u64 ; 64],
pub registers_trace : String // for tests
=======
pub main_memory : [u8 ; MEM_SIZE], pub main_memory : [u8 ; MEM_SIZE],
pub shiftmask : [u64 ; 64], pub shiftmask : [u64 ; 64],
pub interrupt: Interrupt, pub registers_trace : String, // for tests
>>>>>>> 8c6ef4e (Implemente finish (not finished yet), fix ucontext for windows) pub interrupt: Interrupt
// futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize; // futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize;
//creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg //creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg
} }
@ -105,21 +99,14 @@ impl Machine {
sp: 0, sp: 0,
int_reg : Register::<i64>::init(), int_reg : Register::<i64>::init(),
fp_reg : Register::<f32>::init(), fp_reg : Register::<f32>::init(),
<<<<<<< HEAD main_memory : [0; MEM_SIZE],
main_memory : vec![0; MEM_SIZE],
shiftmask, shiftmask,
interrupt: Interrupt::new(),
registers_trace : String::from("") registers_trace : String::from("")
}; };
ret.int_reg.set_reg(10, -1); ret.int_reg.set_reg(10, -1);
ret ret
=======
main_memory : [0 ; MEM_SIZE],
shiftmask,
interrupt: Interrupt::new()
}
>>>>>>> 8c6ef4e (Implemente finish (not finished yet), fix ucontext for windows)
} }
/// Read from main memory of the machine /// Read from main memory of the machine
@ -690,6 +677,21 @@ impl Machine {
println!(); println!();
} }
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)] #[cfg(test)]