-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constructing a !Sized UnsafeCell #307
Comments
I recommend that you use a type like this one: use loom::cell::UnsafeCell as LoomCell;
use std::cell::UnsafeCell as StdCell;
use std::mem::MaybeUninit;
struct CellSlice<T> {
inner: LoomCell<Box<StdCell<[MaybeUninit<T>]>>>,
}
impl<T> CellSlice<T> {
fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(*const T, usize) -> R,
{
self.inner.with(|ptr| {
let ptr = unsafe { StdCell::raw_get(&**ptr) };
let len = unsafe { (*ptr).len() };
f(ptr.cast(), len)
})
}
fn with_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(*mut T, usize) -> R,
{
self.inner.with_mut(|ptr| {
let ptr = unsafe { StdCell::raw_get(&**ptr) };
let len = unsafe { (*ptr).len() };
f(ptr.cast(), len)
})
}
} |
Wouldn't that lead to a test failure in case someone is reading the already initialized elements, while someone else is writing a new element? [playground] CellSliceuse loom::cell::UnsafeCell as LoomCell;
use std::cell::UnsafeCell as StdCell;
use std::mem::{self, MaybeUninit};
struct CellSlice<T> {
inner: LoomCell<Box<StdCell<[MaybeUninit<T>]>>>,
}
#[allow(dead_code)]
impl<T> CellSlice<T> {
fn new() -> Self {
let boxed: Box<StdCell<[MaybeUninit<T>]>> = unsafe {
let boxed = mem::ManuallyDrop::new(Vec::<T>::new().into_boxed_slice());
std::ptr::read(&boxed as *const _ as *const _)
};
Self {
inner: LoomCell::new(boxed),
}
}
fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(*const T, usize) -> R,
{
self.inner.with(|ptr| {
let ptr = unsafe { StdCell::raw_get(&**ptr) };
let len = unsafe { (*ptr).len() };
f(ptr.cast(), len)
})
}
fn with_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(*mut T, usize) -> R,
{
self.inner.with_mut(|ptr| {
let ptr = unsafe { StdCell::raw_get(&**ptr) };
let len = unsafe { (*ptr).len() };
f(ptr.cast(), len)
})
}
} #[test]
fn concurrent_read_and_write() {
loom::model(|| {
let cell_slice = std::sync::Arc::new(CellSlice::<String>::new());
let read = {
let cell_slice = cell_slice.clone();
loom::thread::spawn(move || {
let _ = cell_slice.with(|_, _| {});
})
};
let write = {
let cell_slice = cell_slice.clone();
loom::thread::spawn(move || {
let _ = cell_slice.with_mut(|_, _| {});
})
};
read.join().unwrap();
write.join().unwrap();
});
} |
True, it would not work with per-field concurrency checking. To do that, perhaps you could use a struct like this: struct CellSlice<T> {
fields: Box<StdCell<[MaybeUninit<T>]>>,
loom_check: Box<[LoomCell<()>]>,
} Then, when accessing field |
That's perfect, thanks. Even allows to keep using the 'normal' |
I'm currently working on an atomic, append-only array-vec, that I now wanted to test using
loom
.Besides the API, one of the major differences between
std::cell::UnsafeCell
andloom::cell::UnsafeCell
is that thestd
version isrepr(transparent)
. This allows i.e. casting between[UnsafeCell<T>]
and[T]
or betweenUnsafeCell<[T]>
and[T]
.The
loom
version is notrepr(transparent)
(and appears to not be able to be), which leads to an interesting problem when trying to cast the slice of potentially uninitialized elements into a slice of elements.My initial design looked somewhat like this:
My first idea to solve the problem was to lift the
UnsafeCell
out of the slice:Box<UnsafeCell<[MaybeUninit<T>]>>
. This would lead to less ergonomic code when reading, since I now have to construct slices from pointers, but should still work. The only problem is, that I cannot create such a slice, sinceloom::cell::UnsafeCell::new
(of course) requiresT
to be sized, and I of course also cannot cast between aBox<[MaybeUninit<T>]>
and aBox<UnsafeCell<[MaybeUninit<T>]>>
due to the same reasons as above:The problem is, that lifting the
UnsafeCell
yet another layer toUnsafeCell<Box<[MaybeUninit<T>]>>
breaks soundness, since I can not guarantee sound read access to the whole slice, only a small part of it:So, as far as I can see, it's currently impossible - or at least I cannot think of any method - to represent that type in a way so that soundness is not broken during the
loom
tests.Is there a know solution for that? Or am I just missing something obvious here?
Here's a playground link to the first code snippet, in case someone wants to play with it.
The text was updated successfully, but these errors were encountered: