Skip to content

Commit

Permalink
feat(thingbuf): hahahaha static storage works
Browse files Browse the repository at this point in the history
Signed-off-by: Eliza Weisman <[email protected]>
  • Loading branch information
hawkw committed Nov 13, 2021
1 parent 7efe995 commit e47cd7d
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 4 deletions.
28 changes: 27 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ use crate::util::{Backoff, CachePadded};
#[cfg(feature = "alloc")]
mod stringbuf;

#[cfg(feature = "alloc")]
pub use stringbuf::StringBuf;

/// A ringbuf of...things.
///
/// # Examples
///
/// Using a
pub struct ThingBuf<T, S = Box<[Slot<T>]>> {
head: CachePadded<AtomicUsize>,
tail: CachePadded<AtomicUsize>,
Expand Down Expand Up @@ -267,7 +275,7 @@ where
}
}

impl<T> fmt::Debug for ThingBuf<T> {
impl<T, S> fmt::Debug for ThingBuf<T, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ThingBuf")
.field("capacity", &self.capacity())
Expand Down Expand Up @@ -344,6 +352,16 @@ impl<T: Default> Default for Slot<T> {

impl<T> Slot<T> {
const UNINIT: usize = usize::MAX;

#[cfg(not(test))]
pub const fn new(t: T) -> Self {
Self {
value: UnsafeCell::new(t),
state: AtomicUsize::new(Self::UNINIT),
}
}

#[cfg(test)]
pub fn new(t: T) -> Self {
Self {
value: UnsafeCell::new(t),
Expand All @@ -353,7 +371,15 @@ impl<T> Slot<T> {
}

impl<T> Slot<MaybeUninit<T>> {
#[cfg(not(test))]
pub const fn uninit() -> Self {
Self::new(MaybeUninit::uninit())
}

#[cfg(test)]
pub fn uninit() -> Self {
Self::new(MaybeUninit::uninit())
}
}

unsafe impl<T: Sync> Sync for Slot<T> {}
2 changes: 1 addition & 1 deletion src/loom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ mod inner {
pub(crate) struct UnsafeCell<T>(core::cell::UnsafeCell<T>);

impl<T> UnsafeCell<T> {
pub fn new(data: T) -> UnsafeCell<T> {
pub const fn new(data: T) -> UnsafeCell<T> {
UnsafeCell(core::cell::UnsafeCell::new(data))
}

Expand Down
15 changes: 13 additions & 2 deletions src/stringbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use super::*;
use alloc::string::String;

#[derive(Debug)]
pub struct StringBuf {
inner: ThingBuf<String>,
pub struct StringBuf<S = Box<[Slot<String>]>> {
inner: ThingBuf<String, S>,
max_idle_capacity: usize,
}

Expand All @@ -15,7 +15,18 @@ impl StringBuf {
max_idle_capacity: usize::MAX,
}
}
}

impl<S> StringBuf<S>
where
S: AsRef<[Slot<String>]>,
{
pub fn from_array(array: S) -> Self {
Self {
inner: ThingBuf::from_array(array),
max_idle_capacity: usize::MAX,
}
}
pub fn with_max_idle_capacity(self, max_idle_capacity: usize) -> Self {
Self {
max_idle_capacity,
Expand Down
20 changes: 20 additions & 0 deletions src/sync_channel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use super::*;
use crate::loom::sync::{Condvar, Mutex};

pub struct Sender<T> {
inner: Arc<Inner<T>>,
}

pub struct Receiver<T> {
inner: Arc<Inner<T>>,
}

struct Inner<T> {
lock: Mutex<bool>,
cv: Condvar,
buf: ThingBuf<T>,
}

impl<T> Receiver<T> {

}
109 changes: 109 additions & 0 deletions tests/static_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use std::{fmt::Write, sync::Arc, thread};
use thingbuf::{Slot, StringBuf, ThingBuf};

#[test]
fn static_storage_thingbuf() {
let thingbuf = Arc::new(ThingBuf::from_array([
Slot::new(0),
Slot::new(0),
Slot::new(0),
Slot::new(0),
Slot::new(0),
Slot::new(0),
Slot::new(0),
Slot::new(0),
]));

let producer = {
let thingbuf = thingbuf.clone();
thread::spawn(move || {
for i in 0..32 {
let mut thing = 'write: loop {
match thingbuf.push_ref() {
Ok(thing) => break 'write thing,
_ => thread::yield_now(),
}
};
thing.with_mut(|thing| *thing = i);
}
})
};

let mut i = 0;

// While the producer is writing to the queue, push each entry to the
// results string.
while Arc::strong_count(&thingbuf) > 1 {
match thingbuf.pop_ref() {
Some(thing) => thing.with(|thing| {
assert_eq!(*thing, i);
i += 1;
}),
None => thread::yield_now(),
}
}

producer.join().unwrap();

// drain the queue.
while let Some(thing) = thingbuf.pop_ref() {
thing.with(|thing| {
assert_eq!(*thing, i);
i += 1;
})
}
}

#[test]
fn static_storage_stringbuf() {
let stringbuf = Arc::new(StringBuf::from_array([
Slot::new(String::new()),
Slot::new(String::new()),
Slot::new(String::new()),
Slot::new(String::new()),
Slot::new(String::new()),
Slot::new(String::new()),
Slot::new(String::new()),
Slot::new(String::new()),
]));

let producer = {
let stringbuf = stringbuf.clone();
thread::spawn(move || {
for i in 0..16 {
let mut string = 'write: loop {
match stringbuf.write() {
Ok(string) => break 'write string,
_ => thread::yield_now(),
}
};

write!(&mut string, "{:?}", i).unwrap();
}
})
};

let mut results = String::new();

// While the producer is writing to the queue, push each entry to the
// results string.
while Arc::strong_count(&stringbuf) > 1 {
if let Some(string) = stringbuf.pop_ref() {
writeln!(results, "{}", string).unwrap();
}
thread::yield_now();
}

producer.join().unwrap();

// drain the queue.
while let Some(string) = stringbuf.pop_ref() {
writeln!(results, "{}", string).unwrap();
}

let results = dbg!(results);

for (n, ln) in results.lines().enumerate() {
assert_eq!(ln.parse::<usize>(), Ok(n));
}
}

0 comments on commit e47cd7d

Please sign in to comment.