New TurnLock (contains associated data)
This commit is contained in:
parent
d194a8972e
commit
e5b3e4c788
@ -61,7 +61,14 @@ impl CovertChannelBenchmarkResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn csv(&self) -> String {
|
pub fn csv(&self) -> String {
|
||||||
format!("{},{},{},{},{}", self.num_bytes_transmitted, self.num_bit_errors, self.error_rate, self.time_rdtsc, self.time_seconds.as_nanos())
|
format!(
|
||||||
|
"{},{},{},{},{}",
|
||||||
|
self.num_bytes_transmitted,
|
||||||
|
self.num_bit_errors,
|
||||||
|
self.error_rate,
|
||||||
|
self.time_rdtsc,
|
||||||
|
self.time_seconds.as_nanos()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn csv_header() -> String {
|
pub fn csv_header() -> String {
|
||||||
|
@ -1,52 +1,151 @@
|
|||||||
|
use std::cell::UnsafeCell;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct TurnLock {
|
pub struct RawTurnLock {
|
||||||
turn: Arc<AtomicUsize>,
|
turn: AtomicUsize,
|
||||||
index: usize,
|
|
||||||
num_turns: usize,
|
num_turns: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TurnLock {
|
impl RawTurnLock {
|
||||||
pub fn new(num_turns: usize) -> Vec<Self> {
|
pub fn new(num_turns: usize) -> Self {
|
||||||
let turn = Arc::new(AtomicUsize::new(0));
|
Self {
|
||||||
let mut r = Vec::new();
|
turn: AtomicUsize::new(0),
|
||||||
for i in 0..num_turns {
|
|
||||||
r.push(TurnLock {
|
|
||||||
turn: turn.clone(),
|
|
||||||
index: i,
|
|
||||||
num_turns,
|
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_exchange(
|
|
||||||
self.index,
|
|
||||||
(self.index + 1) % self.num_turns,
|
|
||||||
Ordering::Release,
|
|
||||||
Ordering::Relaxed,
|
|
||||||
);
|
|
||||||
if r.expect("Failed to release lock") != self.index {
|
|
||||||
panic!("Released lock out of turn");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current(&self) -> usize {
|
pub fn is_poisoned(&self) -> bool {
|
||||||
self.turn.load(Ordering::SeqCst)
|
let current = self.turn.load(Ordering::Relaxed);
|
||||||
|
current >= self.num_turns
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn try_wait(&self, turn: usize) -> bool {
|
||||||
|
let current = self.turn.load(Ordering::Acquire);
|
||||||
|
current == turn
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn wait(&self, turn: usize) {
|
||||||
|
let mut current = self.turn.load(Ordering::Acquire);
|
||||||
|
while current < self.num_turns && current != turn {
|
||||||
|
spin_loop_hint();
|
||||||
|
current = self.turn.load(Ordering::Acquire);
|
||||||
|
}
|
||||||
|
if current >= self.num_turns {
|
||||||
|
panic!("Waiting on a poisoned turn lock");
|
||||||
|
}
|
||||||
|
if self.turn.load(Ordering::Relaxed) != turn {
|
||||||
|
panic!("Someone stole the turn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn next(&self, turn: usize) {
|
||||||
|
if self.is_poisoned() {
|
||||||
|
panic!("Using poisoned turn lock");
|
||||||
|
}
|
||||||
|
let current = self.turn.load(Ordering::Relaxed);
|
||||||
|
if current != turn {
|
||||||
|
panic!("Releasing turn lock out of turn");
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = self.turn.compare_exchange(
|
||||||
|
turn,
|
||||||
|
(turn + 1) % self.num_turns,
|
||||||
|
Ordering::Release,
|
||||||
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
if r.expect("Failed to release turn lock") != turn {
|
||||||
|
panic!("Released turn lock out of turn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TurnLockData<T> {
|
||||||
|
pub lock: RawTurnLock,
|
||||||
|
pub data: UnsafeCell<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TurnHandle<T> {
|
||||||
|
raw: Arc<TurnLockData<T>>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TurnHandle<T> {
|
||||||
|
pub fn new(num_turns: usize, data: T) -> Vec<TurnHandle<T>> {
|
||||||
|
let turn_lock = RawTurnLock::new(num_turns);
|
||||||
|
let turn_lock_data = TurnLockData {
|
||||||
|
lock: turn_lock,
|
||||||
|
data: UnsafeCell::new(data),
|
||||||
|
};
|
||||||
|
let arc = Arc::new(turn_lock_data);
|
||||||
|
let mut result = Vec::with_capacity(num_turns);
|
||||||
|
for i in 0..num_turns {
|
||||||
|
result.push(Self {
|
||||||
|
raw: arc.clone(),
|
||||||
|
index: i,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn guard(&mut self) -> TurnLockGuard<T> {
|
||||||
|
TurnLockGuard {
|
||||||
|
handle: &*self,
|
||||||
|
marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait(&mut self) -> TurnLockGuard<T> {
|
||||||
|
unsafe { self.raw.lock.wait(self.index) };
|
||||||
|
// Safety: the turn lock is now held
|
||||||
|
unsafe { self.guard() }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn next(&self) {
|
||||||
|
self.raw.lock.next(self.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "if unused the TurnLock will immediately unlock"]
|
||||||
|
pub struct TurnLockGuard<'a, T> {
|
||||||
|
handle: &'a TurnHandle<T>,
|
||||||
|
marker: PhantomData<&'a T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> TurnLockGuard<'a, T> {
|
||||||
|
pub fn next(self) {
|
||||||
|
drop(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(&self) -> &TurnHandle<T> {
|
||||||
|
self.handle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T> Drop for TurnLockGuard<'a, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.handle.next() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Deref for TurnLockGuard<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { &*self.handle.raw.data.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> DerefMut for TurnLockGuard<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { &mut *self.handle.raw.data.get() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::TurnLock;
|
use crate::TurnHandle;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn it_works() {
|
||||||
@ -55,15 +154,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn three_turns() {
|
fn three_turns() {
|
||||||
let mut v = TurnLock::new(3);
|
let mut v = TurnHandle::<()>::new(3, ());
|
||||||
v[0].wait();
|
let t0 = v[0].wait();
|
||||||
v[0].next();
|
t0.next();
|
||||||
v[1].wait();
|
let t1 = v[1].wait();
|
||||||
v[1].next();
|
t1.next();
|
||||||
v[2].wait();
|
let t2 = v[2].wait();
|
||||||
v[2].next();
|
t2.next();
|
||||||
v[0].wait();
|
let t0 = v[0].wait();
|
||||||
v[0].next();
|
t0.next();
|
||||||
assert_eq!(v[2].current(), 1);
|
//assert_eq!(v[2].current(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user