Add thread save and restore processor context

This commit is contained in:
Quentin Legot 2023-03-09 12:08:33 +01:00
parent fe4bbb2fc2
commit d392c69535
5 changed files with 83 additions and 37 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,
@ -59,28 +58,19 @@ impl Thread {
// self.simulation_context.stackBottom = base_stack_addr.to_vec(); // self.simulation_context.stackBottom = base_stack_addr.to_vec();
// 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

@ -616,6 +616,22 @@ impl Machine {
machine.pc += 8; 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)] #[cfg(test)]