mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 09:26:26 +04:00
user: add peterson algorithm and Eisenberg & McGuire algorithm
This commit is contained in:
parent
a3f9b5fea9
commit
22db3123d8
114
user/src/bin/eisenberg.rs
Normal file
114
user/src/bin/eisenberg.rs
Normal file
@ -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<usize> = 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
|
||||
}
|
59
user/src/bin/peterson.rs
Normal file
59
user/src/bin/peterson.rs
Normal file
@ -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
|
||||
}
|
@ -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)
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user