try to implement join

This commit is contained in:
Quentin Legot
2023-04-23 15:11:06 +02:00
parent 1055e6a0ac
commit a211e93905
8 changed files with 79 additions and 31 deletions

View File

@ -102,7 +102,7 @@ use crate::{
};
/// Using this type alias to simplify struct and method definitions
type ThreadRef = Rc<RefCell<Thread>>;
pub type ThreadRef = Rc<RefCell<Thread>>;
/// # Thread manager
///
@ -186,6 +186,8 @@ impl ThreadManager {
/// 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) {
self.debug(format!("starting thread \"{}\"", thread.borrow().get_name()));
let mut thread_m = thread.borrow_mut();
assert_eq!(thread_m.process, Option::None);
thread_m.process = Option::Some(Rc::clone(&owner));
@ -199,23 +201,29 @@ impl ThreadManager {
/// Wait for another thread to finish its execution
pub fn thread_join(&mut self, machine: &mut Machine, waiter: ThreadRef, waiting_for: ThreadRef) {
let waiting_for = Rc::clone(&waiting_for);
while self.get_g_alive().contains(&waiting_for) {
self.debug(format!("Joining \"{}\" to \"{}\"", waiter.borrow().get_name(), waiting_for.borrow().get_name()));
self.thread_yield(machine, Rc::clone(&waiter));
if self.get_g_alive().contains(&waiting_for) {
waiting_for.borrow_mut().join_thread.push(Rc::clone(&waiter));
self.thread_yield(machine, Rc::clone(&waiter), false);
}
}
/// 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, 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);
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());
let next_thread = self.find_next_to_run();
if let Some(next_thread) = next_thread {
self.ready_to_run(thread);
if is_ready {
self.ready_to_run(thread);
}
self.switch_to(machine, next_thread);
}
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!(machine.interrupt.get_status(), InterruptStatus::InterruptOff);
self.debug(format!("Sleeping thread {}", thread.borrow().get_name()));
let mut next_thread = self.find_next_to_run();
while next_thread.is_none() {
eprintln!("Nobody to run => idle");
@ -240,8 +249,11 @@ impl ThreadManager {
pub fn thread_finish(&mut self, machine: &mut Machine, thread: ThreadRef) {
let old_status = machine.interrupt.set_status(InterruptStatus::InterruptOff);
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
for (_, el) in thread.borrow().join_thread.iter().enumerate() {
self.ready_to_run(Rc::clone(&el));
}
self.thread_sleep(machine, Rc::clone(&thread));
machine.interrupt.set_status(old_status);
}
@ -432,7 +444,7 @@ mod test {
let owner1 = Process { num_thread: 0 };
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!(system.get_thread_manager().get_g_alive().contains(&Rc::clone(&thread1)));