try to implement join
This commit is contained in:
parent
31f1e760e9
commit
c6f5818059
@ -278,7 +278,7 @@ fn sc_new_thread(machine: &mut Machine, system: &mut System) -> Result<MachineOk
|
|||||||
};
|
};
|
||||||
let current_thread = current_thread.borrow_mut();
|
let current_thread = current_thread.borrow_mut();
|
||||||
if let Some(process) = current_thread.get_process_owner() {
|
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);
|
system.get_thread_manager().start_thread(n_thread, Rc::clone(&process), func as u64, current_thread.thread_context.int_registers[2] as u64 + machine.page_size, args);
|
||||||
// TODO changé la valeur de sp quand on supportera les addresses virtuels
|
// TODO changé la valeur de sp quand on supportera les addresses virtuels
|
||||||
machine.write_int_register(10, tid as i64);
|
machine.write_int_register(10, tid as i64);
|
||||||
Ok(MachineOk::Ok)
|
Ok(MachineOk::Ok)
|
||||||
@ -319,7 +319,6 @@ fn get_length_param(addr: usize, machine: & Machine) -> usize {
|
|||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
println!("addr: {:x}, i: {}", addr, i + 1);
|
|
||||||
i + 1
|
i + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +333,6 @@ fn get_string_param(addr: usize, maxlen: usize, machine: &Machine) -> Vec<char>
|
|||||||
dest.push(c as char);
|
dest.push(c as char);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
dest.push('\0');
|
|
||||||
|
|
||||||
dest
|
dest
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{rc::Rc, cell::RefCell};
|
use std::{rc::Rc, cell::RefCell};
|
||||||
|
|
||||||
use super::process::Process;
|
use super::{process::Process, thread_manager::ThreadRef};
|
||||||
use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}};
|
use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, utility::list::List};
|
||||||
|
|
||||||
const STACK_FENCEPOST: u32 = 0xdeadbeef;
|
const STACK_FENCEPOST: u32 = 0xdeadbeef;
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ pub struct Thread {
|
|||||||
name: String,
|
name: String,
|
||||||
pub process: Option<Rc<RefCell<Process>>>,
|
pub process: Option<Rc<RefCell<Process>>>,
|
||||||
pub thread_context: ThreadContext,
|
pub thread_context: ThreadContext,
|
||||||
pub stack_pointer: i32,
|
pub join_thread: List<ThreadRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Thread {
|
impl Thread {
|
||||||
@ -40,9 +40,9 @@ impl Thread {
|
|||||||
thread_context: ThreadContext {
|
thread_context: ThreadContext {
|
||||||
int_registers: [0; NUM_INT_REGS],
|
int_registers: [0; NUM_INT_REGS],
|
||||||
float_registers: [0f32; NUM_FP_REGS],
|
float_registers: [0f32; NUM_FP_REGS],
|
||||||
pc: 0
|
pc: 0,
|
||||||
},
|
},
|
||||||
stack_pointer: 0,
|
join_thread: List::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +94,6 @@ mod test {
|
|||||||
float_registers: [0f32; NUM_FP_REGS],
|
float_registers: [0f32; NUM_FP_REGS],
|
||||||
pc: 0
|
pc: 0
|
||||||
};
|
};
|
||||||
x.stack_pointer = 0;
|
|
||||||
x }
|
x }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Using this type alias to simplify struct and method definitions
|
/// Using this type alias to simplify struct and method definitions
|
||||||
type ThreadRef = Rc<RefCell<Thread>>;
|
pub type ThreadRef = Rc<RefCell<Thread>>;
|
||||||
|
|
||||||
/// # Thread manager
|
/// # Thread manager
|
||||||
///
|
///
|
||||||
@ -186,6 +186,8 @@ impl ThreadManager {
|
|||||||
|
|
||||||
/// Start a thread, attaching it to a process
|
/// Start a thread, attaching it to a process
|
||||||
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
|
pub fn start_thread(&mut self, thread: ThreadRef, owner: Rc<RefCell<Process>>, func_pc: u64, sp_loc: u64, argument: i64) {
|
||||||
|
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
|
||||||
|
|
||||||
let mut thread_m = thread.borrow_mut();
|
let mut thread_m = thread.borrow_mut();
|
||||||
assert_eq!(thread_m.process, Option::None);
|
assert_eq!(thread_m.process, Option::None);
|
||||||
thread_m.process = Option::Some(Rc::clone(&owner));
|
thread_m.process = Option::Some(Rc::clone(&owner));
|
||||||
@ -199,23 +201,29 @@ impl ThreadManager {
|
|||||||
/// Wait for another thread to finish its execution
|
/// Wait for another thread to finish its execution
|
||||||
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
|
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
|
||||||
let waiting_for = Rc::clone(&waiting_for);
|
let waiting_for = Rc::clone(&waiting_for);
|
||||||
while self.get_g_alive().contains(&waiting_for) {
|
if self.get_g_alive().contains(&waiting_for) {
|
||||||
self.debug(format!("Joining \"{}\" to \"{}\"", waiter.borrow().get_name(), waiting_for.borrow().get_name()));
|
waiting_for.borrow_mut().join_thread.push(Rc::clone(&waiter));
|
||||||
self.thread_yield(machine, Rc::clone(&waiter));
|
self.thread_yield(machine, Rc::clone(&waiter), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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, machine: &mut Machine, thread: ThreadRef) {
|
///
|
||||||
|
/// ## Parameters
|
||||||
|
///
|
||||||
|
/// **is_ready** true if **thread** should be readded to ready_to_run list, false otherwise. Typically false when joining per example
|
||||||
|
pub fn thread_yield(&mut self, machine: &mut Machine, thread: ThreadRef, is_ready: bool) {
|
||||||
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff);
|
||||||
|
|
||||||
self.debug(format!("Yeilding thread: {}", thread.borrow().get_name()));
|
self.debug(format!("Yeilding thread: \"{}\"", thread.borrow().get_name()));
|
||||||
debug_assert_eq!(&Option::Some(Rc::clone(&thread)), self.get_g_current_thread());
|
debug_assert_eq!(&Option::Some(Rc::clone(&thread)), self.get_g_current_thread());
|
||||||
let next_thread = self.find_next_to_run();
|
let next_thread = self.find_next_to_run();
|
||||||
if let Some(next_thread) = next_thread {
|
if let Some(next_thread) = next_thread {
|
||||||
|
if is_ready {
|
||||||
self.ready_to_run(thread);
|
self.ready_to_run(thread);
|
||||||
|
}
|
||||||
self.switch_to(machine, next_thread);
|
self.switch_to(machine, next_thread);
|
||||||
}
|
}
|
||||||
machine.interrupt.set_status(old_status);
|
machine.interrupt.set_status(old_status);
|
||||||
@ -226,6 +234,7 @@ impl ThreadManager {
|
|||||||
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
debug_assert_eq!(Option::Some(Rc::clone(&thread)), self.g_current_thread);
|
||||||
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
debug_assert_eq!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
|
||||||
|
|
||||||
|
self.debug(format!("Sleeping thread {}", thread.borrow().get_name()));
|
||||||
let mut next_thread = self.find_next_to_run();
|
let mut next_thread = self.find_next_to_run();
|
||||||
while next_thread.is_none() {
|
while next_thread.is_none() {
|
||||||
eprintln!("Nobody to run => idle");
|
eprintln!("Nobody to run => idle");
|
||||||
@ -240,8 +249,11 @@ impl ThreadManager {
|
|||||||
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef) {
|
||||||
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
|
||||||
assert!(self.g_alive.remove(Rc::clone(&thread)));
|
assert!(self.g_alive.remove(Rc::clone(&thread)));
|
||||||
self.debug(format!("Sleeping thread {}", thread.borrow().get_name()));
|
self.debug(format!("Finishing thread {}", thread.borrow().get_name()));
|
||||||
// g_objets_addrs->removeObject(self.thread) // a ajouté plus tard
|
// g_objets_addrs->removeObject(self.thread) // a ajouté plus tard
|
||||||
|
for (_, el) in thread.borrow().join_thread.iter().enumerate() {
|
||||||
|
self.ready_to_run(Rc::clone(&el));
|
||||||
|
}
|
||||||
self.thread_sleep(machine, Rc::clone(&thread));
|
self.thread_sleep(machine, Rc::clone(&thread));
|
||||||
machine.interrupt.set_status(old_status);
|
machine.interrupt.set_status(old_status);
|
||||||
}
|
}
|
||||||
@ -432,7 +444,7 @@ mod test {
|
|||||||
|
|
||||||
let owner1 = Process { num_thread: 0 };
|
let owner1 = Process { num_thread: 0 };
|
||||||
let owner1 = Rc::new(RefCell::new(owner1));
|
let owner1 = Rc::new(RefCell::new(owner1));
|
||||||
system.get_thread_manager().start_thread(Rc::clone(&thread1), owner1, loader.elf_header.entrypoint, ptr, -1);
|
system.get_thread_manager().start_thread(Rc::clone(&thread1), owner1, loader.elf_header.entrypoint, ptr + machine.page_size, -1);
|
||||||
debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc);
|
debug_assert_eq!(thread1.borrow_mut().thread_context.pc, start_pc);
|
||||||
debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1)));
|
debug_assert!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1)));
|
||||||
|
|
||||||
|
18
src/main.rs
18
src/main.rs
@ -21,7 +21,7 @@ use simulator::{machine::Machine, loader};
|
|||||||
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use utility::cfg::{get_debug_configuration, read_settings};
|
use utility::cfg::read_settings;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(name = "BurritOS", author, version, about = "Burritos (BurritOS Using Rust Really Improves The Operating System)
|
#[command(name = "BurritOS", author, version, about = "Burritos (BurritOS Using Rust Really Improves The Operating System)
|
||||||
@ -30,9 +30,13 @@ Burritos is an educational operating system written in Rust
|
|||||||
running on RISC-V emulator.", long_about = None)]
|
running on RISC-V emulator.", long_about = None)]
|
||||||
/// Launch argument parser
|
/// Launch argument parser
|
||||||
struct Args {
|
struct Args {
|
||||||
/// Enable debug mode
|
/// Enable debug mode.
|
||||||
#[arg(short, long)]
|
/// 0 to disable debug,
|
||||||
debug: bool,
|
/// 1 to enable machine debug,
|
||||||
|
/// 2 to enable system debug,
|
||||||
|
/// 3 to enable all debug
|
||||||
|
#[arg(short, long, value_parser = clap::value_parser!(u8).range(0..=3))]
|
||||||
|
debug: u8,
|
||||||
/// Path to the executable binary file to execute
|
/// Path to the executable binary file to execute
|
||||||
#[arg(short = 'x', long, value_name = "PATH")]
|
#[arg(short = 'x', long, value_name = "PATH")]
|
||||||
executable: String
|
executable: String
|
||||||
@ -41,10 +45,10 @@ struct Args {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let mut machine = Machine::new(args.debug, read_settings().unwrap());
|
let mut machine = Machine::new(args.debug & 1 != 0, read_settings().unwrap());
|
||||||
let (loader, ptr) = loader::Loader::new(args.executable.as_str(), &mut machine, 0).expect("An error occured while parsing the program");
|
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::new(args.debug);
|
let mut system = System::new(args.debug & 2 != 0);
|
||||||
|
|
||||||
let thread_exec = Thread::new(args.executable.as_str());
|
let thread_exec = Thread::new(args.executable.as_str());
|
||||||
let thread_exec = Rc::new(RefCell::new(thread_exec));
|
let thread_exec = Rc::new(RefCell::new(thread_exec));
|
||||||
@ -52,7 +56,7 @@ fn main() {
|
|||||||
|
|
||||||
let owner1 = Process { num_thread: 0 };
|
let owner1 = Process { num_thread: 0 };
|
||||||
let owner1 = Rc::new(RefCell::new(owner1));
|
let owner1 = Rc::new(RefCell::new(owner1));
|
||||||
system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, ptr, -1);
|
system.get_thread_manager().start_thread(Rc::clone(&thread_exec), owner1, loader.elf_header.entrypoint, ptr + machine.page_size, -1);
|
||||||
|
|
||||||
let to_run = system.get_thread_manager().find_next_to_run().unwrap();
|
let to_run = system.get_thread_manager().find_next_to_run().unwrap();
|
||||||
system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));
|
system.get_thread_manager().switch_to(&mut machine, Rc::clone(&to_run));
|
||||||
|
@ -95,7 +95,7 @@ pub struct Machine {
|
|||||||
// 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
|
||||||
num_phy_page: u64,
|
num_phy_page: u64,
|
||||||
page_size: u64,
|
pub page_size: u64,
|
||||||
/// Current machine status
|
/// Current machine status
|
||||||
pub status: MachineStatus
|
pub status: MachineStatus
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,10 @@ use std::ptr;
|
|||||||
/// These methods wrap unsafe instructions because it doesn't respect borrow rules per example
|
/// These methods wrap unsafe instructions because it doesn't respect borrow rules per example
|
||||||
/// but everything has been tested with miri to assure there's no Undefined Behaviour (use-after-free, double free, etc.)
|
/// but everything has been tested with miri to assure there's no Undefined Behaviour (use-after-free, double free, etc.)
|
||||||
/// or memory leak
|
/// or memory leak
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct List<T: PartialEq> {
|
pub struct List<T: PartialEq> {
|
||||||
head: Link<T>,
|
head: Link<T>,
|
||||||
tail: *mut Node<T>,
|
tail: Link<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Link<T> = *mut Node<T>;
|
type Link<T> = *mut Node<T>;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
PROGRAMS = halt.guac prints.guac producteur_consommateur.guac
|
PROGRAMS = halt.guac prints.guac producteur_consommateur.guac join.guac
|
||||||
TOPDIR = ../..
|
TOPDIR = ../..
|
||||||
include $(TOPDIR)/Makefile.rules
|
include $(TOPDIR)/Makefile.rules
|
||||||
|
|
||||||
|
36
test/syscall_tests/join.c
Normal file
36
test/syscall_tests/join.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#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 th1();
|
||||||
|
|
||||||
|
void th2();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ThreadId th1 = threadCreate("th1", th1);
|
||||||
|
ThreadId th2 = threadCreate("th2", th2);
|
||||||
|
Join(th1);
|
||||||
|
Join(th2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void th1() {
|
||||||
|
for(int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
n_printf("Hello from th1\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void th2() {
|
||||||
|
for(int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
n_printf("Hello from th2\n");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user