diff --git a/Cargo.toml b/Cargo.toml index d619237..179c8ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,8 @@ members = [ "polling_serial", "cache_utils", "cpuid", - "aes-t-tables" + "aes-t-tables", + "turn_lock", ] [package] diff --git a/turn_lock/.cargo/config b/turn_lock/.cargo/config new file mode 100644 index 0000000..2f05654 --- /dev/null +++ b/turn_lock/.cargo/config @@ -0,0 +1,2 @@ +[build] +target = "x86_64-unknown-linux-gnu" diff --git a/turn_lock/Cargo.toml b/turn_lock/Cargo.toml new file mode 100644 index 0000000..c9a1db3 --- /dev/null +++ b/turn_lock/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "turn_lock" +version = "0.1.0" +authors = ["GuillaumeDIDIER "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/turn_lock/src/lib.rs b/turn_lock/src/lib.rs new file mode 100644 index 0000000..124ad81 --- /dev/null +++ b/turn_lock/src/lib.rs @@ -0,0 +1,68 @@ +use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; +use std::sync::Arc; + +pub struct TurnLock { + turn: Arc, + index: usize, + num_turns: usize, +} + +impl TurnLock { + pub fn new(num_turns: usize) -> Vec { + let turn = Arc::new(AtomicUsize::new(0)); + let mut r = Vec::new(); + for i in 0..num_turns { + r.push(TurnLock { + turn: turn.clone(), + index: i, + num_turns, + }) + } + r + } + pub fn wait(&mut self) { + while self.turn.load(Ordering::Acquire) != self.index { + spin_loop_hint(); + } + assert_eq!(self.turn.load(Ordering::Relaxed), self.index); + } + pub fn next(&mut self) { + assert_eq!(self.turn.load(Ordering::Relaxed), self.index); + let r = self.turn.compare_and_swap( + self.index, + (self.index + 1) % self.num_turns, + Ordering::Release, + ); + if r != self.index { + panic!("Released lock out of turn"); + } + } + + pub fn current(&self) -> usize { + self.turn.load(Ordering::SeqCst) + } +} + +#[cfg(test)] +mod tests { + use crate::TurnLock; + + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } + + #[test] + fn three_turns() { + let mut v = TurnLock::new(3); + v[0].wait(); + v[0].next(); + v[1].wait(); + v[1].next(); + v[2].wait(); + v[2].next(); + v[0].wait(); + v[0].next(); + assert_eq!(v[2].current(), 1); + } +}