loader now return better understanable errors, fix when compiler when to use bss section, add join exception, fix get_string_param, add support for thread in obbAddr, add a test
This commit is contained in:
parent
05f72af035
commit
f144438490
@ -3,7 +3,7 @@ use std::{cell::RefCell, rc::Rc};
|
||||
use crate::{simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}};
|
||||
use crate::kernel::synch::{Lock, Semaphore};
|
||||
|
||||
use super::{system::System, thread::Thread};
|
||||
use super::{system::{System, self}, thread::Thread};
|
||||
|
||||
/// The halt system call. Stops Burritos.
|
||||
pub const SC_SHUTDOWN: u8 = 0;
|
||||
@ -142,7 +142,7 @@ fn syscall(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Mach
|
||||
Ok(MachineOk::Ok)
|
||||
},
|
||||
SC_EXEC => todo!(),
|
||||
SC_JOIN => todo!(),
|
||||
SC_JOIN => sc_join(machine, system),
|
||||
SC_CREATE => todo!(),
|
||||
SC_OPEN => todo!(),
|
||||
SC_READ => todo!(),
|
||||
@ -231,7 +231,7 @@ fn sc_v(machine: &mut Machine, system: &mut System) -> Result<MachineOk, Machine
|
||||
fn sc_sem_create(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
|
||||
let addr_name = machine.read_int_register(10) as usize;
|
||||
let initial_count = machine.read_int_register(11) as i32;
|
||||
let size = get_length_param(addr_name as usize, machine);
|
||||
let size = get_length_param(addr_name, machine);
|
||||
let _name = get_string_param(addr_name, size, machine);
|
||||
match initial_count < 0 {
|
||||
true => Err(format!("Initial_count < 0"))?,
|
||||
@ -262,6 +262,7 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
|
||||
|
||||
let n_thread = Thread::new(thread_name.as_str());
|
||||
let n_thread = Rc::new(RefCell::new(n_thread));
|
||||
let tid = system.get_thread_manager().get_obj_addrs().add_thread(Rc::clone(&n_thread));
|
||||
let current_thread = match system.get_thread_manager().get_g_current_thread() {
|
||||
Some(th) => {
|
||||
Rc::clone(th)
|
||||
@ -274,25 +275,49 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
|
||||
if let Some(process) = current_thread.get_process_owner() {
|
||||
system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, current_thread.thread_context.int_registers[2] as u64, args);
|
||||
// TODO changé la valeur de sp quand on supportera les addresses virtuels
|
||||
// machine.write_fp_register(10, tid); // tid obtenu en faisant int32_t tid = g_object_addrs->AddObject(ptThread);
|
||||
machine.write_int_register(10, tid as i64);
|
||||
Ok(MachineOk::Ok)
|
||||
} else {
|
||||
return Err("Process owner of current thread is none")?;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_length_param(addr: usize, machine: & Machine) -> usize{
|
||||
fn sc_join(machine: &mut Machine, system: &mut System) -> Result<MachineOk, MachineError> {
|
||||
let tid = machine.read_int_register(10);
|
||||
let p_thread = system.get_thread_manager().get_obj_addrs().search_thread(tid as i32);
|
||||
match p_thread {
|
||||
Some(_) => {
|
||||
if let Some(current_thread) = system.get_thread_manager().get_g_current_thread() {
|
||||
let rc = Rc::clone(current_thread);
|
||||
system.get_thread_manager().thread_join(machine, rc);
|
||||
|
||||
Ok(MachineOk::Ok)
|
||||
} else {
|
||||
Ok(MachineOk::Ok)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// Thread already terminated (type set to INVALID_TYPE) or call on an object
|
||||
// that is not a thread
|
||||
// Exit with no error code since we cannot separate the two cases
|
||||
Ok(MachineOk::Ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_length_param(addr: usize, machine: & Machine) -> usize {
|
||||
let mut i = 0;
|
||||
let mut c = 1;
|
||||
while c!= 0 {
|
||||
while c != 0 {
|
||||
c = machine.read_memory(1, addr + i);
|
||||
i+=1;
|
||||
i +=1;
|
||||
|
||||
}
|
||||
println!("addr: {:x}, i: {}", addr, i + 1);
|
||||
i + 1
|
||||
}
|
||||
|
||||
fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>{
|
||||
fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char> {
|
||||
let mut dest = Vec::with_capacity(maxlen);
|
||||
|
||||
let mut i: usize = 0;
|
||||
@ -300,12 +325,10 @@ fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>{
|
||||
|
||||
while c != 0 && i < maxlen {
|
||||
c = machine.read_memory(1, addr + i) as u8;
|
||||
//dest.push(c as char);
|
||||
dest[i] = c as char;
|
||||
dest.push(c as char);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
dest[maxlen - 1] = '\0';
|
||||
dest.push('\0');
|
||||
|
||||
dest
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let mut machine = Machine::new(args.debug);
|
||||
let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("IO Error");
|
||||
let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("An error occured while parsing the program");
|
||||
|
||||
let mut system = System::default();
|
||||
|
||||
|
@ -213,23 +213,23 @@ impl ElfHeader {
|
||||
}
|
||||
|
||||
impl TryFrom<&Vec<u8>> for ElfHeader {
|
||||
type Error = ();
|
||||
type Error = String;
|
||||
|
||||
fn try_from(instructions: &Vec<u8>) -> Result<Self, Self::Error> {
|
||||
if Self::is_elf(instructions) {
|
||||
let format = Self::is_32bits(instructions);
|
||||
let endianess = Self::check_endianess(instructions);
|
||||
let version = Self::get_version(instructions).ok_or(())?;
|
||||
let version = Self::get_version(instructions).ok_or("Cannot retrieve version")?;
|
||||
let is_sys_v_abi = Self::is_system_v_elf(instructions);
|
||||
let is_rv_target = Self::is_riscv_isa(instructions);
|
||||
let entrypoint = Self::get_entrypoint(instructions, format).ok_or(())?;
|
||||
let elf_header_size = Self::get_elf_header_size(instructions, format).ok_or(())?;
|
||||
let program_header_location = Self::get_program_header_table_location(instructions, format).ok_or(())?;
|
||||
let program_header_entries = Self::get_number_entries_program_header(instructions, format).ok_or(())? ;
|
||||
let program_header_size = Self::get_program_header_size(instructions, format).ok_or(())?;
|
||||
let section_header_location = Self::get_section_header_table_location(instructions, format).ok_or(())?;
|
||||
let section_header_entries = Self::get_section_header_num_entries(instructions, format).ok_or(())?;
|
||||
let section_header_size = Self::get_section_header_size(instructions, format).ok_or(())?;
|
||||
let entrypoint = Self::get_entrypoint(instructions, format).ok_or("Cannot get entrypoint")?;
|
||||
let elf_header_size = Self::get_elf_header_size(instructions, format).ok_or("Cannot get elf header size")?;
|
||||
let program_header_location = Self::get_program_header_table_location(instructions, format).ok_or("Cannot get program header table location")?;
|
||||
let program_header_entries = Self::get_number_entries_program_header(instructions, format).ok_or("Cannot get number of entries in program header table")? ;
|
||||
let program_header_size = Self::get_program_header_size(instructions, format).ok_or("Cannot get program header entry size")?;
|
||||
let section_header_location = Self::get_section_header_table_location(instructions, format).ok_or("Cannot get section header table location")?;
|
||||
let section_header_entries = Self::get_section_header_num_entries(instructions, format).ok_or("Cannot get number of entries of section header")?;
|
||||
let section_header_size = Self::get_section_header_size(instructions, format).ok_or("Cannot get size of section header entry")?;
|
||||
Ok(ElfHeader {
|
||||
endianess,
|
||||
is_32bits: format,
|
||||
@ -246,7 +246,7 @@ impl TryFrom<&Vec<u8>> for ElfHeader {
|
||||
section_header_size
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
Err("File doesn't have elf magic number")?
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -409,7 +409,7 @@ pub enum LoaderError {
|
||||
/// Correspond to std IO error
|
||||
IOError(std::io::Error),
|
||||
/// Others errors
|
||||
ParsingError
|
||||
ParsingError(String)
|
||||
}
|
||||
|
||||
/// Global structure of the loader, one instance per loaded files
|
||||
@ -455,7 +455,13 @@ impl Loader {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for k in 0..buf.len() {
|
||||
buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError)?;
|
||||
if section.does_flag_contains_key(FlagValue::ShfWrite) {
|
||||
// flag WA, on doit allouer des données initialisés à 0
|
||||
// généralement, ce signifie que le compilateur à ajouter une section .bss
|
||||
buf[k] = 0;
|
||||
} else {
|
||||
buf[k] = self.bytes.get(section.image_offset as usize + j + k).copied().ok_or(LoaderError::ParsingError(format!("index 0x{:x} is out of bound because list have a size of 0x{:x} (image offset 0x{:x}, j 0x{:x}, k 0x{:x})", section.image_offset as usize + j + k, self.bytes.len(), section.image_offset, j, k)))?;
|
||||
}
|
||||
}
|
||||
machine.write_memory(4, start_index + section.virt_addr as usize + j, u32::from_le_bytes(buf) as u64);
|
||||
}
|
||||
@ -492,8 +498,8 @@ impl Loader {
|
||||
Ok(header) => {
|
||||
header
|
||||
},
|
||||
Err(_) => {
|
||||
return Err(LoaderError::ParsingError);
|
||||
Err(err) => {
|
||||
return Err(LoaderError::ParsingError(format!("Cannot parse elf header : {}", err)));
|
||||
}
|
||||
};
|
||||
let section_header = match Self::parse_section_header(&instructions, elf_header.is_32bits, elf_header.section_header_location, elf_header.section_header_entries, elf_header.section_header_size) {
|
||||
@ -501,7 +507,7 @@ impl Loader {
|
||||
header
|
||||
},
|
||||
Err(_) => {
|
||||
return Err(LoaderError::ParsingError);
|
||||
return Err(LoaderError::ParsingError("Cannot parse section header".to_string()));
|
||||
}
|
||||
};
|
||||
// #[cfg(debug_assertions)]
|
||||
|
@ -2,9 +2,9 @@
|
||||
//! their references. The ObjAddr struct
|
||||
//! allows to maintain this data structure.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, cell::RefCell, rc::Rc};
|
||||
|
||||
use crate::kernel::synch::{ Semaphore, Lock };
|
||||
use crate::kernel::{synch::{ Semaphore, Lock }, thread::Thread};
|
||||
|
||||
/// Brief Definition of object identifiers:
|
||||
///
|
||||
@ -19,7 +19,8 @@ use crate::kernel::synch::{ Semaphore, Lock };
|
||||
pub struct ObjAddr {
|
||||
last_id: i32,
|
||||
semaphores: HashMap<i32, Semaphore>,
|
||||
locks: HashMap<i32, Lock>
|
||||
locks: HashMap<i32, Lock>,
|
||||
threads: HashMap<i32, Rc<RefCell<Thread>>>,
|
||||
}
|
||||
|
||||
impl ObjAddr {
|
||||
@ -29,7 +30,8 @@ impl ObjAddr {
|
||||
Self {
|
||||
last_id: 3,
|
||||
semaphores: HashMap::<i32, Semaphore>::new(),
|
||||
locks: HashMap::<i32, Lock>::new()
|
||||
locks: HashMap::<i32, Lock>::new(),
|
||||
threads: HashMap::<i32, Rc<RefCell<Thread>>>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,6 +49,13 @@ impl ObjAddr {
|
||||
self.last_id
|
||||
}
|
||||
|
||||
/// Adds the **obj** Lock to self
|
||||
pub fn add_thread(&mut self, obj: Rc<RefCell<Thread>>) -> i32 {
|
||||
self.last_id +=1;
|
||||
self.threads.insert(self.last_id, obj);
|
||||
self.last_id
|
||||
}
|
||||
|
||||
/// Searches for a semaphore of id **id** in self
|
||||
pub fn search_semaphore(&mut self, id: i32) -> Option<&mut Semaphore> {
|
||||
self.semaphores.get_mut(&id)
|
||||
@ -57,6 +66,11 @@ impl ObjAddr {
|
||||
self.locks.get_mut(&id)
|
||||
}
|
||||
|
||||
/// Searches for a lock of id **id** in self
|
||||
pub fn search_thread(&mut self, id: i32) -> Option<&Rc<RefCell<Thread>>> {
|
||||
self.threads.get(&id)
|
||||
}
|
||||
|
||||
/// Removes the object of id **id** from self if it exists
|
||||
pub fn remove_semaphore(&mut self, id: i32) -> Option<Semaphore> {
|
||||
self.semaphores.remove(&id)
|
||||
@ -67,5 +81,10 @@ impl ObjAddr {
|
||||
self.locks.remove(&id)
|
||||
}
|
||||
|
||||
/// Remove the object of id **id** from self if it exists
|
||||
pub fn remove_thread(&mut self, id: i32) -> Option<Rc<RefCell<Thread>>> {
|
||||
self.threads.remove(&id)
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
PROGRAMS = halt.guac prints.guac
|
||||
PROGRAMS = halt.guac prints.guac producteur_consommateur.guac
|
||||
TOPDIR = ../..
|
||||
include $(TOPDIR)/Makefile.rules
|
||||
|
||||
|
48
test/syscall_tests/producteur_consommateur.c
Normal file
48
test/syscall_tests/producteur_consommateur.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include "userlib/syscall.h"
|
||||
#include "userlib/libnachos.h"
|
||||
|
||||
|
||||
const int N = 3;
|
||||
int iplein = 0;
|
||||
int ivide = 0;
|
||||
int tab[3];
|
||||
SemId svide;
|
||||
SemId splein;
|
||||
|
||||
void producteur();
|
||||
|
||||
void consommateur();
|
||||
|
||||
int main() {
|
||||
svide = SemCreate("producteur", N);
|
||||
splein = SemCreate("consommateur", 0);
|
||||
ThreadId producteurTh = threadCreate("producteur", producteur);
|
||||
ThreadId consommateurTh = threadCreate("consommateur", consommateur);
|
||||
Join(producteurTh);
|
||||
Join(consommateurTh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void producteur() {
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
n_printf("batir une information\n");
|
||||
P(svide);
|
||||
iplein = (iplein + 1) % N;
|
||||
n_printf("communique une information : %d\n", i);
|
||||
tab[iplein] = i;
|
||||
V(splein);
|
||||
}
|
||||
}
|
||||
|
||||
void consommateur() {
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
P(splein);
|
||||
ivide = (ivide +1) % N;
|
||||
n_printf("recevoir une information\n");
|
||||
int info = tab[ivide];
|
||||
V(svide);
|
||||
n_printf("exploiter l'information : %d\n", info);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user