Created
February 6, 2019 02:13
-
-
Save veryjos/7a390a917d4ad0c41c9764d9b132b343 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::mem::{MaybeUninit, transmute}; | |
use std::marker::Send; | |
use std::sync::Arc; | |
use std::sync::atomic::AtomicPtr; | |
/// Size of the buffer used for the underlying circular buffer. | |
const BUFFER_SIZE: usize = 16; | |
/// A cell which is syncronized across threads. | |
/// | |
/// When a reader requests the data held by this cell, the most recently | |
/// written data will be given to the reader. | |
pub struct SyncCell<T: Copy> { | |
control_block: Arc<ControlBlock<T>> | |
} | |
impl<T: Copy> SyncCell<T> { | |
pub fn new() -> SyncCell<T> { | |
SyncCell { | |
control_block: Arc::new(ControlBlock::new()) | |
} | |
} | |
pub fn create_reader(&mut self) -> SyncCellReader<T> { | |
SyncCellReader { | |
control_block: unsafe { transmute(Arc::get_mut(&mut self.control_block)) } | |
} | |
} | |
pub fn create_writer(&mut self) -> SyncCellWriter<T> { | |
SyncCellWriter { | |
control_block: unsafe { transmute(Arc::get_mut(&mut self.control_block)) } | |
} | |
} | |
} | |
/// Control block for a SyncCell. Stored in the heap and used for | |
/// resource reclamation. | |
struct ControlBlock<T: Copy> { | |
current: usize, | |
last_update: AtomicPtr<T>, | |
buffer: [T; BUFFER_SIZE] | |
} | |
impl<T: Copy> ControlBlock<T> { | |
fn new() -> ControlBlock<T> { | |
let b: T = unsafe { MaybeUninit::uninitialized().into_inner() }; | |
let mut buffer = [b; BUFFER_SIZE]; | |
ControlBlock { | |
current: 0, | |
last_update: buffer.as_mut_ptr().into(), | |
buffer | |
} | |
} | |
pub fn update(&mut self, data: T) { | |
self.current = (self.current + 1) % BUFFER_SIZE; | |
self.buffer[self.current] = data; | |
unsafe { | |
self.last_update = self.buffer.as_mut_ptr().add(self.current).into(); | |
} | |
} | |
pub fn read(&mut self) -> T { | |
unsafe { **self.last_update.get_mut() } | |
} | |
} | |
/// Writes into a SyncCell. | |
pub struct SyncCellWriter<T: Copy> { | |
control_block: *mut ControlBlock<T> | |
} | |
impl<T: Copy> SyncCellWriter<T> { | |
pub fn update(&self, data: T) { | |
unsafe { | |
(&mut *self.control_block).update(data) | |
} | |
} | |
} | |
/// Reads from a SyncCell. | |
pub struct SyncCellReader<T: Copy> { | |
control_block: *mut ControlBlock<T> | |
} | |
impl<T: Copy> SyncCellReader<T> { | |
pub fn read(&self) -> T { | |
unsafe { | |
(&mut *self.control_block).read() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment