From f1f57a76e1d95835cacc94c65bdb2acd4582c015 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 15 Feb 2023 14:56:11 +0100 Subject: [PATCH 01/37] Add kernel mod --- src/kernel/mod.rs | 2 ++ src/kernel/scheduler.rs | 0 src/kernel/thread.rs | 0 src/main.rs | 1 + 4 files changed, 3 insertions(+) create mode 100644 src/kernel/mod.rs create mode 100644 src/kernel/scheduler.rs create mode 100644 src/kernel/thread.rs diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs new file mode 100644 index 0000000..447d11e --- /dev/null +++ b/src/kernel/mod.rs @@ -0,0 +1,2 @@ +mod thread; +mod scheduler; \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index 4acaaf7..831fcfc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod simulator; +mod kernel; use simulator::machine::Machine; From bd0b6e17a5799b713e6a3e6172098a1b7e22c0ec Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 15 Feb 2023 18:10:08 +0100 Subject: [PATCH 02/37] Add double linked list --- src/main.rs | 1 + src/utility/list.rs | 142 ++++++++++++++++++++++++++++++++++++++++++++ src/utility/mod.rs | 1 + 3 files changed, 144 insertions(+) create mode 100644 src/utility/list.rs create mode 100644 src/utility/mod.rs diff --git a/src/main.rs b/src/main.rs index 831fcfc..986cf3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod simulator; mod kernel; +pub mod utility; use simulator::machine::Machine; diff --git a/src/utility/list.rs b/src/utility/list.rs new file mode 100644 index 0000000..6b0ddbb --- /dev/null +++ b/src/utility/list.rs @@ -0,0 +1,142 @@ +use std::{cell::RefCell, rc::Rc}; + +/// Definition of an element of the list +/// +/// Contain one stored item and the previous/next element of the list +struct ListNode { + item: T, + next: Link, + prev: Link, +} + +impl ListNode { + fn new(item: T) -> Self { + Self { + item, + next: None, + prev: None, + } + } +} + +type Link = Option>>>; + +/// Defintion of the generic linked list +#[derive(Default)] +pub struct DoublyLinkedList { + head: Link, + tail: Link, + size: usize, +} + +impl DoublyLinkedList { + + pub fn new() -> Self { + Self { + head: None, + tail: None, + size: 0, + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn len(&self) -> usize { + self.size + } + + /// Add the item at the end of the list + pub fn push_back(&mut self, item: T) { + let node = Rc::new(RefCell::new(ListNode::new(item))); + if let Some(prev_tail) = self.tail.take() { + prev_tail.borrow_mut().next = Some(Rc::clone(&node)); + node.borrow_mut().prev = Some(prev_tail); + self.tail = Some(node); + self.size += 1; + } else { + self.head = Some(Rc::clone(&node)); + self.tail = Some(node); + self.size = 1; + } + } + + /// Add the item at the start of the list + pub fn push_front(&mut self, item: T) { + let node = Rc::new(RefCell::new(ListNode::new(item))); + if let Some(prev_head) = self.head.take() { + prev_head.borrow_mut().prev = Some(Rc::clone(&node)); + node.borrow_mut().next = Some(prev_head); + self.head = Some(node); + self.size += 1; + } else { + self.head = Some(Rc::clone(&node)); + self.tail = Some(node); + self.size = 1; + } + } + + /// Remove the item at the end of the list + pub fn pop_back(&mut self) -> Option { + self.tail.take().map(|prev_tail| { + self.size -= 1; + match prev_tail.borrow_mut().prev.take() { + Some(node) => { + node.borrow_mut().next = None; + self.tail = Some(node); + } + None => { + self.head.take(); + } + } + Rc::try_unwrap(prev_tail).ok().unwrap().into_inner().item + }) + } + + /// Remove the item at the start of the list + pub fn pop_front(&mut self) -> Option { + self.head.take().map(|prev_head| { + self.size -= 1; + match prev_head.borrow_mut().next.take() { + Some(node) => { + node.borrow_mut().prev = None; + self.head = Some(node); + } + None => { + self.tail.take(); + } + } + Rc::try_unwrap(prev_head).ok().unwrap().into_inner().item + }) + } + +} + +impl Drop for DoublyLinkedList { + /// list destructor, safely desallocate smart pointer Rc + fn drop(&mut self) { + while let Some(node) = self.head.take() { + let _ = node.borrow_mut().prev.take(); + self.head = node.borrow_mut().next.take(); + } + self.tail.take(); + } +} + +#[cfg(test)] +mod test { + + use super::DoublyLinkedList; + + #[test] + fn test_list_push() { + let mut list = DoublyLinkedList::new(); + list.push_back(5); + list.push_front(45); + assert_eq!(list.pop_front().unwrap(), 45); + assert_eq!(list.pop_front().unwrap(), 5); + } + + +} \ No newline at end of file diff --git a/src/utility/mod.rs b/src/utility/mod.rs new file mode 100644 index 0000000..651aed7 --- /dev/null +++ b/src/utility/mod.rs @@ -0,0 +1 @@ +pub mod list; \ No newline at end of file From fd6b22a2f36f13d2bba293f16770228f3189e836 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Fri, 17 Feb 2023 09:45:47 +0100 Subject: [PATCH 03/37] Improve list by adding iterator trait --- src/utility/list.rs | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/utility/list.rs b/src/utility/list.rs index 6b0ddbb..46f5557 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -77,7 +77,7 @@ impl DoublyLinkedList { } } - /// Remove the item at the end of the list + /// Retrieve and remove the item at the end of the list pub fn pop_back(&mut self) -> Option { self.tail.take().map(|prev_tail| { self.size -= 1; @@ -94,7 +94,7 @@ impl DoublyLinkedList { }) } - /// Remove the item at the start of the list + /// Retrieve and remove the item at the start of the list pub fn pop_front(&mut self) -> Option { self.head.take().map(|prev_head| { self.size -= 1; @@ -124,6 +124,43 @@ impl Drop for DoublyLinkedList { } } +impl IntoIterator for DoublyLinkedList { + type Item = as Iterator>::Item; + + type IntoIter = ListIterator; + + fn into_iter(self) -> Self::IntoIter { + Self::IntoIter::new(self) + } +} + +pub struct ListIterator { + list: DoublyLinkedList, +} + +impl ListIterator { + fn new(list: DoublyLinkedList) -> Self { + Self { list } + } +} + +impl Iterator for ListIterator { + type Item = T; + + fn next(&mut self) -> Option { + self.list.pop_front() + } +} + +impl DoubleEndedIterator for ListIterator { + fn next_back(&mut self) -> Option { + self.list.pop_back() + } +} + +pub type List = DoublyLinkedList; +pub type ListInt = List; + #[cfg(test)] mod test { @@ -138,5 +175,4 @@ mod test { assert_eq!(list.pop_front().unwrap(), 5); } - } \ No newline at end of file From e422e657672362f1f7eaf8274e025f8c592d4a9a Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 28 Feb 2023 14:43:40 +0100 Subject: [PATCH 04/37] Add thread structure --- src/kernel/mod.rs | 1 + src/kernel/process.rs | 4 ++ src/kernel/thread.rs | 97 ++++++++++++++++++++++++++++++++++++++++ src/simulator/machine.rs | 3 ++ src/utility/mod.rs | 3 +- src/utility/system.rs | 9 ++++ 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/kernel/process.rs create mode 100644 src/utility/system.rs diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 447d11e..bb7bfe3 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,2 +1,3 @@ +mod process; mod thread; mod scheduler; \ No newline at end of file diff --git a/src/kernel/process.rs b/src/kernel/process.rs new file mode 100644 index 0000000..fe973f4 --- /dev/null +++ b/src/kernel/process.rs @@ -0,0 +1,4 @@ + +pub struct Process { + +} \ No newline at end of file diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index e69de29..3b6cd83 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -0,0 +1,97 @@ +use super::process::Process; +use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS}, utility::system::ObjectType}; + + +struct SimulatorContext { + // todo +} + +struct ThreadContext { + pub int_registers: [i64; NUM_INT_REGS], + pub float_registers: [i64; NUM_FP_REGS], + pc: i64, +} + +pub struct Thread { + name: String, + process: Option, + simulation_context: SimulatorContext, + thread_context: ThreadContext, + stack_pointer: i32, + object_type: ObjectType +} + +impl Thread { + + pub fn new(name: String) -> Self { + Self { + name, + process: None, + simulation_context: SimulatorContext { }, + thread_context: ThreadContext { + int_registers: [0; NUM_INT_REGS], + float_registers: [0; NUM_FP_REGS], + pc: 0 + }, + stack_pointer: 0, + object_type: ObjectType::THREAD_TYPE + } + } + + /// Start a thread, attaching it to a process + pub fn start(&self, owner: &Process, func: i64, arg: i64) -> i32 { + todo!(); + } + + /// Wait for another thread to finish its execution + pub fn join(&self, id_thread: &Thread) { + todo!(); + } + + /// Relinquish the CPU if any other thread is runnable. + /// + /// Cannot use yield as a function name -> reserved name in rust + pub fn t_yield(&self) { + todo!(); + } + + /// 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 + pub fn check_overflow(&self) { + todo!(); + } + + pub fn init_simulator_context(&self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { + todo!(); + } + + pub fn save_processor_state(&self) { + todo!(); + } + + pub fn restore_processor_state(&self) { + todo!(); + } + + pub fn save_simulator_state(&self) { + todo!(); + } + + pub fn restore_simulator_state(&self) { + todo!(); + } + + pub fn get_name(&self) -> String { + self.name.clone() + } + +} \ No newline at end of file diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index f3f635b..a4f91af 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -4,6 +4,9 @@ use super::{decode::{Instruction, decode}}; use super::global::*; use std::fs::File; +pub const NUM_INT_REGS: usize = 32; +pub const NUM_FP_REGS: usize = 32; + /// doit disparaitre const MEM_SIZE : usize = 4096; diff --git a/src/utility/mod.rs b/src/utility/mod.rs index 651aed7..4b92101 100644 --- a/src/utility/mod.rs +++ b/src/utility/mod.rs @@ -1 +1,2 @@ -pub mod list; \ No newline at end of file +pub mod list; +pub mod system; \ No newline at end of file diff --git a/src/utility/system.rs b/src/utility/system.rs new file mode 100644 index 0000000..bbcb003 --- /dev/null +++ b/src/utility/system.rs @@ -0,0 +1,9 @@ + +pub enum ObjectType { + SEMAPHORE_TYPE, + LOCK_TYPE, + CONDITION_TYPE, + FILE_TYPE, + THREAD_TYPE, + INVALID_TYPE +} \ No newline at end of file From 013a2968cd816c9dfc3960094a54635085b58a16 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Tue, 28 Feb 2023 16:39:40 +0100 Subject: [PATCH 05/37] Add scheduler structure --- src/kernel/scheduler.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index e69de29..34f81f9 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -0,0 +1,32 @@ +use crate::utility::list::List; +use crate::kernel::thread::Thread; +use std::rc::Rc; + + +struct Scheduler<> { + ready_list: List> +} + +impl Scheduler { + + /// Constructor + /// + /// Initilize the list of ready thread + pub fn new() -> Self { + Self { + ready_list: List::new() + } + } + + /// Mark a thread as aready, but not necessarily running yet. + /// + /// Put it in the ready list, for later scheduling onto the CPU. + /// + /// ## Pamameter + /// + /// **thread**: Thread is the thread to be put on the read list + pub fn ready_to_run(&mut self, thread: Rc) { + self.ready_list.push_back(thread); + } + +} \ No newline at end of file From 6f98224da140edd1b6b93e8a59bcf3e1e70fdb23 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 10:11:19 +0100 Subject: [PATCH 06/37] scheduler done --- src/kernel/mod.rs | 2 +- src/kernel/scheduler.rs | 46 ++++++++++++++++++++++++++++++++++++++--- src/utility/system.rs | 5 +++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index bb7bfe3..a5dc06d 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,3 +1,3 @@ mod process; -mod thread; +pub mod thread; mod scheduler; \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 34f81f9..1c70460 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,10 +1,11 @@ use crate::utility::list::List; use crate::kernel::thread::Thread; +use crate::utility::system::{g_current_thread, g_thread_to_be_destroyed}; use std::rc::Rc; struct Scheduler<> { - ready_list: List> + ready_list: List } impl Scheduler { @@ -24,9 +25,48 @@ impl Scheduler { /// /// ## Pamameter /// - /// **thread**: Thread is the thread to be put on the read list - pub fn ready_to_run(&mut self, thread: Rc) { + /// **thread** is the thread to be put on the read list + pub fn ready_to_run(&mut self, thread: Thread) { self.ready_list.push_back(thread); } + /// Return the next thread to be scheduled onto the CPU. + /// If there are no ready threads, return Option::None + /// + /// Thread is removed from the ready list. + /// + /// **return** Thread thread to be scheduled + pub fn find_next_to_run(&mut self) -> Option { + self.ready_list.pop_back() + } + + /// Dispatch the CPU to next_thread. Save the state of the old thread + /// and load the state of the new thread. + /// + /// We assume the state of the previously running thread has already been changed from running to blocked or ready. + /// + /// Global variable g_current_thread become next_thread + /// + /// ## Parameter + /// + /// **next_thread** thread to dispatch to the CPU + pub fn switch_to(&self, next_thread: Thread) { + let old_thread = Box::clone(&g_current_thread).unwrap(); + + g_current_thread.check_overflow(); + + g_current_thread = Box::new(Option::Some(next_thread)); + + old_thread.save_processor_state(); + old_thread.save_simulator_state(); + + if(old_thread != g_current_thread) { + next_thread.restore_processor_state(); + next_thread.restore_simulator_state(); + } + + if(g_thread_to_be_destroyed.is_some()) { + drop(g_thread_to_be_destroyed.take()); + } + } } \ No newline at end of file diff --git a/src/utility/system.rs b/src/utility/system.rs index bbcb003..642dd11 100644 --- a/src/utility/system.rs +++ b/src/utility/system.rs @@ -1,3 +1,8 @@ +use crate::kernel::thread::Thread; + + +pub static g_current_thread: Box> = Box::new(Option::None); +pub static g_thread_to_be_destroyed: Box> = Box::new(Option::None); pub enum ObjectType { SEMAPHORE_TYPE, From 4c8062905c99b21a1535a39af0fa81fc19fdb4f8 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 11:10:15 +0100 Subject: [PATCH 07/37] Fix global var --- Cargo.lock | 9 +++++++++ Cargo.toml | 3 +-- src/kernel/process.rs | 1 + src/kernel/scheduler.rs | 38 ++++++++++++++++++++++++-------------- src/kernel/thread.rs | 3 +++ src/utility/system.rs | 14 +++++++++++--- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e08526..5b90585 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,12 @@ version = 3 [[package]] name = "burritos" version = "0.1.0" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index 466166c..fe2c644 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,5 @@ name = "burritos" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +lazy_static = "1.4.0" diff --git a/src/kernel/process.rs b/src/kernel/process.rs index fe973f4..5ae7efc 100644 --- a/src/kernel/process.rs +++ b/src/kernel/process.rs @@ -1,4 +1,5 @@ +#[derive(PartialEq)] pub struct Process { } \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 1c70460..207c5e6 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,7 +1,6 @@ use crate::utility::list::List; use crate::kernel::thread::Thread; use crate::utility::system::{g_current_thread, g_thread_to_be_destroyed}; -use std::rc::Rc; struct Scheduler<> { @@ -51,22 +50,33 @@ impl Scheduler { /// /// **next_thread** thread to dispatch to the CPU pub fn switch_to(&self, next_thread: Thread) { - let old_thread = Box::clone(&g_current_thread).unwrap(); + match g_current_thread.write() { + Ok(mut current_thread) => { + let old_thread = current_thread.as_mut().unwrap(); - g_current_thread.check_overflow(); + old_thread.save_processor_state(); + old_thread.save_simulator_state(); - g_current_thread = Box::new(Option::Some(next_thread)); + if old_thread != &next_thread { + next_thread.restore_processor_state(); + next_thread.restore_simulator_state(); + current_thread.replace(next_thread); + } - old_thread.save_processor_state(); - old_thread.save_simulator_state(); - - if(old_thread != g_current_thread) { - next_thread.restore_processor_state(); - next_thread.restore_simulator_state(); - } - - if(g_thread_to_be_destroyed.is_some()) { - drop(g_thread_to_be_destroyed.take()); + match g_thread_to_be_destroyed.write() { + Ok(mut thread_to_be_destroyed) => { + if thread_to_be_destroyed.is_some() { + drop(thread_to_be_destroyed.take()); + } + }, + Err(err) => { + panic!("RwLock is poisonned: {}", err); + } + } + }, + Err(err) => { + panic!("RwLock is poisonned: {}", err); + } } } } \ No newline at end of file diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 3b6cd83..9b0354d 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -2,16 +2,19 @@ use super::process::Process; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS}, utility::system::ObjectType}; +#[derive(PartialEq)] struct SimulatorContext { // todo } +#[derive(PartialEq)] struct ThreadContext { pub int_registers: [i64; NUM_INT_REGS], pub float_registers: [i64; NUM_FP_REGS], pc: i64, } +#[derive(PartialEq)] pub struct Thread { name: String, process: Option, diff --git a/src/utility/system.rs b/src/utility/system.rs index 642dd11..f5b8b50 100644 --- a/src/utility/system.rs +++ b/src/utility/system.rs @@ -1,9 +1,17 @@ +use std::sync::{Mutex, RwLock}; + +use lazy_static::lazy_static; + use crate::kernel::thread::Thread; +extern crate lazy_static; + +lazy_static! { + pub static ref g_current_thread: RwLock> = RwLock::new(Option::None); + pub static ref g_thread_to_be_destroyed: RwLock> = RwLock::new(Option::None); +} -pub static g_current_thread: Box> = Box::new(Option::None); -pub static g_thread_to_be_destroyed: Box> = Box::new(Option::None); - +#[derive(PartialEq)] pub enum ObjectType { SEMAPHORE_TYPE, LOCK_TYPE, From 792497b14c61d592b8e3608fd9a2caf58c07d94e Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 11:16:21 +0100 Subject: [PATCH 08/37] Change var name to fit with rust conventions --- src/kernel/scheduler.rs | 6 +++--- src/kernel/thread.rs | 2 +- src/utility/system.rs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 207c5e6..7cfe0ee 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,6 +1,6 @@ use crate::utility::list::List; use crate::kernel::thread::Thread; -use crate::utility::system::{g_current_thread, g_thread_to_be_destroyed}; +use crate::utility::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; struct Scheduler<> { @@ -50,7 +50,7 @@ impl Scheduler { /// /// **next_thread** thread to dispatch to the CPU pub fn switch_to(&self, next_thread: Thread) { - match g_current_thread.write() { + match G_CURRENT_THREAD.write() { Ok(mut current_thread) => { let old_thread = current_thread.as_mut().unwrap(); @@ -63,7 +63,7 @@ impl Scheduler { current_thread.replace(next_thread); } - match g_thread_to_be_destroyed.write() { + match G_THREAD_TO_BE_DESTROYED.write() { Ok(mut thread_to_be_destroyed) => { if thread_to_be_destroyed.is_some() { drop(thread_to_be_destroyed.take()); diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 9b0354d..922df0e 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -37,7 +37,7 @@ impl Thread { pc: 0 }, stack_pointer: 0, - object_type: ObjectType::THREAD_TYPE + object_type: ObjectType::ThreadType } } diff --git a/src/utility/system.rs b/src/utility/system.rs index f5b8b50..4c274ec 100644 --- a/src/utility/system.rs +++ b/src/utility/system.rs @@ -6,17 +6,17 @@ use crate::kernel::thread::Thread; extern crate lazy_static; lazy_static! { - pub static ref g_current_thread: RwLock> = RwLock::new(Option::None); - pub static ref g_thread_to_be_destroyed: RwLock> = RwLock::new(Option::None); + pub static ref G_CURRENT_THREAD: RwLock> = RwLock::new(Option::None); + pub static ref G_THREAD_TO_BE_DESTROYED: RwLock> = RwLock::new(Option::None); } #[derive(PartialEq)] pub enum ObjectType { - SEMAPHORE_TYPE, - LOCK_TYPE, - CONDITION_TYPE, - FILE_TYPE, - THREAD_TYPE, - INVALID_TYPE + SemaphoreType, + LockType, + ConditionType, + FileType, + ThreadType, + InvalidType } \ No newline at end of file From 77e6d74b3bc9e8927255c5594da42c64aff290b5 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 15:45:49 +0100 Subject: [PATCH 09/37] Adding some content to thread --- src/kernel/process.rs | 2 +- src/kernel/scheduler.rs | 2 +- src/kernel/thread.rs | 29 ++++++++++++++++++++++++++--- src/simulator/machine.rs | 2 ++ src/utility/system.rs | 5 ++++- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/kernel/process.rs b/src/kernel/process.rs index 5ae7efc..a56883e 100644 --- a/src/kernel/process.rs +++ b/src/kernel/process.rs @@ -1,5 +1,5 @@ #[derive(PartialEq)] pub struct Process { - + pub num_thread: usize, } \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 7cfe0ee..d2670b3 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -3,7 +3,7 @@ use crate::kernel::thread::Thread; use crate::utility::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; -struct Scheduler<> { +struct Scheduler { ready_list: List } diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 922df0e..a4301f8 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,6 +1,7 @@ use super::process::Process; -use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS}, utility::system::ObjectType}; +use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, utility::system::ObjectType}; +const SIMULATORSTACKSIZE: usize = 32 * 1024; #[derive(PartialEq)] struct SimulatorContext { @@ -42,10 +43,23 @@ impl Thread { } /// Start a thread, attaching it to a process - pub fn start(&self, owner: &Process, func: i64, arg: i64) -> i32 { + pub fn start(&mut self, owner: Process, func: i64, arg: i64) -> i32 { + self.process = Option::Some(owner); + let ptr = 0; // todo addrspace + self.init_thread_context(func, ptr, arg); + let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray + self.init_simulator_context(base_stack_addr); + self.process.as_mut().unwrap().num_thread += 1; + todo!(); } + fn init_thread_context(&mut self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { + self.thread_context.pc = initial_pc_reg; + self.thread_context.int_registers[10] = arg; + self.thread_context.int_registers[STACK_REG] = initial_sp; + } + /// Wait for another thread to finish its execution pub fn join(&self, id_thread: &Thread) { todo!(); @@ -73,7 +87,7 @@ impl Thread { todo!(); } - pub fn init_simulator_context(&self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { + pub fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { todo!(); } @@ -97,4 +111,13 @@ impl Thread { self.name.clone() } +} + +impl Drop for Thread { + + fn drop(&mut self) { + self.object_type = ObjectType::InvalidType; + todo!(); + } + } \ No newline at end of file diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index a4f91af..6523628 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -4,6 +4,8 @@ use super::{decode::{Instruction, decode}}; use super::global::*; use std::fs::File; +pub const STACK_REG: usize = 2; + pub const NUM_INT_REGS: usize = 32; pub const NUM_FP_REGS: usize = 32; diff --git a/src/utility/system.rs b/src/utility/system.rs index 4c274ec..701e0b7 100644 --- a/src/utility/system.rs +++ b/src/utility/system.rs @@ -1,13 +1,16 @@ -use std::sync::{Mutex, RwLock}; +use std::sync::{RwLock, Arc}; use lazy_static::lazy_static; use crate::kernel::thread::Thread; + +use super::list::List; extern crate lazy_static; lazy_static! { pub static ref G_CURRENT_THREAD: RwLock> = RwLock::new(Option::None); pub static ref G_THREAD_TO_BE_DESTROYED: RwLock> = RwLock::new(Option::None); + // pub static ref G_ALIVE: Arc>> = Arc::new(RwLock::new(List::new())); } From 68ee179e12366545e0e68c4fd4bfa6c0b2b5dc60 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 16:55:17 +0100 Subject: [PATCH 10/37] Implement Thread::start and join --- src/kernel/mgerror.rs | 31 ++++ src/kernel/mod.rs | 3 +- src/kernel/scheduler.rs | 14 +- src/kernel/thread.rs | 49 ++++-- src/utility/list.rs | 323 ++++++++++++++++++++++------------------ src/utility/system.rs | 7 +- 6 files changed, 264 insertions(+), 163 deletions(-) create mode 100644 src/kernel/mgerror.rs diff --git a/src/kernel/mgerror.rs b/src/kernel/mgerror.rs new file mode 100644 index 0000000..453a9bd --- /dev/null +++ b/src/kernel/mgerror.rs @@ -0,0 +1,31 @@ + +/// Error enum, use it with Result +pub enum ErrorCode { + INC_ERROR, + OPENFILE_ERROR, + EXEC_FILE_FORMAT_ERROR, + OUT_OF_MEMORY, + + OUT_OF_DISK, + ALREADY_IN_DIRECTORY, + INEXIST_FILE_ERROR, + INEXIST_DIRECTORY_ERROR, + NOSPACE_IN_DIRECTORY, + NOT_A_FILE, + NOT_A_DIRECTORY, + DIRECTORY_NOT_EMPTY, + INVALID_COUNTER, + + /* Invalid typeId fields: */ + INVALID_SEMAPHORE_ID, + INVALID_LOCK_ID, + INVALID_CONDITION_ID, + INVALID_FILE_ID, + INVALID_THREAD_ID, + + /* Other messages */ + WRONG_FILE_ENDIANESS, + NO_ACIA, + + NUMMSGERROR /* Must always be last */ +} \ No newline at end of file diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index a5dc06d..135f0a3 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,3 +1,4 @@ mod process; pub mod thread; -mod scheduler; \ No newline at end of file +pub mod scheduler; +pub mod mgerror; \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index d2670b3..0e71684 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,10 +1,12 @@ +use std::sync::Arc; + use crate::utility::list::List; use crate::kernel::thread::Thread; use crate::utility::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; -struct Scheduler { - ready_list: List +pub struct Scheduler { + ready_list: List> } impl Scheduler { @@ -25,8 +27,8 @@ impl Scheduler { /// ## Pamameter /// /// **thread** is the thread to be put on the read list - pub fn ready_to_run(&mut self, thread: Thread) { - self.ready_list.push_back(thread); + pub fn ready_to_run(&mut self, thread: Arc) { + self.ready_list.push(thread); } /// Return the next thread to be scheduled onto the CPU. @@ -35,8 +37,8 @@ impl Scheduler { /// Thread is removed from the ready list. /// /// **return** Thread thread to be scheduled - pub fn find_next_to_run(&mut self) -> Option { - self.ready_list.pop_back() + pub fn find_next_to_run(&mut self) -> Option> { + self.ready_list.pop() } /// Dispatch the CPU to next_thread. Save the state of the old thread diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index a4301f8..7f109df 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,5 +1,7 @@ -use super::process::Process; -use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, utility::system::ObjectType}; +use std::sync::Arc; + +use super::{process::Process, mgerror::ErrorCode}; +use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, utility::system::{ObjectType, G_ALIVE, G_SCHEDULER}, kernel::scheduler}; const SIMULATORSTACKSIZE: usize = 32 * 1024; @@ -43,15 +45,31 @@ impl Thread { } /// Start a thread, attaching it to a process - pub fn start(&mut self, owner: Process, func: i64, arg: i64) -> i32 { + pub fn start(mut self, owner: Process, func: i64, arg: i64) -> Result<(), ErrorCode> { self.process = Option::Some(owner); let ptr = 0; // todo addrspace self.init_thread_context(func, ptr, arg); let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray self.init_simulator_context(base_stack_addr); self.process.as_mut().unwrap().num_thread += 1; - - todo!(); + match G_ALIVE.write() { + Ok(mut alive) => { + let this = Arc::new(self); + alive.push(Arc::clone(&this)); + match G_SCHEDULER.write() { + Ok(mut scheduler) => { + scheduler.ready_to_run(Arc::clone(&this)); + }, + Err(err) => { + panic!("RwLock poisonned, {}", err); + } + } + }, + Err(err) => { + panic!("RwLock poisonned, {}", err); + } + } + Result::Ok(()) } fn init_thread_context(&mut self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { @@ -60,11 +78,24 @@ impl Thread { self.thread_context.int_registers[STACK_REG] = initial_sp; } - /// Wait for another thread to finish its execution - pub fn join(&self, id_thread: &Thread) { + fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { todo!(); } + /// Wait for another thread to finish its execution + pub fn join(&self, id_thread: Arc) { + match G_ALIVE.write() { + Ok(alive) => { + while alive.contains(&Arc::clone(&id_thread)) { + self.t_yield(); + } + }, + Err(err) => { + panic!("RwLock poisonned, {}", err) + } + } + } + /// Relinquish the CPU if any other thread is runnable. /// /// Cannot use yield as a function name -> reserved name in rust @@ -87,10 +118,6 @@ impl Thread { todo!(); } - pub fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { - todo!(); - } - pub fn save_processor_state(&self) { todo!(); } diff --git a/src/utility/list.rs b/src/utility/list.rs index 46f5557..a90ec2b 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -1,178 +1,217 @@ -use std::{cell::RefCell, rc::Rc}; -/// Definition of an element of the list -/// -/// Contain one stored item and the previous/next element of the list -struct ListNode { - item: T, - next: Link, - prev: Link, -} - -impl ListNode { - fn new(item: T) -> Self { - Self { - item, - next: None, - prev: None, - } - } -} - -type Link = Option>>>; - -/// Defintion of the generic linked list -#[derive(Default)] -pub struct DoublyLinkedList { +pub struct List { head: Link, - tail: Link, - size: usize, } -impl DoublyLinkedList { +type Link = Option>>; +struct Node { + elem: T, + next: Link, +} + +impl List { pub fn new() -> Self { - Self { - head: None, - tail: None, - size: 0, - } + List { head: None } } - pub fn is_empty(&self) -> bool { - self.len() == 0 + /// Push an item at the end of the list + pub fn push(&mut self, elem: T) { + let new_node = Box::new(Node { + elem: elem, + next: self.head.take(), + }); + + self.head = Some(new_node); } - pub fn len(&self) -> usize { - self.size - } - - /// Add the item at the end of the list - pub fn push_back(&mut self, item: T) { - let node = Rc::new(RefCell::new(ListNode::new(item))); - if let Some(prev_tail) = self.tail.take() { - prev_tail.borrow_mut().next = Some(Rc::clone(&node)); - node.borrow_mut().prev = Some(prev_tail); - self.tail = Some(node); - self.size += 1; - } else { - self.head = Some(Rc::clone(&node)); - self.tail = Some(node); - self.size = 1; - } - } - - /// Add the item at the start of the list - pub fn push_front(&mut self, item: T) { - let node = Rc::new(RefCell::new(ListNode::new(item))); - if let Some(prev_head) = self.head.take() { - prev_head.borrow_mut().prev = Some(Rc::clone(&node)); - node.borrow_mut().next = Some(prev_head); - self.head = Some(node); - self.size += 1; - } else { - self.head = Some(Rc::clone(&node)); - self.tail = Some(node); - self.size = 1; - } - } - - /// Retrieve and remove the item at the end of the list - pub fn pop_back(&mut self) -> Option { - self.tail.take().map(|prev_tail| { - self.size -= 1; - match prev_tail.borrow_mut().prev.take() { - Some(node) => { - node.borrow_mut().next = None; - self.tail = Some(node); - } - None => { - self.head.take(); - } - } - Rc::try_unwrap(prev_tail).ok().unwrap().into_inner().item + /// Retrieve and remove the item at the end of the list. + /// + /// Return None if list is empty + pub fn pop(&mut self) -> Option { + self.head.take().map(|node| { + self.head = node.next; + node.elem }) } - /// Retrieve and remove the item at the start of the list - pub fn pop_front(&mut self) -> Option { - self.head.take().map(|prev_head| { - self.size -= 1; - match prev_head.borrow_mut().next.take() { - Some(node) => { - node.borrow_mut().prev = None; - self.head = Some(node); - } - None => { - self.tail.take(); - } - } - Rc::try_unwrap(prev_head).ok().unwrap().into_inner().item + /// Retrieve without removing the item at the end of the list + /// + /// Return None if list is empty + pub fn peek(&self) -> Option<&T> { + self.head.as_ref().map(|node| { + &node.elem }) } - + + /// Retrieve without removing the item at the end of the list as mutable + /// + /// Return None if lsit is empty + pub fn peek_mut(&mut self) -> Option<&mut T> { + self.head.as_mut().map(|node| { + &mut node.elem + }) + } + + /// Search for an element in the list + /// + /// Return **bool** true if the list contains the element, false otherwise + /// + /// Worst case complexity of this function is O(n) + pub fn contains(&self, elem: &T) -> bool { + let mut iter = self.iter(); + let element = iter.next(); + while element.is_some() { + if element.unwrap() == elem { + return true; + } + } + false + } + + pub fn into_iter(self) -> IntoIter { + IntoIter(self) + } + + pub fn iter(&self) -> Iter<'_, T> { + Iter { next: self.head.as_deref() } + } + + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { next: self.head.as_deref_mut() } + } } -impl Drop for DoublyLinkedList { - /// list destructor, safely desallocate smart pointer Rc +impl Drop for List { fn drop(&mut self) { - while let Some(node) = self.head.take() { - let _ = node.borrow_mut().prev.take(); - self.head = node.borrow_mut().next.take(); + let mut cur_link = self.head.take(); + while let Some(mut boxed_node) = cur_link { + cur_link = boxed_node.next.take(); } - self.tail.take(); } } -impl IntoIterator for DoublyLinkedList { - type Item = as Iterator>::Item; +pub struct IntoIter(List); - type IntoIter = ListIterator; - - fn into_iter(self) -> Self::IntoIter { - Self::IntoIter::new(self) - } -} - -pub struct ListIterator { - list: DoublyLinkedList, -} - -impl ListIterator { - fn new(list: DoublyLinkedList) -> Self { - Self { list } - } -} - -impl Iterator for ListIterator { +impl Iterator for IntoIter { type Item = T; + fn next(&mut self) -> Option { + // access fields of a tuple struct numerically + self.0.pop() + } +} + +pub struct Iter<'a, T> { + next: Option<&'a Node>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + fn next(&mut self) -> Option { + self.next.map(|node| { + self.next = node.next.as_deref(); + &node.elem + }) + } +} + +pub struct IterMut<'a, T> { + next: Option<&'a mut Node>, +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; fn next(&mut self) -> Option { - self.list.pop_front() + self.next.take().map(|node| { + self.next = node.next.as_deref_mut(); + &mut node.elem + }) } } -impl DoubleEndedIterator for ListIterator { - fn next_back(&mut self) -> Option { - self.list.pop_back() - } -} - -pub type List = DoublyLinkedList; -pub type ListInt = List; - #[cfg(test)] mod test { - - use super::DoublyLinkedList; + use super::List; #[test] - fn test_list_push() { - let mut list = DoublyLinkedList::new(); - list.push_back(5); - list.push_front(45); - assert_eq!(list.pop_front().unwrap(), 45); - assert_eq!(list.pop_front().unwrap(), 5); + fn basics() { + let mut list = List::new(); + + // Check empty list behaves right + assert_eq!(list.pop(), None); + + // Populate list + list.push(1); + list.push(2); + list.push(3); + + // Check normal removal + assert_eq!(list.pop(), Some(3)); + assert_eq!(list.pop(), Some(2)); + + // Push some more just to make sure nothing's corrupted + list.push(4); + list.push(5); + + // Check normal removal + assert_eq!(list.pop(), Some(5)); + assert_eq!(list.pop(), Some(4)); + + // Check exhaustion + assert_eq!(list.pop(), Some(1)); + assert_eq!(list.pop(), None); } + #[test] + fn peek() { + let mut list = List::new(); + assert_eq!(list.peek(), None); + assert_eq!(list.peek_mut(), None); + list.push(1); list.push(2); list.push(3); + + assert_eq!(list.peek(), Some(&3)); + assert_eq!(list.peek_mut(), Some(&mut 3)); + + list.peek_mut().map(|value| { + *value = 42 + }); + + assert_eq!(list.peek(), Some(&42)); + assert_eq!(list.pop(), Some(42)); + } + + #[test] + fn into_iter() { + let mut list = List::new(); + list.push(1); list.push(2); list.push(3); + + let mut iter = list.into_iter(); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), None); + } + + #[test] + fn iter() { + let mut list = List::new(); + list.push(1); list.push(2); list.push(3); + + let mut iter = list.iter(); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&1)); + } + + #[test] + fn iter_mut() { + let mut list = List::new(); + list.push(1); list.push(2); list.push(3); + + let mut iter = list.iter_mut(); + assert_eq!(iter.next(), Some(&mut 3)); + assert_eq!(iter.next(), Some(&mut 2)); + assert_eq!(iter.next(), Some(&mut 1)); + } } \ No newline at end of file diff --git a/src/utility/system.rs b/src/utility/system.rs index 701e0b7..08dc9bf 100644 --- a/src/utility/system.rs +++ b/src/utility/system.rs @@ -1,8 +1,8 @@ -use std::sync::{RwLock, Arc}; +use std::{sync::{RwLock, Arc}}; use lazy_static::lazy_static; -use crate::kernel::thread::Thread; +use crate::kernel::{thread::Thread, scheduler::Scheduler}; use super::list::List; extern crate lazy_static; @@ -10,7 +10,8 @@ extern crate lazy_static; lazy_static! { pub static ref G_CURRENT_THREAD: RwLock> = RwLock::new(Option::None); pub static ref G_THREAD_TO_BE_DESTROYED: RwLock> = RwLock::new(Option::None); - // pub static ref G_ALIVE: Arc>> = Arc::new(RwLock::new(List::new())); + pub static ref G_ALIVE: RwLock>> = RwLock::new(List::new()); + pub static ref G_SCHEDULER: RwLock = RwLock::new(Scheduler::new()); } From b39e56b9c4dc032100f8ea5cea0e31a2a972660d Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 17:01:02 +0100 Subject: [PATCH 11/37] Move system to the right location --- src/kernel/mod.rs | 3 ++- src/kernel/scheduler.rs | 2 +- src/{utility => kernel}/system.rs | 3 +-- src/kernel/thread.rs | 4 ++-- src/utility/mod.rs | 3 +-- 5 files changed, 7 insertions(+), 8 deletions(-) rename src/{utility => kernel}/system.rs (88%) diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 135f0a3..bbd9f52 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,4 +1,5 @@ mod process; pub mod thread; pub mod scheduler; -pub mod mgerror; \ No newline at end of file +pub mod mgerror; +pub mod system; \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 0e71684..3500f65 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -2,8 +2,8 @@ use std::sync::Arc; use crate::utility::list::List; use crate::kernel::thread::Thread; -use crate::utility::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; +use super::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; pub struct Scheduler { ready_list: List> diff --git a/src/utility/system.rs b/src/kernel/system.rs similarity index 88% rename from src/utility/system.rs rename to src/kernel/system.rs index 08dc9bf..5f04b2c 100644 --- a/src/utility/system.rs +++ b/src/kernel/system.rs @@ -2,9 +2,8 @@ use std::{sync::{RwLock, Arc}}; use lazy_static::lazy_static; -use crate::kernel::{thread::Thread, scheduler::Scheduler}; +use crate::{kernel::{thread::Thread, scheduler::Scheduler}, utility::list::List}; -use super::list::List; extern crate lazy_static; lazy_static! { diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 7f109df..12d9db4 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use super::{process::Process, mgerror::ErrorCode}; -use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, utility::system::{ObjectType, G_ALIVE, G_SCHEDULER}, kernel::scheduler}; +use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, G_ALIVE, G_SCHEDULER}}; +use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; const SIMULATORSTACKSIZE: usize = 32 * 1024; diff --git a/src/utility/mod.rs b/src/utility/mod.rs index 4b92101..651aed7 100644 --- a/src/utility/mod.rs +++ b/src/utility/mod.rs @@ -1,2 +1 @@ -pub mod list; -pub mod system; \ No newline at end of file +pub mod list; \ No newline at end of file From 4dae2990084bfd68e9f8ce31df3802bec5b56dae Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 1 Mar 2023 17:18:45 +0100 Subject: [PATCH 12/37] Implement interrupt --- src/simulator/interrupt.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/simulator/mod.rs | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/simulator/interrupt.rs diff --git a/src/simulator/interrupt.rs b/src/simulator/interrupt.rs new file mode 100644 index 0000000..8f71885 --- /dev/null +++ b/src/simulator/interrupt.rs @@ -0,0 +1,38 @@ + + +struct Interrupt { + level: InterruptStatus +} + +impl Interrupt { + + pub fn new() -> Self { + Self { + level: InterruptStatus::InterruptOff + } + } + + pub fn set_status(&mut self, newStatus: InterruptStatus) -> InterruptStatus { + let old = self.level; + self.level = newStatus; + if newStatus == InterruptStatus::InterruptOn && old == InterruptStatus::InterruptOff { + self.one_tick(1); + } + old + } + + fn one_tick(&self, nb_cycle: i32) { + todo!(); + } + + pub fn get_status(&self) -> InterruptStatus { + self.level + } + +} + +#[derive(PartialEq, Clone, Copy)] +pub enum InterruptStatus { + InterruptOff, + InterruptOn +} \ No newline at end of file diff --git a/src/simulator/mod.rs b/src/simulator/mod.rs index 54d271e..769616f 100644 --- a/src/simulator/mod.rs +++ b/src/simulator/mod.rs @@ -2,7 +2,7 @@ pub mod machine; pub mod decode; pub mod print; pub mod mem_cmp; - +pub mod interrupt; pub mod global { From 6ca0b564c59c6e9260ed1f605706f54fa306acfd Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Mon, 6 Mar 2023 16:31:35 +0100 Subject: [PATCH 13/37] Add ucontext_t --- Cargo.lock | 7 ++++ Cargo.toml | 1 + src/kernel/mod.rs | 3 +- src/kernel/thread.rs | 31 ++++++++++++------ src/kernel/ucontext.rs | 72 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 src/kernel/ucontext.rs diff --git a/Cargo.lock b/Cargo.lock index 5b90585..9898199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ name = "burritos" version = "0.1.0" dependencies = [ "lazy_static", + "libc", ] [[package]] @@ -14,3 +15,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" diff --git a/Cargo.toml b/Cargo.toml index fe2c644..d9e3b00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] lazy_static = "1.4.0" +libc = { version = "0.2.139", features = ["extra_traits"] } diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index bbd9f52..e061a2a 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -2,4 +2,5 @@ mod process; pub mod thread; pub mod scheduler; pub mod mgerror; -pub mod system; \ No newline at end of file +pub mod system; +mod ucontext; \ No newline at end of file diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 12d9db4..000877a 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,14 +1,10 @@ -use std::sync::Arc; +use std::{sync::Arc}; -use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, G_ALIVE, G_SCHEDULER}}; +use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, G_ALIVE, G_SCHEDULER}, ucontext::UContextT}; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; const SIMULATORSTACKSIZE: usize = 32 * 1024; - -#[derive(PartialEq)] -struct SimulatorContext { - // todo -} +const STACK_FENCEPOST: u32 = 0xdeadbeef; #[derive(PartialEq)] struct ThreadContext { @@ -21,7 +17,7 @@ struct ThreadContext { pub struct Thread { name: String, process: Option, - simulation_context: SimulatorContext, + // simulation_context: UContextT, thread_context: ThreadContext, stack_pointer: i32, object_type: ObjectType @@ -33,7 +29,7 @@ impl Thread { Self { name, process: None, - simulation_context: SimulatorContext { }, + // simulation_context: UContextT::new(), thread_context: ThreadContext { int_registers: [0; NUM_INT_REGS], float_registers: [0; NUM_FP_REGS], @@ -79,7 +75,18 @@ impl Thread { } fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { - todo!(); + // let res = self.simulation_context.get_context(); + // if res != 0 { + // panic!("getcontext returns non-zero value {}", res); + // } + // self.simulation_context.buf.uc_stack.ss_sp = base_stack_addr; + // self.simulation_context.buf.uc_stack.ss_size = base_stack_addr.len(); + // self.simulation_context.buf.uc_stack.ss_flags = 0; + // self.simulation_context.buf.uc_link = UContextT::new().buf; + // self.simulation_context.make_context(start_thread_execution, 0); + + // self.simulation_context.stackBottom = base_stack_addr.to_vec(); + // self.simulation_context.stackBottom[0] = STACK_FENCEPOST; } /// Wait for another thread to finish its execution @@ -147,4 +154,8 @@ impl Drop for Thread { todo!(); } +} + +fn start_thread_execution() { + } \ No newline at end of file diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs new file mode 100644 index 0000000..89b847d --- /dev/null +++ b/src/kernel/ucontext.rs @@ -0,0 +1,72 @@ + +use std::mem::MaybeUninit; + +use libc::{ucontext_t, getcontext, setcontext, makecontext}; + +/// Safe wrapper for ucontext_t struct of linux-gnu libc +/// +/// setcontext and getcontext are unsafe function, this wrap unsafe libc functions +/// +/// This struct doesn't work on windows, because this struct is unavailable +/// +/// todo ucontext_t is not thread-safe (doesn't implements Send and Sync trait), and cannot be use in Threads as rust require var in Mutex (see system.rs) to have everything inside to implements thread-safe traits +#[derive(PartialEq)] +pub struct UContextT { + #[cfg(not(target_os = "windows"))] // struct non disponible sur la libc sur windows + pub buf: ucontext_t, + pub stackBottom: Vec +} + +#[cfg(not(target_os = "windows"))] +impl UContextT { + + pub fn new() -> Self { + let mut context = MaybeUninit::::uninit(); + unsafe { getcontext(context.as_mut_ptr()) }; + Self { + buf: unsafe { context.assume_init() }, + stackBottom: Vec::default(), + } + } + + /// Get user context and store it in variable pointed to by UCP. + /// + /// Use `man getcontext` for more informations + pub fn get_context(&mut self) -> i32 { + unsafe { + getcontext(&mut self.buf) + } + } + + /// Set user context from information of variable pointed to by UCP. + /// + /// Use `man setcontext` for more informations + pub fn set_context(&mut self) -> i32 { + unsafe { + setcontext(&self.buf) + } + } + + pub fn make_context(&mut self, func: extern "C" fn(), args: i32) { + unsafe { + makecontext(&mut self.buf, func, args) + } + } + +} + +#[cfg(target_os = "windows")] +impl UContextT { + + pub fn new() -> Self { + Self {} + } + + pub fn get_context(&mut self) { + // no op + } + + pub fn set_context(&mut self) { + // no op + } +} \ No newline at end of file From 8c6ef4e1311c1ed5fc5e52d4301b219ad1608e2d Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 8 Mar 2023 13:21:08 +0100 Subject: [PATCH 14/37] Implemente finish (not finished yet), fix ucontext for windows --- src/kernel/system.rs | 3 ++- src/kernel/thread.rs | 31 +++++++++++++++++++++++++++++-- src/kernel/ucontext.rs | 16 ++++++++-------- src/simulator/interrupt.rs | 2 +- src/simulator/machine.rs | 8 +++++--- 5 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/kernel/system.rs b/src/kernel/system.rs index 5f04b2c..1fd2de9 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -2,11 +2,12 @@ use std::{sync::{RwLock, Arc}}; use lazy_static::lazy_static; -use crate::{kernel::{thread::Thread, scheduler::Scheduler}, utility::list::List}; +use crate::{kernel::{thread::Thread, scheduler::Scheduler}, utility::list::List, simulator::machine::Machine}; extern crate lazy_static; lazy_static! { + pub static ref G_MACHINE: RwLock = RwLock::new(Machine::_init_machine()); pub static ref G_CURRENT_THREAD: RwLock> = RwLock::new(Option::None); pub static ref G_THREAD_TO_BE_DESTROYED: RwLock> = RwLock::new(Option::None); pub static ref G_ALIVE: RwLock>> = RwLock::new(List::new()); diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 000877a..0a163d0 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,7 +1,7 @@ use std::{sync::Arc}; use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, G_ALIVE, G_SCHEDULER}, ucontext::UContextT}; -use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; +use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, kernel::system::{G_MACHINE, G_THREAD_TO_BE_DESTROYED}}; const SIMULATORSTACKSIZE: usize = 32 * 1024; const STACK_FENCEPOST: u32 = 0xdeadbeef; @@ -116,7 +116,34 @@ impl Thread { } /// Finish the execution of the thread and prepare its deallocation - pub fn finish(&self) { + pub fn finish(mut self) { + match G_MACHINE.write() { + Ok(mut machine) => { + let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff); + match G_ALIVE.write() { + Ok(alive) => { + // todo alive.remove(T) à implémenter dans List + }, + Err(err) => { + panic!("RwLock is poisoned: {}", err); + } + } + match G_THREAD_TO_BE_DESTROYED.write() { + Ok(mut thread_to_be_destroyed) => { + thread_to_be_destroyed.replace(self); + }, + Err(err) => { + panic!("RwLock is poisoned: {}", err); + } + } + // self.sleep(); + machine.interrupt.set_status(old_status); + }, + Err(err) => { + panic!("RwLock is poisoned: {}", err); + } + } + todo!(); } diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs index 89b847d..6217a1d 100644 --- a/src/kernel/ucontext.rs +++ b/src/kernel/ucontext.rs @@ -1,8 +1,6 @@ use std::mem::MaybeUninit; -use libc::{ucontext_t, getcontext, setcontext, makecontext}; - /// Safe wrapper for ucontext_t struct of linux-gnu libc /// /// setcontext and getcontext are unsafe function, this wrap unsafe libc functions @@ -13,7 +11,7 @@ use libc::{ucontext_t, getcontext, setcontext, makecontext}; #[derive(PartialEq)] pub struct UContextT { #[cfg(not(target_os = "windows"))] // struct non disponible sur la libc sur windows - pub buf: ucontext_t, + pub buf: lib::ucontext_t, pub stackBottom: Vec } @@ -22,7 +20,7 @@ impl UContextT { pub fn new() -> Self { let mut context = MaybeUninit::::uninit(); - unsafe { getcontext(context.as_mut_ptr()) }; + unsafe { lib::getcontext(context.as_mut_ptr()) }; Self { buf: unsafe { context.assume_init() }, stackBottom: Vec::default(), @@ -34,7 +32,7 @@ impl UContextT { /// Use `man getcontext` for more informations pub fn get_context(&mut self) -> i32 { unsafe { - getcontext(&mut self.buf) + lib::getcontext(&mut self.buf) } } @@ -43,13 +41,13 @@ impl UContextT { /// Use `man setcontext` for more informations pub fn set_context(&mut self) -> i32 { unsafe { - setcontext(&self.buf) + lib::setcontext(&self.buf) } } pub fn make_context(&mut self, func: extern "C" fn(), args: i32) { unsafe { - makecontext(&mut self.buf, func, args) + lib::makecontext(&mut self.buf, func, args) } } @@ -59,7 +57,9 @@ impl UContextT { impl UContextT { pub fn new() -> Self { - Self {} + Self { + stackBottom: Vec::default() + } } pub fn get_context(&mut self) { diff --git a/src/simulator/interrupt.rs b/src/simulator/interrupt.rs index 8f71885..8f08312 100644 --- a/src/simulator/interrupt.rs +++ b/src/simulator/interrupt.rs @@ -1,6 +1,6 @@ -struct Interrupt { +pub struct Interrupt { level: InterruptStatus } diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 6523628..59ab1b8 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -1,6 +1,6 @@ use std::{ops::{Add, Sub}, io::Write}; -use super::{decode::{Instruction, decode}}; +use super::{decode::{Instruction, decode}, interrupt::Interrupt}; use super::global::*; use std::fs::File; @@ -71,7 +71,8 @@ pub struct Machine { pub int_reg : Register, pub fp_reg : Register, pub main_memory : [u8 ; MEM_SIZE], - pub shiftmask : [u64 ; 64] + pub shiftmask : [u64 ; 64], + 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 } @@ -95,7 +96,8 @@ impl Machine { int_reg : Register::::init(), fp_reg : Register::::init(), main_memory : [0 ; MEM_SIZE], - shiftmask + shiftmask, + interrupt: Interrupt::new() } } From 8889d43f9d7f0a81846a74a6ae6497cfb8b8c465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 14:09:07 +0100 Subject: [PATCH 15/37] Fixed ucontext & libc --- src/kernel/ucontext.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs index 6217a1d..16c29f1 100644 --- a/src/kernel/ucontext.rs +++ b/src/kernel/ucontext.rs @@ -11,7 +11,7 @@ use std::mem::MaybeUninit; #[derive(PartialEq)] pub struct UContextT { #[cfg(not(target_os = "windows"))] // struct non disponible sur la libc sur windows - pub buf: lib::ucontext_t, + pub buf: libc::ucontext_t, pub stackBottom: Vec } @@ -19,8 +19,8 @@ pub struct UContextT { impl UContextT { pub fn new() -> Self { - let mut context = MaybeUninit::::uninit(); - unsafe { lib::getcontext(context.as_mut_ptr()) }; + let mut context = MaybeUninit::::uninit(); + unsafe { libc::getcontext(context.as_mut_ptr()) }; Self { buf: unsafe { context.assume_init() }, stackBottom: Vec::default(), @@ -32,7 +32,7 @@ impl UContextT { /// Use `man getcontext` for more informations pub fn get_context(&mut self) -> i32 { unsafe { - lib::getcontext(&mut self.buf) + libc::getcontext(&mut self.buf) } } @@ -41,13 +41,13 @@ impl UContextT { /// Use `man setcontext` for more informations pub fn set_context(&mut self) -> i32 { unsafe { - lib::setcontext(&self.buf) + libc::setcontext(&self.buf) } } pub fn make_context(&mut self, func: extern "C" fn(), args: i32) { unsafe { - lib::makecontext(&mut self.buf, func, args) + libc::makecontext(&mut self.buf, func, args) } } From 4c79f86b89b599c9e104413df0d5e923714a3a69 Mon Sep 17 00:00:00 2001 From: Moysan Gabriel Date: Wed, 8 Mar 2023 14:38:02 +0100 Subject: [PATCH 16/37] dataTypes definition --- src/kernel/elf.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 src/kernel/elf.rs diff --git a/src/kernel/elf.rs b/src/kernel/elf.rs new file mode 100644 index 0000000..84dce69 --- /dev/null +++ b/src/kernel/elf.rs @@ -0,0 +1,143 @@ +//Declaration des alias + +/* + Def ELF : + + The header file defines the format of ELF executable binary + files. Amongst these files are normal executable files, relocatable + object files, core files and shared libraries. + + An executable file using the ELF file format consists of an ELF header, + followed by a program header table or a section header table, or both. + The ELF header is always at offset zero of the file. The program + header table and the section header table's offset in the file are + defined in the ELF header. The two tables describe the rest of the + particularities of the file + */ + + +/* Type for a 16-bit quantity. */ + +type Elf32_Half = u16; + +type Elf64_Half = u16; + +/* Types for signed and unsigned 32-bit quantities. */ + +type Elf32_Word = u32; + +type Elf32_Sword = i32; + +type Elf64_Word = u32; + +type Elf64_Sword = i32; + +/* Types for signed and unsigned 64-bit quantities. */ + +type Elf32_Xword = u64; + +type Elf32_Sxword = i64; + +type Elf64_Xword = u64; + +type Elf64_Sxword = i64; + +/* Type of addresses. */ + +type Elf32_Addr = u32; + +type Elf64_Addr = u64; + +/* Type of file offsets. */ + +type Elf32_Off = u32; + +type Elf64_Off = u64; + +//role de ce truc ? +const EI_NIDENT : u8 = 16; + +//ELF file header 32 bits +struct Elf32Ehdr{ + e_ident : [u8;EI_NIDENT],//16 octects décrivant comment le fichier doit etre parsé + //e_ident must starts with magice number : 0x 7f 45 4c 46 + e_type : Elf32_Half,//type of the file + e_machine : Elf32_Half,//type architecture machine + e_version : Elf32_Word,//always 1 + e_entry : Elf32_Addr,//entry point @ for executable + e_phoff : Elf32_Off,//Offset of the program header table + e_shoff : Elf32_Off,//Offset of the section header table + e_flags : Elf32_Word,//des flags ? + e_ehsize : Elf32_Half,//size of this (the header), redundant + e_phentsize : Elf32_Half,//size per program header + e_phnum : Elf32_Half,//number of program header + e_shentsize : Elf32_Half,//size per section header + e_shnum : Elf32_Half,//number of section header + e_shstrndx : Elf32_Half//section header string table index +} + + +//ELF file header 64 bits +//les champs ont le meme rôle que dans le header 32 bits +struct Elf64Ehdr{ + e_ident : [u8;EI_NIDENT], + e_type : Elf64_Half, + e_machine : Elf64_Half, + e_version : Elf64_Word, + e_entry : Elf64_Addr, + e_phoff : Elf64_Off, + e_shoff : Elf64_Off, + e_flags : Elf64_Word, + e_ehsize : Elf64_Half, + e_phentsize : Elf64_Half, + e_phnum : Elf64_Half, + e_shentsize : Elf64_Half, + e_shnum : Elf64_Half, + e_shstrndx : Elf64_Half +} + + + +/* e_ident offsets */ +const EI_MAG0 : u32 = 0; +const EI_MAG1 : u32 = 1; +const EI_MAG2 : u32 = 2; +const EI_MAG3 : u32 = 3; +const EI_CLASS : u32 = 4; +const EI_DATA : u32 = 5; +const EI_VERSION : u32 = 6; +const EI_PAD : u32 = 7; + +/* e_ident[EI_CLASS] */ +const ELFCLASSNONE : u32 = 0; +const ELFCLASS32 : u32 = 1; +const ELFCLASS64 : u32 = 2; + +/* e_ident[EI_DATA] */ +const ELFDATANONE : u32 = 0; +const ELFDATA2LSB : u32 = 1; +const ELFDATA2MSB : u32 = 2; + +/* e_type */ +const ET_NONE : u32 = 0; /* No file type */ +const ET_REL : u32 = 1; /* Relocatable file */ +const ET_EXEC : u32 = 2; /* Executable file */ +const ET_DYN : u32 = 3; /* Shared object file */ +const ET_CORE : u32 = 4; /* Core file */ +const ET_LOPROC : u32 = 0xff00; /* Processor-specific */ +const ET_HIPROC : u32 = 0xffff; /* Processor-specific */ + +/* e_machine */ +const EM_NONE : u32 = 0; /* No machine */ +const EM_M32 : u32 = 1; /* AT&T WE 32100 */ +const EM_SPARC : u32 = 2; /* SPARC */ +const EM_386 : u32 = 3; /* Intel 80386 */ +const EM_68K : u32 = 4; /* Motorola 68000 */ +const EM_88K : u32 = 5; /* Motorola 88000 */ +const EM_860 : u32 = 7; /* Intel 80860 */ +const EM_MIPS : u32 = 8; /* MIPS R3000 */ +const EM_RISC : u32 = 243; /* RISCV */ + +/* e_version */ + const EV_NONE : u32 = 0; /* invalid version */ + const EV_CURRENT : u32 = 1; /* current version */ From 0309614396de7d10547326ba756513f56514f4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 15:16:10 +0100 Subject: [PATCH 17/37] New system structure --- Cargo.lock | 7 ---- Cargo.toml | 1 - src/kernel/system.rs | 94 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 81 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9898199..e3bcbe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,16 +6,9 @@ version = 3 name = "burritos" version = "0.1.0" dependencies = [ - "lazy_static", "libc", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.139" diff --git a/Cargo.toml b/Cargo.toml index d9e3b00..1d66884 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -lazy_static = "1.4.0" libc = { version = "0.2.139", features = ["extra_traits"] } diff --git a/src/kernel/system.rs b/src/kernel/system.rs index 1fd2de9..b0f54c8 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -1,19 +1,87 @@ -use std::{sync::{RwLock, Arc}}; +use std::rc::Rc; +use crate::{ + kernel::{ + thread::Thread, + scheduler::Scheduler + }, + utility::list::List, + simulator::machine::Machine +}; -use lazy_static::lazy_static; - -use crate::{kernel::{thread::Thread, scheduler::Scheduler}, utility::list::List, simulator::machine::Machine}; - -extern crate lazy_static; - -lazy_static! { - pub static ref G_MACHINE: RwLock = RwLock::new(Machine::_init_machine()); - pub static ref G_CURRENT_THREAD: RwLock> = RwLock::new(Option::None); - pub static ref G_THREAD_TO_BE_DESTROYED: RwLock> = RwLock::new(Option::None); - pub static ref G_ALIVE: RwLock>> = RwLock::new(List::new()); - pub static ref G_SCHEDULER: RwLock = RwLock::new(Scheduler::new()); +/// # System +/// +/// This structure represents the state of the threads running on the operating system. +/// It contains references to the following: +/// +/// - The simulated machine +/// - The current running thread +/// - The list of active threads +/// - The thread to be destroyed next +/// - The scheduler which acts upon these threads +pub struct System { + g_machine: Machine, + g_current_thread: Option, + g_thread_to_be_destroyed: Option, + g_alive: List>, + g_scheduler: Scheduler } +impl System { + + // GETTERS + + /// Returns the Machine + /// + /// Useful to access RAM, devices, ... + pub fn get_g_machine(&mut self) -> &mut Machine { + &mut self.g_machine + } + + /// Currently running thread + pub fn get_g_current_thread(&mut self) -> &mut Option { + &mut self.g_current_thread + } + + /// Thread to be destroyed by [...] + /// + /// TODO: Finish the comment with the relevant value + pub fn get_g_thread_to_be_destroyed(&mut self) -> &mut Option { + &mut self.g_thread_to_be_destroyed + } + + /// List of alive threads + pub fn get_g_alive(&mut self) -> &mut List> { + &mut self.g_alive + } + + /// Current scheduler + pub fn g_scheduler(&mut self) -> &mut Scheduler { + &mut self.g_scheduler + } + + // Setters + + /// Assign a machine to the system + pub fn set_g_machine(&mut self, machine: Machine) { + self.g_machine = machine + } + + /// Set currently running thread + pub fn set_g_current_thread(&mut self, thread: Option) { + self.g_current_thread = thread + } + + /// Set thread to be destroyed next + pub fn set_g_thread_to_be_destroyed(&mut self, thread: Option) { + self.g_thread_to_be_destroyed = thread + } + + /// Set Scheduler which will manage the threads + pub fn set_g_scheduler(&mut self, scheduler: Scheduler) { + self.g_scheduler = scheduler + } + +} #[derive(PartialEq)] pub enum ObjectType { From de502973c77a81833b286391a70cea4f1da469d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 15:34:13 +0100 Subject: [PATCH 18/37] Added System initializer method --- src/kernel/system.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/kernel/system.rs b/src/kernel/system.rs index b0f54c8..e650097 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -28,6 +28,17 @@ pub struct System { impl System { + /// System constructor + pub fn new(machine: Machine, scheduler: Scheduler) -> Self { + Self { + g_machine: machine, + g_current_thread: None, + g_thread_to_be_destroyed: None, + g_alive: List::new(), + g_scheduler: scheduler + } + } + // GETTERS /// Returns the Machine From a11ca01368282787ecab5f1b7814f9488f9ca2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 15:38:19 +0100 Subject: [PATCH 19/37] Main now initializes System object --- src/main.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 986cf3b..9e6d750 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,15 +2,14 @@ mod simulator; mod kernel; pub mod utility; +use kernel::{ + scheduler::Scheduler, + system::System +}; use simulator::machine::Machine; fn main() { - let mut m = Machine::_init_machine(); - m.main_memory[4] = 43; - m.main_memory[5] = 150; - let a : u8 = 128; - let b : i8 = a as i8; - let c : u8 = b as u8; - println!("aaa {c}"); - println!("read_memory : {}", Machine::read_memory(&mut m, 2, 4)); + let machine = Machine::_init_machine(); + let scheduler = Scheduler::new(); + let system = System::new(machine, scheduler); } From cf65688566a91af5fb0df795432c8eb8ce591caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Wed, 8 Mar 2023 15:45:35 +0100 Subject: [PATCH 20/37] Sarting synch.rs implementation --- src/kernel/mod.rs | 3 ++- src/kernel/synch.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/kernel/synch.rs diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index e061a2a..f1abafa 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -3,4 +3,5 @@ pub mod thread; pub mod scheduler; pub mod mgerror; pub mod system; -mod ucontext; \ No newline at end of file +mod ucontext; +mod synch; \ No newline at end of file diff --git a/src/kernel/synch.rs b/src/kernel/synch.rs new file mode 100644 index 0000000..8a7fe98 --- /dev/null +++ b/src/kernel/synch.rs @@ -0,0 +1,43 @@ +use crate::utility::list::List; +use crate::kernel::thread::Thread; +use std::rc::Rc; +use crate::simulator::interrupt::InterruptStatus::InterruptOff; +use crate::simulator::machine::Machine; + +pub struct Semaphore{ + + counter:i32, + waiting_queue:List> + +} + +impl Semaphore{ + + pub fn p(&mut self, current_thread:Rc, machine: &mut Machine){ + let old_status = machine.interrupt.set_status(InterruptOff); + self.counter-=1; + if self.counter < 0 { + self.waiting_queue.push(Rc::clone(¤t_thread)); + current_thread.sleep(); + } + machine.interrupt.set_status(old_status); + } + + pub fn v(&mut self, current_thread:Rc, machine: &mut Machine){ + let old_status = machine.interrupt.set_status(InterruptOff); + self.counter-=1; + if self.waiting_queue.peek == None { + self.waiting_queue.push(Rc::clone(¤t_thread)); + current_thread.sleep(); + } + machine.interrupt.set_status(old_status); + } +} + +pub struct Lock{ + +} + +pub struct Condition{ + +} \ No newline at end of file From a29f410a6637c7eedb942b2a4cd1016a8fc35042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rativel?= Date: Wed, 8 Mar 2023 15:46:27 +0100 Subject: [PATCH 21/37] small fix --- src/kernel/synch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/synch.rs b/src/kernel/synch.rs index 8a7fe98..a2038e6 100644 --- a/src/kernel/synch.rs +++ b/src/kernel/synch.rs @@ -26,7 +26,7 @@ impl Semaphore{ pub fn v(&mut self, current_thread:Rc, machine: &mut Machine){ let old_status = machine.interrupt.set_status(InterruptOff); self.counter-=1; - if self.waiting_queue.peek == None { + if self.waiting_queue.peek() == None { self.waiting_queue.push(Rc::clone(¤t_thread)); current_thread.sleep(); } From 62b60186e97d29fe201e619239bdaa66820c2f79 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 8 Mar 2023 15:46:53 +0100 Subject: [PATCH 22/37] Add list.remove(T) --- src/utility/list.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/utility/list.rs b/src/utility/list.rs index a90ec2b..e750b17 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -69,6 +69,33 @@ impl List { false } + /// Remove the item from the list + /// + /// Return true if the item has been found, otherwise return false + /// + /// Worst-case complexity is O(n) + pub fn remove(&mut self, item: T)-> bool { + let mut found = false; + let mut tmp_list: List = List::new(); + while !self.is_empty() { + let current = self.pop().unwrap(); + if current != item { + tmp_list.push(current); + } else { + found = true; + break; + } + } + while !tmp_list.is_empty() { + self.push(tmp_list.pop().unwrap()); + } + found + } + + pub fn is_empty(&self) -> bool { + self.head.is_none() + } + pub fn into_iter(self) -> IntoIter { IntoIter(self) } From 7520fd4458556bdba75a2ad0a60833a0e9f34dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 15:48:03 +0100 Subject: [PATCH 23/37] Added partialeq trait to List struct --- src/utility/list.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utility/list.rs b/src/utility/list.rs index a90ec2b..88962c4 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -1,4 +1,5 @@ +#[derive(PartialEq)] pub struct List { head: Link, } From 5e265ab27b309cffbc8e5ab46ec688bb95b44726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 15:48:33 +0100 Subject: [PATCH 24/37] Added partialeq trait where relevant --- src/kernel/scheduler.rs | 1 + src/kernel/system.rs | 1 + src/kernel/thread.rs | 44 +++++++++----------------------------- src/simulator/interrupt.rs | 2 +- src/simulator/machine.rs | 3 ++- 5 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 3500f65..9753cdf 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -5,6 +5,7 @@ use crate::kernel::thread::Thread; use super::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; +#[derive(PartialEq)] pub struct Scheduler { ready_list: List> } diff --git a/src/kernel/system.rs b/src/kernel/system.rs index e650097..8ef7ecb 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -18,6 +18,7 @@ use crate::{ /// - The list of active threads /// - The thread to be destroyed next /// - The scheduler which acts upon these threads +#[derive(PartialEq)] pub struct System { g_machine: Machine, g_current_thread: Option, diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 0a163d0..ce4aec8 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,7 +1,7 @@ -use std::{sync::Arc}; +use std::{sync::Arc, rc::Rc}; -use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, G_ALIVE, G_SCHEDULER}, ucontext::UContextT}; -use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}, kernel::system::{G_MACHINE, G_THREAD_TO_BE_DESTROYED}}; +use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, System}, ucontext::UContextT}; +use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; const SIMULATORSTACKSIZE: usize = 32 * 1024; const STACK_FENCEPOST: u32 = 0xdeadbeef; @@ -20,12 +20,14 @@ pub struct Thread { // simulation_context: UContextT, thread_context: ThreadContext, stack_pointer: i32, - object_type: ObjectType + object_type: ObjectType, + system: Rc } impl Thread { - pub fn new(name: String) -> Self { + /// Thread constructor + pub fn new(name: String, system: Rc) -> Self { Self { name, process: None, @@ -36,7 +38,8 @@ impl Thread { pc: 0 }, stack_pointer: 0, - object_type: ObjectType::ThreadType + object_type: ObjectType::ThreadType, + system } } @@ -116,34 +119,7 @@ impl Thread { } /// Finish the execution of the thread and prepare its deallocation - pub fn finish(mut self) { - match G_MACHINE.write() { - Ok(mut machine) => { - let old_status = machine.interrupt.set_status(crate::simulator::interrupt::InterruptStatus::InterruptOff); - match G_ALIVE.write() { - Ok(alive) => { - // todo alive.remove(T) à implémenter dans List - }, - Err(err) => { - panic!("RwLock is poisoned: {}", err); - } - } - match G_THREAD_TO_BE_DESTROYED.write() { - Ok(mut thread_to_be_destroyed) => { - thread_to_be_destroyed.replace(self); - }, - Err(err) => { - panic!("RwLock is poisoned: {}", err); - } - } - // self.sleep(); - machine.interrupt.set_status(old_status); - }, - Err(err) => { - panic!("RwLock is poisoned: {}", err); - } - } - + pub fn finish(&self) { todo!(); } diff --git a/src/simulator/interrupt.rs b/src/simulator/interrupt.rs index 8f08312..9cede5b 100644 --- a/src/simulator/interrupt.rs +++ b/src/simulator/interrupt.rs @@ -1,5 +1,5 @@ - +#[derive(PartialEq)] pub struct Interrupt { level: InterruptStatus } diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 59ab1b8..73dc8b5 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -19,7 +19,7 @@ impl RegisterNum for i64 {} impl RegisterNum for f32 {} - +#[derive(PartialEq)] pub struct Register { register: [U; 32] } @@ -65,6 +65,7 @@ impl Register { } +#[derive(PartialEq)] pub struct Machine { pub pc : u64, pub sp: usize, From f4edac230eb91c233479c3aafb84ee75d86f341d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Wed, 8 Mar 2023 15:49:31 +0100 Subject: [PATCH 25/37] Added partialeq trait to Node --- src/utility/list.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utility/list.rs b/src/utility/list.rs index 024606c..f6efb50 100644 --- a/src/utility/list.rs +++ b/src/utility/list.rs @@ -6,6 +6,7 @@ pub struct List { type Link = Option>>; +#[derive(PartialEq)] struct Node { elem: T, next: Link, From f15d782916931d99e25d915a02ee0c1093a52cf1 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 8 Mar 2023 15:54:10 +0100 Subject: [PATCH 26/37] Fix thread --- src/kernel/scheduler.rs | 10 ++++------ src/kernel/thread.rs | 33 ++++++--------------------------- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 9753cdf..670f0fa 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,13 +1,11 @@ -use std::sync::Arc; +use std::{sync::Arc, rc::Rc}; use crate::utility::list::List; use crate::kernel::thread::Thread; -use super::system::{G_CURRENT_THREAD, G_THREAD_TO_BE_DESTROYED}; - #[derive(PartialEq)] pub struct Scheduler { - ready_list: List> + ready_list: List> } impl Scheduler { @@ -28,7 +26,7 @@ impl Scheduler { /// ## Pamameter /// /// **thread** is the thread to be put on the read list - pub fn ready_to_run(&mut self, thread: Arc) { + pub fn ready_to_run(&mut self, thread: Rc) { self.ready_list.push(thread); } @@ -38,7 +36,7 @@ impl Scheduler { /// Thread is removed from the ready list. /// /// **return** Thread thread to be scheduled - pub fn find_next_to_run(&mut self) -> Option> { + pub fn find_next_to_run(&mut self) -> Option> { self.ready_list.pop() } diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index ce4aec8..3ffbba6 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -51,23 +51,9 @@ impl Thread { let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray self.init_simulator_context(base_stack_addr); self.process.as_mut().unwrap().num_thread += 1; - match G_ALIVE.write() { - Ok(mut alive) => { - let this = Arc::new(self); - alive.push(Arc::clone(&this)); - match G_SCHEDULER.write() { - Ok(mut scheduler) => { - scheduler.ready_to_run(Arc::clone(&this)); - }, - Err(err) => { - panic!("RwLock poisonned, {}", err); - } - } - }, - Err(err) => { - panic!("RwLock poisonned, {}", err); - } - } + let this = Rc::new(self); + self.system.get_g_alive().push(Rc::clone(&this)); + self.system.g_scheduler().ready_to_run(Rc::clone(&this)); Result::Ok(()) } @@ -93,16 +79,9 @@ impl Thread { } /// Wait for another thread to finish its execution - pub fn join(&self, id_thread: Arc) { - match G_ALIVE.write() { - Ok(alive) => { - while alive.contains(&Arc::clone(&id_thread)) { - self.t_yield(); - } - }, - Err(err) => { - panic!("RwLock poisonned, {}", err) - } + pub fn join(&self, id_thread: Rc) { + while self.system.get_g_alive().contains(&Rc::clone(&id_thread)) { + self.t_yield(); } } From 0f5eb84c7b03d5f52b21daf7aa6d064551bd182a Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 8 Mar 2023 16:05:05 +0100 Subject: [PATCH 27/37] Remove old static vars in scheduler, doesn't work --- src/kernel/scheduler.rs | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 670f0fa..0398799 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,8 +1,10 @@ -use std::{sync::Arc, rc::Rc}; +use std::rc::Rc; use crate::utility::list::List; use crate::kernel::thread::Thread; +use super::system::System; + #[derive(PartialEq)] pub struct Scheduler { ready_list: List> @@ -50,34 +52,16 @@ impl Scheduler { /// ## Parameter /// /// **next_thread** thread to dispatch to the CPU - pub fn switch_to(&self, next_thread: Thread) { - match G_CURRENT_THREAD.write() { - Ok(mut current_thread) => { - let old_thread = current_thread.as_mut().unwrap(); + pub fn switch_to(&self, system: Rc, next_thread: Thread) { + /* if let Some(old_thread) = system.get_g_current_thread() { + old_thread.save_processor_state(); + old_thread.save_simulator_state(); - old_thread.save_processor_state(); - old_thread.save_simulator_state(); - - if old_thread != &next_thread { - next_thread.restore_processor_state(); - next_thread.restore_simulator_state(); - current_thread.replace(next_thread); - } - - match G_THREAD_TO_BE_DESTROYED.write() { - Ok(mut thread_to_be_destroyed) => { - if thread_to_be_destroyed.is_some() { - drop(thread_to_be_destroyed.take()); - } - }, - Err(err) => { - panic!("RwLock is poisonned: {}", err); - } - } - }, - Err(err) => { - panic!("RwLock is poisonned: {}", err); + if old_thread != &next_thread { + next_thread.restore_processor_state(); + next_thread.restore_simulator_state(); + system.set_g_current_thread(Option::Some(next_thread)); } - } + } */ } } \ No newline at end of file From 82731cabcf5205c21c425320f8082c44cc775a9f Mon Sep 17 00:00:00 2001 From: Samy Solhi Date: Wed, 8 Mar 2023 16:39:00 +0100 Subject: [PATCH 28/37] synch.rs implemented --- src/kernel/synch.rs | 93 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 8 deletions(-) diff --git a/src/kernel/synch.rs b/src/kernel/synch.rs index a2038e6..98a1f76 100644 --- a/src/kernel/synch.rs +++ b/src/kernel/synch.rs @@ -1,8 +1,11 @@ use crate::utility::list::List; use crate::kernel::thread::Thread; -use std::rc::Rc; use crate::simulator::interrupt::InterruptStatus::InterruptOff; use crate::simulator::machine::Machine; +use std::rc::Rc; + + +use super::scheduler::Scheduler; pub struct Semaphore{ @@ -13,9 +16,9 @@ pub struct Semaphore{ impl Semaphore{ - pub fn p(&mut self, current_thread:Rc, machine: &mut Machine){ + pub fn p(&mut self, current_thread: Rc, machine: &mut Machine){ let old_status = machine.interrupt.set_status(InterruptOff); - self.counter-=1; + self.counter -= 1; if self.counter < 0 { self.waiting_queue.push(Rc::clone(¤t_thread)); current_thread.sleep(); @@ -23,12 +26,11 @@ impl Semaphore{ machine.interrupt.set_status(old_status); } - pub fn v(&mut self, current_thread:Rc, machine: &mut Machine){ + pub fn v(&mut self, machine: &mut Machine, scheduler: &mut Scheduler){ let old_status = machine.interrupt.set_status(InterruptOff); - self.counter-=1; - if self.waiting_queue.peek() == None { - self.waiting_queue.push(Rc::clone(¤t_thread)); - current_thread.sleep(); + self.counter -= 1; + if self.waiting_queue.peek() != None { + scheduler.ready_to_run(self.waiting_queue.pop().unwrap()); } machine.interrupt.set_status(old_status); } @@ -36,8 +38,83 @@ impl Semaphore{ pub struct Lock{ + owner: Rc, + waiting_queue:List>, + free: bool + +} + +impl Lock { + pub fn acquire(&mut self, machine: &mut Machine, current_thread: Rc) { + let old_status = machine.interrupt.set_status(InterruptOff); + + if self.free { + self.free = false; + self.owner = current_thread; + } else { + self.waiting_queue.push(Rc::clone(¤t_thread)); + current_thread.sleep(); + } + + machine.interrupt.set_status(old_status); + } + + pub fn release(&mut self, machine: &mut Machine, scheduler: &mut Scheduler, current_thread: Rc) { + let old_status = machine.interrupt.set_status(InterruptOff); + + if self.is_held_by_current_thread(current_thread) { + if self.waiting_queue.peek() != None { + self.owner = self.waiting_queue.pop().unwrap(); + scheduler.ready_to_run(Rc::clone(&self.owner)); + } else { + self.free = true; + } + } + + machine.interrupt.set_status(old_status); + } + + pub fn is_held_by_current_thread(&mut self, current_thread: Rc) -> bool { + Rc::ptr_eq(&self.owner, ¤t_thread) + } } pub struct Condition{ + waiting_queue:List> + +} + +impl Condition { + + pub fn wait(&mut self, machine: &mut Machine, current_thread: Rc) { + let old_status = machine.interrupt.set_status(InterruptOff); + + self.waiting_queue.push(Rc::clone(¤t_thread)); + current_thread.sleep(); + + machine.interrupt.set_status(old_status); + } + + pub fn signal(&mut self, machine: &mut Machine, scheduler: &mut Scheduler) { + let old_status = machine.interrupt.set_status(InterruptOff); + + if self.waiting_queue.peek() != None { + scheduler.ready_to_run(self.waiting_queue.pop().unwrap()); + } + + machine.interrupt.set_status(old_status); + + } + + pub fn broadcast(&mut self, machine: &mut Machine, scheduler: &mut Scheduler) { + let old_status = machine.interrupt.set_status(InterruptOff); + + while self.waiting_queue.peek() != None { + scheduler.ready_to_run(self.waiting_queue.pop().unwrap()); + } + machine.interrupt.set_status(old_status); + + } + } \ No newline at end of file From 4ca85b54d41bb4d1b3d44cc77af45433f007d153 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 8 Mar 2023 21:10:51 +0100 Subject: [PATCH 29/37] Added thread manager --- src/kernel/mod.rs | 3 +- src/kernel/system.rs | 71 +++++---------------------- src/kernel/thread.rs | 44 +++-------------- src/kernel/thread_manager.rs | 95 ++++++++++++++++++++++++++++++++++++ src/kernel/ucontext.rs | 2 +- src/main.rs | 8 +-- 6 files changed, 119 insertions(+), 104 deletions(-) create mode 100644 src/kernel/thread_manager.rs diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index f1abafa..1988e43 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -4,4 +4,5 @@ pub mod scheduler; pub mod mgerror; pub mod system; mod ucontext; -mod synch; \ No newline at end of file +mod synch; +mod thread_manager; \ No newline at end of file diff --git a/src/kernel/system.rs b/src/kernel/system.rs index 8ef7ecb..863bdc2 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -1,12 +1,6 @@ -use std::rc::Rc; -use crate::{ - kernel::{ - thread::Thread, - scheduler::Scheduler - }, - utility::list::List, - simulator::machine::Machine -}; +use crate::simulator::machine::Machine; + +use super::thread_manager::ThreadManager; /// # System /// @@ -19,26 +13,24 @@ use crate::{ /// - The thread to be destroyed next /// - The scheduler which acts upon these threads #[derive(PartialEq)] -pub struct System { +pub struct System<'a> { g_machine: Machine, - g_current_thread: Option, - g_thread_to_be_destroyed: Option, - g_alive: List>, - g_scheduler: Scheduler + thread_manager: ThreadManager<'a> } -impl System { +impl<'a> System<'a> { /// System constructor - pub fn new(machine: Machine, scheduler: Scheduler) -> Self { + pub fn new(machine: Machine) -> System<'a> { Self { g_machine: machine, - g_current_thread: None, - g_thread_to_be_destroyed: None, - g_alive: List::new(), - g_scheduler: scheduler + thread_manager: ThreadManager::new() } - } + } + + pub fn freeze(&'a mut self) { + self.thread_manager.system.set(Option::Some(self)); + } // GETTERS @@ -49,28 +41,6 @@ impl System { &mut self.g_machine } - /// Currently running thread - pub fn get_g_current_thread(&mut self) -> &mut Option { - &mut self.g_current_thread - } - - /// Thread to be destroyed by [...] - /// - /// TODO: Finish the comment with the relevant value - pub fn get_g_thread_to_be_destroyed(&mut self) -> &mut Option { - &mut self.g_thread_to_be_destroyed - } - - /// List of alive threads - pub fn get_g_alive(&mut self) -> &mut List> { - &mut self.g_alive - } - - /// Current scheduler - pub fn g_scheduler(&mut self) -> &mut Scheduler { - &mut self.g_scheduler - } - // Setters /// Assign a machine to the system @@ -78,21 +48,6 @@ impl System { self.g_machine = machine } - /// Set currently running thread - pub fn set_g_current_thread(&mut self, thread: Option) { - self.g_current_thread = thread - } - - /// Set thread to be destroyed next - pub fn set_g_thread_to_be_destroyed(&mut self, thread: Option) { - self.g_thread_to_be_destroyed = thread - } - - /// Set Scheduler which will manage the threads - pub fn set_g_scheduler(&mut self, scheduler: Scheduler) { - self.g_scheduler = scheduler - } - } #[derive(PartialEq)] diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 3ffbba6..68bc7c9 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -1,6 +1,4 @@ -use std::{sync::Arc, rc::Rc}; - -use super::{process::Process, mgerror::ErrorCode, system::{ObjectType, System}, ucontext::UContextT}; +use super::{process::Process, system::ObjectType}; use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; const SIMULATORSTACKSIZE: usize = 32 * 1024; @@ -16,18 +14,17 @@ struct ThreadContext { #[derive(PartialEq)] pub struct Thread { name: String, - process: Option, + pub process: Option, // simulation_context: UContextT, thread_context: ThreadContext, stack_pointer: i32, - object_type: ObjectType, - system: Rc + object_type: ObjectType } impl Thread { /// Thread constructor - pub fn new(name: String, system: Rc) -> Self { + pub fn new(name: String) -> Self { Self { name, process: None, @@ -39,31 +36,16 @@ impl Thread { }, stack_pointer: 0, object_type: ObjectType::ThreadType, - system } } - /// Start a thread, attaching it to a process - pub fn start(mut self, owner: Process, func: i64, arg: i64) -> Result<(), ErrorCode> { - self.process = Option::Some(owner); - let ptr = 0; // todo addrspace - self.init_thread_context(func, ptr, arg); - let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray - self.init_simulator_context(base_stack_addr); - self.process.as_mut().unwrap().num_thread += 1; - let this = Rc::new(self); - self.system.get_g_alive().push(Rc::clone(&this)); - self.system.g_scheduler().ready_to_run(Rc::clone(&this)); - Result::Ok(()) - } - - fn init_thread_context(&mut self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { + pub fn init_thread_context(&mut self, initial_pc_reg: i64, initial_sp: i64, arg: i64) { self.thread_context.pc = initial_pc_reg; self.thread_context.int_registers[10] = arg; self.thread_context.int_registers[STACK_REG] = initial_sp; } - fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { + pub fn init_simulator_context(&self, base_stack_addr: [i8; SIMULATORSTACKSIZE]) { // let res = self.simulation_context.get_context(); // if res != 0 { // panic!("getcontext returns non-zero value {}", res); @@ -78,20 +60,6 @@ impl Thread { // self.simulation_context.stackBottom[0] = STACK_FENCEPOST; } - /// Wait for another thread to finish its execution - pub fn join(&self, id_thread: Rc) { - while self.system.get_g_alive().contains(&Rc::clone(&id_thread)) { - self.t_yield(); - } - } - - /// Relinquish the CPU if any other thread is runnable. - /// - /// Cannot use yield as a function name -> reserved name in rust - pub fn t_yield(&self) { - todo!(); - } - /// Put the thread to sleep and relinquish the processor pub fn sleep(&self) { todo!(); diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs new file mode 100644 index 0000000..28e5eaa --- /dev/null +++ b/src/kernel/thread_manager.rs @@ -0,0 +1,95 @@ +use std::{rc::Rc, cell::Cell}; + +use crate::utility::list::List; + +use super::{scheduler::Scheduler, thread::Thread, system::System, mgerror::ErrorCode, process::Process}; + +const SIMULATORSTACKSIZE: usize = 32 * 1024; + +#[derive(PartialEq)] +pub struct ThreadManager<'a> { + pub g_current_thread: Option, + pub g_thread_to_be_destroyed: Option, + pub g_alive: List>, + pub g_scheduler: Scheduler, + pub system: Cell>> +} + +impl<'a> ThreadManager<'a> { + + pub fn new() -> Self { + Self { + g_current_thread: Option::None, + g_thread_to_be_destroyed: Option::None, + g_alive: List::new(), + g_scheduler: Scheduler::new(), + system: Cell::new(None) + } + } + + /// Start a thread, attaching it to a process + pub fn start_thread(&mut self, thread: &mut Thread, owner: Process, func_pc: i64, argument: i64) -> Result<(), ErrorCode> { + thread.process = Option::Some(owner); + let ptr = 0; // todo addrspace + thread.init_thread_context(func_pc, ptr, argument); + let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray + thread.init_simulator_context(base_stack_addr); + thread.process.as_mut().unwrap().num_thread += 1; + let thread_m = Rc::new(thread); + // self.get_g_alive().push(Rc::clone(thread)); + // self.g_scheduler().ready_to_run(Rc::clone(&thread)); + Result::Ok(()) + } + + /// Wait for another thread to finish its execution + pub fn thread_join(&mut self, id_thread: Rc) { + while self.get_g_alive().contains(&Rc::clone(&id_thread)) { + self.thread_yield(); + } + } + + /// 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) { + todo!(); + } + + /// Currently running thread + pub fn get_g_current_thread(&mut self) -> &mut Option { + &mut self.g_current_thread + } + + /// Thread to be destroyed by [...] + /// + /// TODO: Finish the comment with the relevant value + pub fn get_g_thread_to_be_destroyed(&mut self) -> &mut Option { + &mut self.g_thread_to_be_destroyed + } + + /// List of alive threads + pub fn get_g_alive(&mut self) -> &mut List> { + &mut self.g_alive + } + + /// Current scheduler + pub fn g_scheduler(&mut self) -> &mut Scheduler { + &mut self.g_scheduler + } + + /// Set currently running thread + pub fn set_g_current_thread(&mut self, thread: Option) { + self.g_current_thread = thread + } + + /// Set thread to be destroyed next + pub fn set_g_thread_to_be_destroyed(&mut self, thread: Option) { + self.g_thread_to_be_destroyed = thread + } + + /// Set Scheduler which will manage the threads + pub fn set_g_scheduler(&mut self, scheduler: Scheduler) { + self.g_scheduler = scheduler + } + +} \ No newline at end of file diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs index 16c29f1..567d144 100644 --- a/src/kernel/ucontext.rs +++ b/src/kernel/ucontext.rs @@ -1,5 +1,5 @@ -use std::mem::MaybeUninit; +// use std::mem::MaybeUninit; /// Safe wrapper for ucontext_t struct of linux-gnu libc /// diff --git a/src/main.rs b/src/main.rs index 9e6d750..1bde63e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,14 +2,10 @@ mod simulator; mod kernel; pub mod utility; -use kernel::{ - scheduler::Scheduler, - system::System -}; +use kernel::system::System; use simulator::machine::Machine; fn main() { let machine = Machine::_init_machine(); - let scheduler = Scheduler::new(); - let system = System::new(machine, scheduler); + let _system = System::new(machine); } From fe4bbb2fc2f1058e787adde37717128cb3af873a Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Wed, 8 Mar 2023 21:43:03 +0100 Subject: [PATCH 30/37] Fix start_thread --- src/kernel/thread_manager.rs | 6 +++--- src/simulator/interrupt.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 28e5eaa..466d14e 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -28,7 +28,7 @@ impl<'a> ThreadManager<'a> { } /// Start a thread, attaching it to a process - pub fn start_thread(&mut self, thread: &mut Thread, owner: Process, func_pc: i64, argument: i64) -> Result<(), ErrorCode> { + pub fn start_thread(&mut self, mut thread: Thread, owner: Process, func_pc: i64, argument: i64) -> Result<(), ErrorCode> { thread.process = Option::Some(owner); let ptr = 0; // todo addrspace thread.init_thread_context(func_pc, ptr, argument); @@ -36,8 +36,8 @@ impl<'a> ThreadManager<'a> { thread.init_simulator_context(base_stack_addr); thread.process.as_mut().unwrap().num_thread += 1; let thread_m = Rc::new(thread); - // self.get_g_alive().push(Rc::clone(thread)); - // self.g_scheduler().ready_to_run(Rc::clone(&thread)); + self.get_g_alive().push(Rc::clone(&thread_m)); + self.g_scheduler().ready_to_run(Rc::clone(&thread_m)); Result::Ok(()) } diff --git a/src/simulator/interrupt.rs b/src/simulator/interrupt.rs index 9cede5b..e63e0af 100644 --- a/src/simulator/interrupt.rs +++ b/src/simulator/interrupt.rs @@ -12,10 +12,10 @@ impl Interrupt { } } - pub fn set_status(&mut self, newStatus: InterruptStatus) -> InterruptStatus { + pub fn set_status(&mut self, new_status: InterruptStatus) -> InterruptStatus { let old = self.level; - self.level = newStatus; - if newStatus == InterruptStatus::InterruptOn && old == InterruptStatus::InterruptOff { + self.level = new_status; + if new_status == InterruptStatus::InterruptOn && old == InterruptStatus::InterruptOff { self.one_tick(1); } old From d392c69535f4b787f2a75b8f8834e01998799b79 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Thu, 9 Mar 2023 12:08:33 +0100 Subject: [PATCH 31/37] Add thread save and restore processor context --- src/kernel/system.rs | 12 +++++---- src/kernel/thread.rs | 38 +++++++++++------------------ src/kernel/thread_manager.rs | 47 ++++++++++++++++++++++++++++++++---- src/kernel/ucontext.rs | 7 +++--- src/simulator/machine.rs | 16 ++++++++++++ 5 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/kernel/system.rs b/src/kernel/system.rs index 863bdc2..319be5c 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -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, 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 { + &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) { self.g_machine = machine } diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 68bc7c9..326bb9c 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -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, // 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, @@ -59,28 +58,19 @@ impl Thread { // self.simulation_context.stackBottom = base_stack_addr.to_vec(); // 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) { diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 466d14e..39a7f81 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -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) { 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) { todo!(); } + /// Put the thread to sleep and relinquish the processor + pub fn thread_sleep(&mut self, thread: Rc) { + todo!(); + } + + /// Finish the execution of the thread and prepare its deallocation + pub fn thread_finish(&self, thread: Rc) { + todo!(); + } + + pub fn thread_save_processor_state(&mut self, thread: Rc>) { + 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>) { + 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 { &mut self.g_current_thread diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs index 567d144..1ffee6f 100644 --- a/src/kernel/ucontext.rs +++ b/src/kernel/ucontext.rs @@ -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 + pub stack_bottom: Vec } #[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(), } } diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 73dc8b5..228fbf6 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -616,6 +616,22 @@ impl Machine { machine.pc += 8; } + + 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)] From 0f339dd936ab1aed8f36cda51acfd2af520a775d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Thu, 9 Mar 2023 12:44:03 +0100 Subject: [PATCH 32/37] Changed constructor to allow any string slice as parameter + started writing unit tests --- src/kernel/thread.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 326bb9c..1b8b41d 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -23,9 +23,9 @@ pub struct Thread { impl Thread { /// Thread constructor - pub fn new(name: String) -> Self { + pub fn new(name: &str) -> Self { Self { - name, + name: String::from(name), process: None, // simulation_context: UContextT::new(), thread_context: ThreadContext { @@ -98,4 +98,15 @@ impl Drop for Thread { fn start_thread_execution() { +} + +#[cfg(test)] +mod test { + + use super::Thread; + + fn get_new_thread() -> Thread { + Thread::new("test_thread") + } + } \ No newline at end of file From 8bf7a452f3a773217993e38374717a4e46220dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Thu, 9 Mar 2023 13:07:50 +0100 Subject: [PATCH 33/37] Added macro to get new thread easily and started writing test --- src/kernel/thread.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 1b8b41d..b07058b 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -103,10 +103,26 @@ fn start_thread_execution() { #[cfg(test)] mod test { - use super::Thread; + use super::{Thread, ThreadContext}; - fn get_new_thread() -> Thread { - Thread::new("test_thread") + macro_rules! get_new_thread { + () => { Thread::new("test_thread") }; + ($a:literal) => { + Thread::new(&$a.to_string()) + }; + } + + #[test] + fn test_macro() { + let t = get_new_thread!("hello"); + assert_eq!(t.get_name(), "hello"); + let t = get_new_thread!(1); + assert_eq!(t.get_name(), "1"); + } + + #[test] + fn check_init() { + let t = get_new_thread!(); } } \ No newline at end of file From bfef7254d846121e14ae0ba8737941e11ed905c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Thu, 9 Mar 2023 13:24:04 +0100 Subject: [PATCH 34/37] Added debug attributes to structs pertaining to thread in order to allow for applying assertions upon Thread --- src/kernel/process.rs | 2 +- src/kernel/system.rs | 2 +- src/kernel/thread.rs | 25 ++++++++++++++++++++++--- test_programs/userlib/libnachos.o | Bin 0 -> 15488 bytes test_programs/userlib/sys.o | Bin 0 -> 3624 bytes 5 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 test_programs/userlib/libnachos.o create mode 100644 test_programs/userlib/sys.o diff --git a/src/kernel/process.rs b/src/kernel/process.rs index a56883e..f28b0fa 100644 --- a/src/kernel/process.rs +++ b/src/kernel/process.rs @@ -1,5 +1,5 @@ -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub struct Process { pub num_thread: usize, } \ No newline at end of file diff --git a/src/kernel/system.rs b/src/kernel/system.rs index 319be5c..bad8652 100644 --- a/src/kernel/system.rs +++ b/src/kernel/system.rs @@ -52,7 +52,7 @@ impl<'a> System<'a> { } -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum ObjectType { SemaphoreType, LockType, diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index b07058b..d4aedbc 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -3,14 +3,14 @@ use crate::{simulator::machine::{NUM_INT_REGS, NUM_FP_REGS, STACK_REG}}; const STACK_FENCEPOST: u32 = 0xdeadbeef; -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub struct ThreadContext { pub int_registers: [i64; NUM_INT_REGS], pub float_registers: [f32; NUM_FP_REGS], pc: i64, } -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub struct Thread { name: String, pub process: Option, @@ -103,7 +103,7 @@ fn start_thread_execution() { #[cfg(test)] mod test { - use super::{Thread, ThreadContext}; + use super::{Thread, ThreadContext, NUM_INT_REGS, NUM_FP_REGS, ObjectType}; macro_rules! get_new_thread { () => { Thread::new("test_thread") }; @@ -112,6 +112,23 @@ mod test { }; } + macro_rules! expected_initial_state { + () => { expected_initial_state!("test_thread") }; + ($a:literal) => { { + let mut x = Thread::new($a); + x.name = $a.to_string(); + x.process = Option::None; + x.thread_context = ThreadContext { + int_registers: [0; NUM_INT_REGS], + float_registers: [0f32; NUM_FP_REGS], + pc: 0 + }; + x.stack_pointer = 0; + x.object_type = ObjectType::ThreadType; + x } + }; + } + #[test] fn test_macro() { let t = get_new_thread!("hello"); @@ -123,6 +140,8 @@ mod test { #[test] fn check_init() { let t = get_new_thread!(); + let expected_state = expected_initial_state!(); + assert_eq!(t, expected_state) } } \ No newline at end of file diff --git a/test_programs/userlib/libnachos.o b/test_programs/userlib/libnachos.o new file mode 100644 index 0000000000000000000000000000000000000000..26f4ccaceb20d8eedc82ca547f5f92ffa2644878 GIT binary patch literal 15488 zcmcJV4RBP~b;s}SKIsvVLH5cuDI``|0W!wwuC)3}NV6`oA+8#$4r#tp{ zp8vh)N@uTj38|CE?0fh9-v6F^?zx}uiLX7=_-rr`Q1%F@|5b~3mMYa(Z_*xJ5;~bs zMQVi#2Lf}E_`|_S^yOgK3xpzDPR|~x?I$)hPuKa0K3|0klsZ9qCi;{L)Aa~xL-9b6 z@`m<-1p@PtEf1?m-OGw>1S9d&^O5Me`M>g&N)PyIn0}#JZ+?wWwhDcf{yN=P_s?6K zX}>^)iILp^*$t4rAloHB7X6CUotur6dGnEV-h8J@tT?ig&# zFWA}#pQtQulkso)RPTIs&F*(-U+NcgvR@!xXuD9gx0G{C5ohWTIv!!tBhGL7nFR9c zdx}xjfT{ES^-CMS*0vX2=1L!spD#qmS!S%5KTp3xj~VxxMK z+Hm-U9ZT8vQD6Ga;TocR)c!o?MBlXI?V|2Ko#1le)i{m{GY)`~F>;i#(d& z3TS?trTJ|(?H8&@#T5F*Y-Gz6&70nAq;6^!^UUHrrItO=-0^FkbCTaSaiMm(ix`dX z%}k?>xSk%(K?OYL-oKtvtP506s;{0;XZk|j;+($7M>YfxIa{2wcjIKk$^{Y0R3{*3*}%vKpgN}h{W?pWX!yW=Q$DhmGz+NQJe&iO7)#Wr+SI}6U*6p-qbShFeHbv|3H1(0` zG7XjS0>%(k8i)s>1g5jkFTrYS1;dLL;H}l-xQ#>{c8F|VK9B! z4~A(Dw0kP;%MX0DkM?IYzmWenru}F;mAo>6`b~$i_lRGcM){`S<2f-}Q#;kA0FAd> z;ei3#yIq?)LiVsvF>64BvGXqa@q^gEw8TEuAEtJh!ydtoO={nnvnM7Ltp&6`do$_FZ-*ArnD>|`kJH+DG~ZTJ0>b`BLRu5*jy zUB?JxAL}H=OZQKIQjNbiadROCr`}Ht&f}fz0phoGE_$$h=L_A~%`x8O`cvm=8B$4CScPyV>(=Xk){jTrnrxPiEP~SdW^$V)8q_XXkS; z^G^2wWzqgCS3Rhl*)-ah?c<%8=0uvO5|Jz)Ouc3zo4uJxg-6f(X#CK=kjD?z9L>+%viY3oMZNp4>YzY zMrOaEzcc9l=fd8I_Q*e@d3rjc_b~nTU1T}Ei>%;xkvsHVDM;Uyg0z?O@NFs*AEn(-BymhY=9@G;VsPHaqPD-f6L(qn6Gv0^e}I7crWt?hku26k<*11=8=*>6@ zsMF2>zQuZ4O0$j`<|7U_6I(#N<8V*+?|{1I@DDIAbIM)GJnHZ;^P>)5&HSXpKg7Jz zDR&+7VxHG*3?eNXa2OqIYbB!@?cX$o+wGRI%^HIlsg88wBv+X~_eA3ZB$9%P8 z|9R#+?SjeXb}(;p_~)2MS7ev_MQh*TN#<7_JNudUI{FUgXNt1zcQbEVnaz8dUvlhx zh54w%UtxaIu|L4P&*6j2w>$is%!^iK`*WQ6Z7i(f7-rt+@b5Ce>F^&g-{SB;XMV=v zXPKXL_>Y)hb@<;hzu?sC@0l-i>h({|6Hfg9h52EJUuJ&J;s3$>w!_Dn?{LcfFXrz! z{C}9Acla&lLk_>ooc=tVbp-T!7EpuEhQntbb@UH0KkVqk%x^mUgUqiu{Bh=Gj{Wt_ zmpS?;nU^@@H^#i*u~W(Ge3hD0C9YQ`6Y)p zGcR`9YcF%<%o|@~o^Zx>7xNa!&Ozok91hn)%9-TZ-;i<^1>#>OJ5G~m_1B0$Li^qZ z&ih%u4(8DxXZp!c^`6v?Z3;snD+y=9uv%8XMULVlhzK0`gOKH!@P|9!+F++$PdKx z6!*8I%vTc675@^}Ut>E>tbaU@UbVOFInbQk-`P`PR;hDU>Rh^UV!Cx=mAXXT7BSsaG2K?N zN?oFEvY2kOSe4GJn<*BDwK|+?b@(8zMVYnL>Y3iQ6!*BT)a_EO>OkwE9l8fn&+AEb zCp)@0(e;u^w6`8$(ww41s`Fr1S8KOUwRaxUspeE?8-b424wD@Tot+Xrt;p4Ku%nA^ zD8*fy3bVcZGu>_QV;6?OF6#H{1xn}UXn# zjia~R)mtCn&sRAwE|$CcH&}z^Pfq=Ip2S=t=aZ|fcXe@f`fgx(HL__<#2Vji^c zbA#Z!1>Y$6QRc8?=L9@HFZdHee?#z1g5MVWNx>U<9|8ND1#is5o0!A@r-Xh`=qm(2 zCiK58_!YsUf*14t1^&bY-_9K6Rto-Ep_hHVojJyq+&Wt>wJ_JkdW;FFx7^jISdVe~ z4H)3Va#w$t_3%G##dM|rmZA^TSMnj|@Lz7tEqCo7V?F$rddpos{Wn>Cxc*!2>PLm2 z)h4Sxk1f2cl|M|aCYd`x1|A;2$WWRgC|Dqh+wLd8QmwL-x{ZJnNEqC>A2tPk6{JAao7Qt<& zM|~wP;=us^F`+MEj&}SV!Ak}IxZnw4Cn0#d;7<$Ae{Rz2(eDc0FZ7ZR<>4cF_z#(* zz2qkw%iVaMV?Fwt)LZWA-x1|*75>jMN8B0&FXcgtI6otJo#4+3eo=6#zrq~$w+a1} z&~F#Kjt39Q{e<9Kn7e-N7y9RfzDw}m6FepCGzxx9=zm}E*9HHi;Bg)#@Kfp=n8VNK zg?^{dHwiu>_#X&XVAu3h%iZzb&w9)c zQg6Ad9~Az`a!(6?_UIDL>8jvK!LJEBvR)nnKnLQ}qEqISV2(?x;EjUs6}(08eS#ll z4*OC+BJ}%({tdy~1iz8Tj(rKl<3ASq?I@5A@Gt3paYM)bjqCU-+x>lWj*}=6QMsWc(>rQ%yHqRTR*kj?N@zaliAfwOa>a*ppzC`H1F7%eW`f}C;=z37-Hw*rv z;8DTl{vn=++dV4mOTFDAxjZ54$a3x2boF*Ec6p<)bBNQpGzl*K*^!6aHNv%T=Wv(r z&SS^UA+FwzaqwQwi;EpouD**kE>Gp*)~2gJEc7pNT3;%9Ug}6S?@<->rO#aV+f;XJ zdvisqwKt_ITAEYMs$x%1kE+nLyVHe+jB70+9Qj2Kj~7+ zjJoja?}DiWr{diI?E}vy_=@!fEW!8oa%sIuC3v2~HWTI8Ib$^oH!u(Jy}hKIaxI4q zd0a`}A{Qrh}&af}kV>R-$+nZ;}v^)C?lZT<1Cg7WP=KuLYv z=JMBCz*k#;d&Qob>TbL7g1Y2UlYDZ4n1sz|G49>E<5`09@8|s*w(IEQw*J+Sx%11&_-IEW0Z}C2KiJA57vTPfP2Gt_rXe%%0d&J%)Gw9*c5j20p27Tf7eIh@ zO`Q_DSLi;WGeS=Yofo<$^peoaLT@Ct#$6HqGvTiae@*Chp`Qu8AvB17pkr&Sl<<3n z?h`sA^n}oPp=&}f3B4@ziqNY_bV||RU;0yA-ps)am&rojj7mk1JeOc?9 zD%0&U-HLd_s&_^*cE&bI(T{|#1CL8<8w^n`ag<3@naH3eZ;}{ zGe4>L;|~5?=JSgG#=(y=UsC+Aga4lSMa7Rh_%qC3Q+&?BUt)e)@fRHYW#)fVe9^)C z%->gh&B6c7{3FHJ9sE`1*A)M&gTKN2zly)^;OV*0{&}MKn-2aC^UoE3%fYWOzoGcw z9sEP)Hx>WD!T-g4m-^BA)4~74{2s+WcJS-W_bUFWgMY>RVa306@Nby!SNv-Sza2Sx zU&D&;#60f%f!0anvV5TW*bmde{b`U#(L`J(%>$)ONgDm}@bVL=fr0!j*Z?kFY_R zWNpcs#@vRgm13(0N}?Wc`k0+Fjn$LPc{3GL!a*td&aawc!8BGi8P;>QLQ6oEwFT=n z)^%#G=+SbrFFSVv~NoWc~W#LOPetCz3KVT24bZ5lb>KS+JgGTlyP*|sr-GI zQ+s`K%P1~NiIwpMCiHyYxBW3}`>y%_tp?QdKaB0k%iz@({J$p8<_;{0i}nJY>nP}a zgmb5#^|sjLaSyh+&ACd8u(;Fk0XAo8U Date: Thu, 9 Mar 2023 13:33:00 +0100 Subject: [PATCH 35/37] Put default thread name in a const --- src/kernel/thread.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index d4aedbc..298df68 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -104,17 +104,18 @@ fn start_thread_execution() { mod test { use super::{Thread, ThreadContext, NUM_INT_REGS, NUM_FP_REGS, ObjectType}; + const DEFAULT_THREAD_NAME: &str = "test_thread"; macro_rules! get_new_thread { - () => { Thread::new("test_thread") }; + () => { Thread::new(DEFAULT_THREAD_NAME) }; ($a:literal) => { Thread::new(&$a.to_string()) }; } macro_rules! expected_initial_state { - () => { expected_initial_state!("test_thread") }; - ($a:literal) => { { + () => { expected_initial_state!(DEFAULT_THREAD_NAME) }; + ($a:expr) => { { let mut x = Thread::new($a); x.name = $a.to_string(); x.process = Option::None; From e1ba3f6078dbf3887a2d7da46830eb73c8ac80a5 Mon Sep 17 00:00:00 2001 From: Quentin Legot Date: Thu, 9 Mar 2023 14:00:42 +0100 Subject: [PATCH 36/37] Changed all reference to thread with an RefCell to enforce mutability --- src/kernel/mgerror.rs | 40 +++++++++++++++++------------------ src/kernel/scheduler.rs | 7 +++--- src/kernel/synch.rs | 41 ++++++++++++++++++++---------------- src/kernel/thread.rs | 4 ---- src/kernel/thread_manager.rs | 28 ++++++++++++------------ src/kernel/ucontext.rs | 2 +- 6 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/kernel/mgerror.rs b/src/kernel/mgerror.rs index 453a9bd..54e0e58 100644 --- a/src/kernel/mgerror.rs +++ b/src/kernel/mgerror.rs @@ -1,31 +1,31 @@ /// Error enum, use it with Result pub enum ErrorCode { - INC_ERROR, - OPENFILE_ERROR, - EXEC_FILE_FORMAT_ERROR, - OUT_OF_MEMORY, + IncError, + OpenfileError, + ExecFileFormatError, + OutOfMemory, - OUT_OF_DISK, - ALREADY_IN_DIRECTORY, - INEXIST_FILE_ERROR, - INEXIST_DIRECTORY_ERROR, - NOSPACE_IN_DIRECTORY, - NOT_A_FILE, - NOT_A_DIRECTORY, - DIRECTORY_NOT_EMPTY, - INVALID_COUNTER, + OutOfDisk, + AlreadyInDirectory, + InexistFileError, + InexistDirectoryError, + NospaceInDirectory, + NotAFile, + NotADirectory, + DirectoryNotEmpty, + InvalidCounter, /* Invalid typeId fields: */ - INVALID_SEMAPHORE_ID, - INVALID_LOCK_ID, - INVALID_CONDITION_ID, - INVALID_FILE_ID, - INVALID_THREAD_ID, + InvalidSemaphoreId, + InvalidLockId, + InvalidConditionId, + InvalidFileId, + InvalidThreadId, /* Other messages */ - WRONG_FILE_ENDIANESS, - NO_ACIA, + WrongFileEndianess, + NoAcia, NUMMSGERROR /* Must always be last */ } \ No newline at end of file diff --git a/src/kernel/scheduler.rs b/src/kernel/scheduler.rs index 0398799..c0c6cb3 100644 --- a/src/kernel/scheduler.rs +++ b/src/kernel/scheduler.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::rc::Rc; use crate::utility::list::List; @@ -7,7 +8,7 @@ use super::system::System; #[derive(PartialEq)] pub struct Scheduler { - ready_list: List> + ready_list: List>> } impl Scheduler { @@ -28,7 +29,7 @@ impl Scheduler { /// ## Pamameter /// /// **thread** is the thread to be put on the read list - pub fn ready_to_run(&mut self, thread: Rc) { + pub fn ready_to_run(&mut self, thread: Rc>) { self.ready_list.push(thread); } @@ -38,7 +39,7 @@ impl Scheduler { /// Thread is removed from the ready list. /// /// **return** Thread thread to be scheduled - pub fn find_next_to_run(&mut self) -> Option> { + pub fn find_next_to_run(&mut self) -> Option>> { self.ready_list.pop() } diff --git a/src/kernel/synch.rs b/src/kernel/synch.rs index 98a1f76..77fc56c 100644 --- a/src/kernel/synch.rs +++ b/src/kernel/synch.rs @@ -2,26 +2,29 @@ use crate::utility::list::List; use crate::kernel::thread::Thread; use crate::simulator::interrupt::InterruptStatus::InterruptOff; use crate::simulator::machine::Machine; +use std::cell::RefCell; use std::rc::Rc; use super::scheduler::Scheduler; +use super::thread_manager::ThreadManager; -pub struct Semaphore{ +pub struct Semaphore<'t> { counter:i32, - waiting_queue:List> + waiting_queue:List>>, + thread_manager: Rc>> // On s'assure que le tm vit plus longtemps que les semaphore avec le lifetime } -impl Semaphore{ +impl<'t> Semaphore<'_> { - pub fn p(&mut self, current_thread: Rc, machine: &mut Machine){ + pub fn p(&mut self, current_thread: Rc>, machine: &mut Machine){ let old_status = machine.interrupt.set_status(InterruptOff); self.counter -= 1; if self.counter < 0 { self.waiting_queue.push(Rc::clone(¤t_thread)); - current_thread.sleep(); + self.thread_manager.borrow_mut().thread_sleep(current_thread); } machine.interrupt.set_status(old_status); } @@ -36,16 +39,17 @@ impl Semaphore{ } } -pub struct Lock{ +pub struct Lock<'t>{ - owner: Rc, - waiting_queue:List>, + owner: Rc>, + waiting_queue:List>>, + thread_manager: Rc>>, free: bool } -impl Lock { - pub fn acquire(&mut self, machine: &mut Machine, current_thread: Rc) { +impl<'t> Lock<'_> { + pub fn acquire(&mut self, machine: &mut Machine, current_thread: Rc>) { let old_status = machine.interrupt.set_status(InterruptOff); if self.free { @@ -53,13 +57,13 @@ impl Lock { self.owner = current_thread; } else { self.waiting_queue.push(Rc::clone(¤t_thread)); - current_thread.sleep(); + self.thread_manager.borrow_mut().thread_sleep(current_thread); } machine.interrupt.set_status(old_status); } - pub fn release(&mut self, machine: &mut Machine, scheduler: &mut Scheduler, current_thread: Rc) { + pub fn release(&mut self, machine: &mut Machine, scheduler: &mut Scheduler, current_thread: Rc>) { let old_status = machine.interrupt.set_status(InterruptOff); if self.is_held_by_current_thread(current_thread) { @@ -74,24 +78,25 @@ impl Lock { machine.interrupt.set_status(old_status); } - pub fn is_held_by_current_thread(&mut self, current_thread: Rc) -> bool { + pub fn is_held_by_current_thread(&mut self, current_thread: Rc>) -> bool { Rc::ptr_eq(&self.owner, ¤t_thread) } } -pub struct Condition{ +pub struct Condition<'t>{ - waiting_queue:List> + waiting_queue:List>>, + thread_manager: Rc>>, } -impl Condition { +impl<'t> Condition<'_> { - pub fn wait(&mut self, machine: &mut Machine, current_thread: Rc) { + pub fn wait(&mut self, machine: &mut Machine, current_thread: Rc>) { let old_status = machine.interrupt.set_status(InterruptOff); self.waiting_queue.push(Rc::clone(¤t_thread)); - current_thread.sleep(); + self.thread_manager.borrow_mut().thread_sleep(current_thread); machine.interrupt.set_status(old_status); } diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 298df68..7e185a0 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -69,10 +69,6 @@ impl Thread { // } } - pub fn sleep(&self) { - unreachable!("Has been moved to thread manager"); - } - pub fn save_simulator_state(&self) { todo!(); } diff --git a/src/kernel/thread_manager.rs b/src/kernel/thread_manager.rs index 39a7f81..2d32e55 100644 --- a/src/kernel/thread_manager.rs +++ b/src/kernel/thread_manager.rs @@ -10,7 +10,7 @@ pub const SIMULATORSTACKSIZE: usize = 32 * 1024; pub struct ThreadManager<'a> { pub g_current_thread: Option, pub g_thread_to_be_destroyed: Option, - pub g_alive: List>, + pub g_alive: List>>, pub g_scheduler: Scheduler, pub system: Cell>> } @@ -28,21 +28,21 @@ impl<'a> ThreadManager<'a> { } /// Start a thread, attaching it to a process - pub fn start_thread(&mut self, mut thread: Thread, owner: Process, func_pc: i64, argument: i64) -> Result<(), ErrorCode> { - thread.process = Option::Some(owner); + pub fn start_thread(&mut self, thread: Rc>, owner: Process, func_pc: i64, argument: i64) -> Result<(), ErrorCode> { + let mut thread_m = thread.borrow_mut(); + thread_m.process = Option::Some(owner); let ptr = 0; // todo addrspace - thread.init_thread_context(func_pc, ptr, argument); + thread_m.init_thread_context(func_pc, ptr, argument); let base_stack_addr: [i8; SIMULATORSTACKSIZE] = [0; SIMULATORSTACKSIZE]; // todo AllocBoundedArray - thread.init_simulator_context(base_stack_addr); - thread.process.as_mut().unwrap().num_thread += 1; - let thread_m = Rc::new(thread); - self.get_g_alive().push(Rc::clone(&thread_m)); - self.g_scheduler().ready_to_run(Rc::clone(&thread_m)); + thread_m.init_simulator_context(base_stack_addr); + thread_m.process.as_mut().unwrap().num_thread += 1; + self.get_g_alive().push(Rc::clone(&thread)); + self.g_scheduler().ready_to_run(Rc::clone(&thread)); Result::Ok(()) } /// Wait for another thread to finish its execution - pub fn thread_join(&mut self, id_thread: Rc) { + pub fn thread_join(&mut self, id_thread: Rc>) { while self.get_g_alive().contains(&Rc::clone(&id_thread)) { self.thread_yield(Rc::clone(&id_thread)); } @@ -51,17 +51,17 @@ impl<'a> ThreadManager<'a> { /// 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, thread: Rc) { + pub fn thread_yield(&mut self, thread: Rc>) { todo!(); } /// Put the thread to sleep and relinquish the processor - pub fn thread_sleep(&mut self, thread: Rc) { + pub fn thread_sleep(&mut self, thread: Rc>) { todo!(); } /// Finish the execution of the thread and prepare its deallocation - pub fn thread_finish(&self, thread: Rc) { + pub fn thread_finish(&self, thread: Rc>) { todo!(); } @@ -105,7 +105,7 @@ impl<'a> ThreadManager<'a> { } /// List of alive threads - pub fn get_g_alive(&mut self) -> &mut List> { + pub fn get_g_alive(&mut self) -> &mut List>> { &mut self.g_alive } diff --git a/src/kernel/ucontext.rs b/src/kernel/ucontext.rs index 1ffee6f..c50c223 100644 --- a/src/kernel/ucontext.rs +++ b/src/kernel/ucontext.rs @@ -59,7 +59,7 @@ impl UContextT { pub fn new() -> Self { Self { - stackBottom: Vec::default() + stack_bottom: Vec::default() } } From ecff299b28d7a5a16f623e33f96d94a1d06f2ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Thu, 9 Mar 2023 14:03:35 +0100 Subject: [PATCH 37/37] added comments to macros --- src/kernel/thread.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kernel/thread.rs b/src/kernel/thread.rs index 298df68..31029f8 100644 --- a/src/kernel/thread.rs +++ b/src/kernel/thread.rs @@ -106,6 +106,7 @@ mod test { use super::{Thread, ThreadContext, NUM_INT_REGS, NUM_FP_REGS, ObjectType}; const DEFAULT_THREAD_NAME: &str = "test_thread"; + /// Polymorphic macro to get thread without passing a name by default macro_rules! get_new_thread { () => { Thread::new(DEFAULT_THREAD_NAME) }; ($a:literal) => { @@ -113,6 +114,9 @@ mod test { }; } + /// This macro allows for getting a Thread for which we've ensured proper initial state + /// in case a commit further down the line changes the initial state of threads generated + /// from Thread::new macro_rules! expected_initial_state { () => { expected_initial_state!(DEFAULT_THREAD_NAME) }; ($a:expr) => { {