Skip to content

Commit 6a689ea

Browse files
committed
Make storage Send + Sync if item is only Send, bump version
1 parent ba69a52 commit 6a689ea

File tree

5 files changed

+67
-13
lines changed

5 files changed

+67
-13
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ readme = "README.md"
77
license = "MIT/Apache-2.0"
88

99
[workspace.dependencies]
10-
ringbuf = { path = ".", version = "0.4.0" }
10+
ringbuf = { path = ".", version = "0.4.1" }
1111

1212
[workspace]
1313
members = ["async", "blocking"]
1414

1515
[package]
1616
name = "ringbuf"
17-
version = "0.4.0"
17+
version = "0.4.1"
1818
edition.workspace = true
1919
authors.workspace = true
2020
description = "Lock-free SPSC FIFO ring buffer with direct access to inner data"

async/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "async-ringbuf"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition.workspace = true
55
authors.workspace = true
66
description = "Async SPSC FIFO ring buffer"

src/storage.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub unsafe trait Storage {
3838
/// # Safety
3939
///
4040
/// Slice must not overlab with existing mutable slices.
41+
///
42+
/// Non-`Sync` items must not be accessed concurrently.
4143
unsafe fn slice(&self, range: Range<usize>) -> &[MaybeUninit<Self::Item>] {
4244
slice::from_raw_parts(self.as_ptr().add(range.start), range.len())
4345
}
@@ -57,8 +59,8 @@ pub struct Ref<'a, T> {
5759
ptr: *mut MaybeUninit<T>,
5860
len: usize,
5961
}
60-
unsafe impl<'a, T> Send for Ref<'a, T> where T: Sync {}
61-
unsafe impl<'a, T> Sync for Ref<'a, T> where T: Sync {}
62+
unsafe impl<'a, T> Send for Ref<'a, T> where T: Send {}
63+
unsafe impl<'a, T> Sync for Ref<'a, T> where T: Send {}
6264
unsafe impl<'a, T> Storage for Ref<'a, T> {
6365
type Item = T;
6466
#[inline]
@@ -88,7 +90,7 @@ impl<'a, T> From<Ref<'a, T>> for &'a mut [MaybeUninit<T>] {
8890
pub struct Owning<T: ?Sized> {
8991
data: UnsafeCell<T>,
9092
}
91-
unsafe impl<T: ?Sized> Sync for Owning<T> where T: Sync {}
93+
unsafe impl<T: ?Sized> Sync for Owning<T> where T: Send {}
9294
impl<T> From<T> for Owning<T> {
9395
fn from(value: T) -> Self {
9496
Self {
@@ -136,7 +138,7 @@ pub struct Heap<T> {
136138
#[cfg(feature = "alloc")]
137139
unsafe impl<T> Send for Heap<T> where T: Send {}
138140
#[cfg(feature = "alloc")]
139-
unsafe impl<T> Sync for Heap<T> where T: Sync {}
141+
unsafe impl<T> Sync for Heap<T> where T: Send {}
140142
#[cfg(feature = "alloc")]
141143
unsafe impl<T> Storage for Heap<T> {
142144
type Item = T;
@@ -188,3 +190,19 @@ impl<T> Drop for Heap<T> {
188190
drop(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) });
189191
}
190192
}
193+
194+
#[cfg(test)]
195+
mod tests {
196+
use super::*;
197+
use core::{cell::Cell, marker::PhantomData};
198+
199+
struct Check<S: Storage + Send + Sync + ?Sized>(PhantomData<S>);
200+
201+
#[allow(dead_code)]
202+
fn check_send_sync() {
203+
let _: Check<Ref<Cell<i32>>>;
204+
let _: Check<Array<Cell<i32>, 4>>;
205+
let _: Check<Slice<Cell<i32>>>;
206+
let _: Check<Heap<Cell<i32>>>;
207+
}
208+
}

src/tests/shared.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use crate::{storage::Heap, traits::*, SharedRb};
2-
use std::{thread, thread::sleep, time::Duration, vec::Vec};
2+
use std::{cell::Cell, thread, thread::sleep, time::Duration, vec::Vec};
3+
4+
fn yield_() {
5+
sleep(Duration::from_millis(1));
6+
}
37

4-
#[cfg(feature = "std")]
58
#[test]
69
fn concurrent() {
7-
fn yield_() {
8-
sleep(Duration::from_millis(1));
9-
}
10-
1110
const MSG: &[u8] = b"The quick brown fox jumps over the lazy dog\0";
1211
let rb = SharedRb::<Heap<u8>>::new(4);
1312
let (mut prod, mut cons) = rb.split();
@@ -34,3 +33,38 @@ fn concurrent() {
3433
pjh.join().unwrap();
3534
assert_eq!(cjh.join().unwrap(), MSG);
3635
}
36+
37+
#[test]
38+
fn non_sync() {
39+
const N: i32 = 256;
40+
41+
let rb = SharedRb::<Heap<Cell<i32>>>::new(4);
42+
let (mut prod, mut cons) = rb.split();
43+
44+
let pjh = thread::spawn({
45+
move || {
46+
for i in 0..N {
47+
while prod.try_push(Cell::new(i)).is_err() {
48+
yield_();
49+
}
50+
}
51+
}
52+
});
53+
54+
let cjh = thread::spawn(move || {
55+
for i in 0..N {
56+
assert_eq!(
57+
i,
58+
loop {
59+
match cons.try_pop() {
60+
Some(i) => break i.get(),
61+
None => yield_(),
62+
}
63+
}
64+
);
65+
}
66+
});
67+
68+
pjh.join().unwrap();
69+
cjh.join().unwrap();
70+
}

src/traits/observer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub trait Observer {
2626
/// # Safety
2727
///
2828
/// Slice must not overlap with any mutable slice existing at the same time.
29+
///
30+
/// Non-`Sync` items must not be accessed from multiple threads at the same time.
2931
unsafe fn unsafe_slices(&self, start: usize, end: usize) -> (&[MaybeUninit<Self::Item>], &[MaybeUninit<Self::Item>]);
3032

3133
/// Get mutable slice between `start` and `end` indices.

0 commit comments

Comments
 (0)