Add turn lock

This commit is contained in:
GuillaumeDIDIER 2020-10-05 15:25:46 +02:00
parent 456c812d9a
commit dca4a79fff
4 changed files with 81 additions and 1 deletions

View File

@ -5,7 +5,8 @@ members = [
"polling_serial", "polling_serial",
"cache_utils", "cache_utils",
"cpuid", "cpuid",
"aes-t-tables" "aes-t-tables",
"turn_lock",
] ]
[package] [package]

2
turn_lock/.cargo/config Normal file
View File

@ -0,0 +1,2 @@
[build]
target = "x86_64-unknown-linux-gnu"

9
turn_lock/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "turn_lock"
version = "0.1.0"
authors = ["GuillaumeDIDIER <guillaume.didier95@hotmail.fr>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

68
turn_lock/src/lib.rs Normal file
View File

@ -0,0 +1,68 @@
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
use std::sync::Arc;
pub struct TurnLock {
turn: Arc<AtomicUsize>,
index: usize,
num_turns: usize,
}
impl TurnLock {
pub fn new(num_turns: usize) -> Vec<Self> {
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);
}
}