|
|
|
@ -7,16 +7,18 @@ extern crate user_lib;
|
|
|
|
|
extern crate alloc;
|
|
|
|
|
extern crate core;
|
|
|
|
|
|
|
|
|
|
use user_lib::{thread_create, waittid, exit, sleep};
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
|
use user_lib::{exit, sleep, thread_create, waittid};
|
|
|
|
|
|
|
|
|
|
const N: usize = 2;
|
|
|
|
|
const THREAD_NUM: usize = 10;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
enum FlagState {
|
|
|
|
|
Out, Want, In,
|
|
|
|
|
Out,
|
|
|
|
|
Want,
|
|
|
|
|
In,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static mut TURN: usize = 0;
|
|
|
|
@ -25,7 +27,7 @@ static mut FLAG: [FlagState; THREAD_NUM] = [FlagState::Out; THREAD_NUM];
|
|
|
|
|
static GUARD: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
|
|
|
fn critical_test_enter() {
|
|
|
|
|
assert_eq!(GUARD.fetch_add(1, Ordering::SeqCst), 0);
|
|
|
|
|
assert_eq!(GUARD.fetch_add(1, Ordering::SeqCst), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn critical_test_claim() {
|
|
|
|
@ -33,7 +35,7 @@ fn critical_test_claim() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn critical_test_exit() {
|
|
|
|
|
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
|
|
|
|
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eisenberg_enter_critical(id: usize) {
|
|
|
|
@ -43,7 +45,7 @@ fn eisenberg_enter_critical(id: usize) {
|
|
|
|
|
vstore!(&FLAG[id], FlagState::Want);
|
|
|
|
|
loop {
|
|
|
|
|
/* check if any with higher priority is `Want` or `In` */
|
|
|
|
|
let mut prior_thread:Option<usize> = None;
|
|
|
|
|
let mut prior_thread: Option<usize> = None;
|
|
|
|
|
let turn = vload!(&TURN);
|
|
|
|
|
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
|
|
|
|
// FLAG.iter() may lead to some errors, use for-loop instead
|
|
|
|
@ -56,8 +58,11 @@ fn eisenberg_enter_critical(id: usize) {
|
|
|
|
|
if prior_thread.is_none() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
println!("Thread[{}]: prior thread {} exist, sleep and retry",
|
|
|
|
|
id, prior_thread.unwrap());
|
|
|
|
|
println!(
|
|
|
|
|
"Thread[{}]: prior thread {} exist, sleep and retry",
|
|
|
|
|
id,
|
|
|
|
|
prior_thread.unwrap()
|
|
|
|
|
);
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
/* now tentatively claim the resource */
|
|
|
|
@ -86,7 +91,7 @@ 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 {
|
|
|
|
|
for i in (id + 1)..ring_id {
|
|
|
|
|
let idx = i % THREAD_NUM;
|
|
|
|
|
if vload!(&FLAG[idx]) == FlagState::Want {
|
|
|
|
|
next = idx;
|
|
|
|
@ -119,7 +124,7 @@ 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];
|
|
|
|
|
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]));
|
|
|
|
|
}
|
|
|
|
@ -130,4 +135,4 @@ pub fn main() -> i32 {
|
|
|
|
|
}
|
|
|
|
|
println!("main thread exited.");
|
|
|
|
|
0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|