Skip to content

Instantly share code, notes, and snippets.

@veryjos
Created February 6, 2019 02:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veryjos/7a390a917d4ad0c41c9764d9b132b343 to your computer and use it in GitHub Desktop.
Save veryjos/7a390a917d4ad0c41c9764d9b132b343 to your computer and use it in GitHub Desktop.
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