diff --git a/user/src/bin/eisenberg.rs b/user/src/bin/eisenberg.rs new file mode 100644 index 00000000..1ebb2d28 --- /dev/null +++ b/user/src/bin/eisenberg.rs @@ -0,0 +1,114 @@ +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; +extern crate core; + +use user_lib::{thread_create, waittid, exit, sleep}; +use alloc::vec::Vec; + +const N: usize = 2; +const THREAD_NUM: usize = 10; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum FlagState { + Out, Want, In, +} + +static mut TURN: usize = 0; +static mut FLAG: [FlagState; THREAD_NUM] = [FlagState::Out; THREAD_NUM]; + +fn eisenberg_enter_critical(id: usize) { + /* announce that we want to enter */ + loop { + println!("Thread[{}] try enter", id); + store!(&FLAG[id], FlagState::Want); + loop { + /* check if any with higher priority is `Want` or `In` */ + let mut prior_thread:Option = None; + let turn = load!(&TURN); + let ring_id = if id < turn { id + THREAD_NUM } else { id }; + // FLAG.iter() may lead to some errors, use for-loop instead + for i in turn..ring_id { + if load!(&FLAG[i % THREAD_NUM]) != FlagState::Out { + prior_thread = Some(i % THREAD_NUM); + break; + } + } + if prior_thread.is_none() { + break; + } + println!("Thread[{}]: prior thread {} exist, sleep and retry", + id, prior_thread.unwrap()); + sleep(1); + } + /* now tentatively claim the resource */ + store!(&FLAG[id], FlagState::In); + /* enforce the order of `claim` and `conflict check`*/ + memory_fence!(); + /* check if anthor thread is also `In`, which imply a conflict*/ + let mut conflict = false; + for i in 0..THREAD_NUM { + if i != id && load!(&FLAG[i]) == FlagState::In { + conflict = true; + } + } + if !conflict { + break; + } + println!("Thread[{}]: CONFLECT!", id); + /* no need to sleep */ + } + /* clain the trun */ + store!(&TURN, id); + println!("Thread[{}] enter", id); +} + +fn eisenberg_exit_critical(id: usize) { + /* find next one who wants to enter and give the turn to it*/ + let mut next = id; + let ring_id = id + THREAD_NUM; + for i in (id+1)..ring_id { + let idx = i % THREAD_NUM; + if load!(&FLAG[idx]) == FlagState::Want { + next = idx; + break; + } + } + store!(&TURN, next); + /* All done */ + store!(&FLAG[id], FlagState::Out); + println!("Thread[{}] exit, give turn to {}", id, next); +} + +pub fn thread_fn(id: usize) -> ! { + println!("Thread[{}] init.", id); + for _ in 0..N { + eisenberg_enter_critical(id); + for _ in 0..3 { + sleep(2); + } + eisenberg_exit_critical(id); + } + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + let mut v = Vec::new(); + // TODO: really shuffle + assert_eq!(THREAD_NUM, 10); + let shuffle:[usize; 10] = [0, 7, 4, 6, 2, 9, 8, 1, 3, 5]; + for i in 0..THREAD_NUM { + v.push(thread_create(thread_fn as usize, shuffle[i])); + } + for tid in v.iter() { + let exit_code = waittid(*tid as usize); + println!("thread#{} exited with code {}", tid, exit_code); + } + println!("main thread exited."); + 0 +} \ No newline at end of file diff --git a/user/src/bin/peterson.rs b/user/src/bin/peterson.rs new file mode 100644 index 00000000..11447ce9 --- /dev/null +++ b/user/src/bin/peterson.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] +#![feature(core_intrinsics)] + +#[macro_use] +extern crate user_lib; +extern crate alloc; +extern crate core; + +use user_lib::{thread_create, waittid, exit, sleep}; +use alloc::vec::Vec; +const N: usize = 3; + +static mut TURN: usize = 0; +static mut FLAG: [bool; 2] = [false; 2]; + +fn peterson_enter_critical(id: usize, peer_id: usize) { + println!("Thread {} try enter", id); + store!(&FLAG[id], true); + store!(&TURN, peer_id); + memory_fence!(); + while load!(&FLAG[peer_id]) && load!(&TURN) == peer_id { + println!("Thread {} enter fail", id); + sleep(1); + println!("Thread {} retry enter", id); + } + println!("Thread {} enter", id); +} + +fn peterson_exit_critical(id: usize) { + store!(&FLAG[id], false); + println!("Thread {} exit", id); +} + +pub fn thread_fn(id: usize) -> ! { + println!("Thread {} init.", id); + let peer_id: usize = id ^ 1; + for _ in 0..N { + peterson_enter_critical(id, peer_id); + for _ in 0..3 { + sleep(2); + } + peterson_exit_critical(id); + } + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + let mut v = Vec::new(); + v.push(thread_create(thread_fn as usize, 0)); + v.push(thread_create(thread_fn as usize, 1)); + for tid in v.iter() { + let exit_code = waittid(*tid as usize); + println!("thread#{} exited with code {}", tid, exit_code); + } + println!("main thread exited."); + 0 +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index afde2ecc..c1a47a15 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -3,6 +3,7 @@ #![feature(linkage)] #![feature(panic_info_message)] #![feature(alloc_error_handler)] +#![feature(core_intrinsics)] #[macro_use] pub mod console; @@ -129,3 +130,23 @@ pub fn semaphore_down(sem_id: usize) { sys_semaphore_down(sem_id); } +#[macro_export] +macro_rules! store { + ($var_ref: expr, $value: expr) => { + unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) } + }; +} + +#[macro_export] +macro_rules! load { + ($var_ref: expr) => { + unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) } + }; +} + +#[macro_export] +macro_rules! memory_fence { + () => { + core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst) + }; +} \ No newline at end of file