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 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)]
|
||||||
|
Loading…
Reference in New Issue
Block a user