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 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<Machine>,
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<Machine> {
&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<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}};
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<Process>,
// 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) {

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};
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<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.
///
/// 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!();
}
/// 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
pub fn get_g_current_thread(&mut self) -> &mut Option<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
///
@ -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<i8>
pub stack_bottom: Vec<i8>
}
#[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(),
}
}

View File

@ -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)]