From dca4a79fffee4ec8e5c1ecd7849b0a378c481308 Mon Sep 17 00:00:00 2001 From: GuillaumeDIDIER Date: Mon, 5 Oct 2020 15:25:46 +0200 Subject: [PATCH] Add turn lock --- Cargo.toml | 3 +- turn_lock/.cargo/config | 2 ++ turn_lock/Cargo.toml | 9 ++++++ turn_lock/src/lib.rs | 68 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 turn_lock/.cargo/config create mode 100644 turn_lock/Cargo.toml create mode 100644 turn_lock/src/lib.rs 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); + } +}