Add thread save and restore processor context
This commit is contained in:
parent
0c3af96b78
commit
26b75ffe8d
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
@ -60,27 +59,18 @@ impl Thread {
|
||||
// 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) {
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ use std::{ops::{Add, Sub}, io::Write};
|
||||
|
||||
use crate::simulator::print;
|
||||
|
||||
use super::{decode::{Instruction, decode}};
|
||||
use super::{decode::{Instruction, decode}, interrupt::Interrupt};
|
||||
use super::global::*;
|
||||
use std::fs::File;
|
||||
@ -74,15 +73,10 @@ pub struct Machine {
|
||||
pub sp: usize,
|
||||
pub int_reg : Register<i64>,
|
||||
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 shiftmask : [u64 ; 64],
|
||||
pub interrupt: Interrupt,
|
||||
>>>>>>> 8c6ef4e (Implemente finish (not finished yet), fix ucontext for windows)
|
||||
pub registers_trace : String, // for tests
|
||||
pub interrupt: Interrupt
|
||||
// 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
|
||||
}
|
||||
@ -105,21 +99,14 @@ impl Machine {
|
||||
sp: 0,
|
||||
int_reg : Register::<i64>::init(),
|
||||
fp_reg : Register::<f32>::init(),
|
||||
<<<<<<< HEAD
|
||||
main_memory : vec![0; MEM_SIZE],
|
||||
main_memory : [0; MEM_SIZE],
|
||||
shiftmask,
|
||||
interrupt: Interrupt::new(),
|
||||
registers_trace : String::from("")
|
||||
};
|
||||
|
||||
ret.int_reg.set_reg(10, -1);
|
||||
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
|
||||
@ -690,6 +677,21 @@ impl Machine {
|
||||
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)]
|
||||
|
Loading…
Reference in New Issue
Block a user