Getting 'unordered' semantics in Rust - rust

How do I create a fixed length list of integers V with the "unordered" semantics of LLVM (see https://llvm.org/docs/Atomics.html).
The "unordered" semantics means if you read a location in the thread, you will get a previously written value (not necessarily the most recent one, as the optimisers is allowed to rearrange / cache values from the array). This can be viewed as the "natural" behaviour of reading and writing the raw memory, as long as values are only written and read in a single CPU instruction (so other threads never see "half a written value").
It is important to me this is as close to the performance of a single-threaded array of integers as possible, because writes are extremely rare, and I am happy for them to be lost.

rustc exposes a fair number of LLVM intrinsics through the std::intrinsics module, which is permanently unstable.
Still, it is available in Nightly, and there you can find:
atomic_load_unordered,
atomic_store_unordered.
With those at hand, you can use UnsafeCell as a basic building block to build your own UnorderedAtomicXXX.
You can follow the std atomics to help with your implementation. The basics should look like:
pub struct UnorderedAtomic(UnsafeCell<i32>);
impl UnorderedAtomic {
pub fn new() -> Self {
UnorderedAtomic(Default::default())
}
pub fn load(&self) -> i32 {
unsafe { atomic_load_unordered(self.0.get()) }
}
pub fn store(&self, i: i32) {
unsafe { atomic_store_unordered(self.0.get(), i) }
}
unsafe fn raw(&self) -> *mut i32 { self.0.get() }
}
It's unclear whether you can get unordered compare/exchange or fetch/add.

Related

Are mutable static primitives actually `unsafe` if single-threaded?

I'm developing for a single-core embedded chip. In C & C++ it's common to statically-define mutable values that can be used globally. The Rust equivalent is roughly this:
static mut MY_VALUE: usize = 0;
pub fn set_value(val: usize) {
unsafe { MY_VALUE = val }
}
pub fn get_value() -> usize {
unsafe { MY_VALUE }
}
Now anywhere can call the free functions get_value and set_value.
I think that this should be entirely safe in single-threaded embedded Rust, but I've not been able to find a definitive answer. I'm only interested in types that don't require allocation or destruction (like the primitive in the example here).
The only gotcha I can see is with the compiler or processor reordering accesses in unexpected ways (which could be solves using the volatile access methods), but is that unsafe per se?
Edit:
The book suggests that this is safe so long as we can guarantee no multi-threaded data races (obviously the case here)
With mutable data that is globally accessible, it’s difficult to ensure there are no data races, which is why Rust considers mutable static variables to be unsafe.
The docs are phrased less definitively, suggesting that data races are only one way this can be unsafe but not expanding on other examples
accessing mutable statics can cause undefined behavior in a number of ways, for example due to data races in a multithreaded context
The nomicon suggests that this should be safe so long as you don't somehow dereference a bad pointer.
Be aware as there is no such thing as single-threaded code as long as interrupts are enabled. So even for microcontrollers, mutable statics are unsafe.
If you really can guarantee single-threaded access, your assumption is correct that accessing primitive types should be safe. That's why the Cell type exists, which allows mutability of primitive types with the exception that it is not Sync (meaning it explicitely prevents threaded access).
That said, to create a safe static variable, it needs to implement Sync for exactly the reason mentioned above; which Cell doesn't do, for obvious reasons.
To actually have a mutable global variable with a primitive type without using an unsafe block, I personally would use an Atomic. Atomics do not allocate and are available in the core library, meaning they work on microcontrollers.
use core::sync::atomic::{AtomicUsize, Ordering};
static MY_VALUE: AtomicUsize = AtomicUsize::new(0);
pub fn set_value(val: usize) {
MY_VALUE.store(val, Ordering::Relaxed)
}
pub fn get_value() -> usize {
MY_VALUE.load(Ordering::Relaxed)
}
fn main() {
println!("{}", get_value());
set_value(42);
println!("{}", get_value());
}
Atomics with Relaxed are zero-overhead on almost all architectures.
In this case it's not unsound, but you still should avoid it because it is too easy to misuse it in a way that is UB.
Instead, use a wrapper around UnsafeCell that is Sync:
pub struct SyncCell<T>(UnsafeCell<T>);
unsafe impl<T> Sync for SyncCell<T> {}
impl<T> SyncCell<T> {
pub const fn new(v: T) -> Self { Self(UnsafeCell::new(v)); }
pub unsafe fn set(&self, v: T) { *self.0.get() = v; }
}
impl<T: Copy> SyncCell<T> {
pub unsafe fn get(&self) -> T { *self.0.get() }
}
If you use nightly, you can use SyncUnsafeCell.
Mutable statics are unsafe in general because they circumvent the normal borrow checker rules that enforce either exactly 1 mutable borrow exists or any number of immutable borrows exist (including 0), which allows you to write code which causes undefined behavior. For instance, the following compiles and prints 2 2:
static mut COUNTER: i32 = 0;
fn main() {
unsafe {
let mut_ref1 = &mut COUNTER;
let mut_ref2 = &mut COUNTER;
*mut_ref1 += 1;
*mut_ref2 += 1;
println!("{mut_ref1} {mut_ref2}");
}
}
However we have two mutable references to the same location in memory existing concurrently, which is UB.
I believe the code that you posted there is safe, but I generally would not recommend using static mut. Use an atomic, SyncUnsafeCell/UnsafeCell, a wrapper around a Cell that implements Sync which is safe since your environment is single-threaded, or honestly just about anything else. static mut is wildly unsafe and its use is highly discouraged.
In order to sidestep the issue of exactly how mutable statics can be used safely in single-threaded code, another option is to use thread-local storage:
use std::cell::Cell;
thread_local! (static MY_VALUE: Cell<usize> = {
Cell::new(0)
});
pub fn set_value(val: usize) {
MY_VALUE.with(|cell| cell.set(val))
}
pub fn get_value() -> usize {
MY_VALUE.with(|cell| cell.get())
}

Rust (Newbie): Read and write (mutable) access to the same underlying array from multiple threads for in-memory database?

I'm considering making Rust my primary development language instead of Go, so I've been reading the docs.
One thing that my work requires a lot of is reading and writing from multiple threads into a custom database that is stored in memory as a single massive array and could be 32GB in size. The database functions are designed to avoid race conditions, and mutexes or atomic primitives are used where necessary.
The Rust doc implies that an array can only be either mutable (writeable) on a single thread, or non-mutable (read only) by many threads, and cannot be writable on one and readable on another simultaneously. How then can an in-memory database be used...? It doesn't make sense!
Do I have this wrong?
Forgive me that I can't give any specific Rust example, because I'm still learning the Rust syntax, and to be honest I need to know the answer to this question before using all my time learning a language I will be unable to use.
There is an unsafe way to do it, namely using the UnsafeCell, which returns mutable raw pointers to its interior data. These are not tracked by the Borrow-Checker and so you have to make sure the invariants are upheld
pub struct UnsafeVec<T> {
data: UnsafeCell<Vec<T>>
}
impl<T> UnsafeVec<T> {
pub fn new() -> Self {
UnsafeVec { data: UnsafeCell::new(Vec::new()) }
}
pub fn push(&mut self, arg: T) {
self.data.get_mut().push(arg)
}
pub unsafe fn index_mut(&self, index: usize) -> &mut T {
&mut (*self.data.get())[index]
}
}
unsafe impl<T> Sync for UnsafeVec<T> {}
unsafe impl<T> Send for UnsafeVec<T> {}
which allows you to write
fn main() {
let mut unsafe_vec = UnsafeVec::<i32>::new();
unsafe_vec.push(15);
unsafe {
*unsafe_vec.index_mut(0) += 1;
}
}
The method index_mut allows to modify the interior vector with an immutable reference.
The Sync and Send traits signal the compiler that the type can be safely shared across threads, which is only true if you prevent possible data races manually!.
Again, this is an unsafe option that requires you to uphold the invariants yourself.

How do I force Rust to allocate a big object on the heap without using a Vec? [duplicate]

In this code...
struct Test { a: i32, b: i64 }
fn foo() -> Box<Test> { // Stack frame:
let v = Test { a: 123, b: 456 }; // 12 bytes
Box::new(v) // `usize` bytes (`*const T` in `Box`)
}
... as far as I understand (ignoring possible optimizations), v gets allocated on the stack and then copied to the heap, before being returned in a Box.
And this code...
fn foo() -> Box<Test> {
Box::new(Test { a: 123, b: 456 })
}
...shouldn't be any different, presumably, since there should be a temporary variable for struct allocation (assuming compiler doesn't have any special semantics for the instantiation expression inside Box::new()).
I've found Do values in return position always get allocated in the parents stack frame or receiving Box?. Regarding my specific question, it only proposes the experimental box syntax, but mostly talks about compiler optimizations (copy elision).
So my question remains: using stable Rust, how does one allocate structs directly on the heap, without relying on compiler optimizations?
As of Rust 1.39, there seems to be only one way in stable to allocate memory on the heap directly - by using std::alloc::alloc (note that the docs state that it is expected to be deprecated). It's reasonably unsafe.
Example:
#[derive(Debug)]
struct Test {
a: i64,
b: &'static str,
}
fn main() {
use std::alloc::{alloc, dealloc, Layout};
unsafe {
let layout = Layout::new::<Test>();
let ptr = alloc(layout) as *mut Test;
(*ptr).a = 42;
(*ptr).b = "testing";
let bx = Box::from_raw(ptr);
println!("{:?}", bx);
}
}
This approach is used in the unstable method Box::new_uninit.
It turns out there's even a crate for avoiding memcpy calls (among other things): copyless. This crate also uses an approach based on this.
You seem to be looking for the box_syntax feature, however as of Rust 1.39.0 it is not stable and only available with a nightly compiler. It also seems like this feature will not be stabilized any time soon, and might have a different design if it ever gets stabilized.
On a nightly compiler, you can write:
#![feature(box_syntax)]
struct Test { a: i32, b: i64 }
fn foo() -> Box<Test> {
box Test { a: 123, b: 456 }
}
Is there a way to allocate directly to the heap without box?
No. If there was, it wouldn't need a language change.
People tend to avoid this by using the unstable syntax indirectly, such as by using one of the standard containers which, in turn, uses it internally.
See also:
How to allocate arrays on the heap in Rust 1.0?
Is there any way to allocate a standard Rust array directly on the heap, skipping the stack entirely?
What does the box keyword do?
What is the <- symbol in Rust?
I recently had the same problem. Based on the answers here and other places, I wrote a simple function for heap allocation:
pub fn unsafe_allocate<T>() -> Box<T> {
let mut grid_box: Box<T>;
unsafe {
use std::alloc::{alloc, dealloc, Layout};
let layout = Layout::new::<T>();
let ptr = alloc(layout) as *mut T;
grid_box = Box::from_raw(ptr);
}
return grid_box;
}
This will create a region in memory automatically sized after T and unsafely convince Rust that that memory region is an actual T value. The memory may contain arbitrary data; you should not assume all values are 0.
Example use:
let mut triangles: Box<[Triangle; 100000]> = unsafe_allocate::<[Triangle; 100000]>();

Is it safe to `Send` struct containing `Rc` if strong_count is 1 and weak_count is 0?

I have a struct that is not Send because it contains Rc. Lets say that Arc has too big overhead, so I want to keep using Rc. I would still like to occasionally Send this struct between threads, but only when I can verify that the Rc has strong_count 1 and weak_count 0.
Here is (hopefully safe) abstraction that I have in mind:
mod my_struct {
use std::rc::Rc;
#[derive(Debug)]
pub struct MyStruct {
reference_counted: Rc<String>,
// more fields...
}
impl MyStruct {
pub fn new() -> Self {
MyStruct {
reference_counted: Rc::new("test".to_string())
}
}
pub fn pack_for_sending(self) -> Result<Sendable, Self> {
if Rc::strong_count(&self.reference_counted) == 1 &&
Rc::weak_count(&self.reference_counted) == 0
{
Ok(Sendable(self))
} else {
Err(self)
}
}
// There are more methods, some may clone the `Rc`!
}
/// `Send`able wrapper for `MyStruct` that does not allow you to access it,
/// only unpack it.
pub struct Sendable(MyStruct);
// Safety: `MyStruct` is not `Send` because of `Rc`. `Sendable` can be
// only created when the `Rc` has strong count 1 and weak count 0.
unsafe impl Send for Sendable {}
impl Sendable {
/// Retrieve the inner `MyStruct`, making it not-sendable again.
pub fn unpack(self) -> MyStruct {
self.0
}
}
}
use crate::my_struct::MyStruct;
fn main() {
let handle = std::thread::spawn(|| {
let my_struct = MyStruct::new();
dbg!(&my_struct);
// Do something with `my_struct`, but at the end the inner `Rc` should
// not be shared with anybody.
my_struct.pack_for_sending().expect("Some Rc was still shared!")
});
let my_struct = handle.join().unwrap().unpack();
dbg!(&my_struct);
}
I did a demo on the Rust playground.
It works. My question is, is it actually safe?
I know that the Rc is owned only by a single onwer and nobody can change that under my hands, because it can't be accessed by other threads and we wrap it into Sendable which does not allow access to the contained value.
But in some crazy world Rc could for example internally use thread local storage and this would not be safe... So is there some guarantee that I can do this?
I know that I must be extremely careful to not introduce some additional reason for the MyStruct to not be Send.
No.
There are multiple points that need to be verified to be able to send Rc across threads:
There can be no other handle (Rc or Weak) sharing ownership.
The content of Rc must be Send.
The implementation of Rc must use a thread-safe strategy.
Let's review them in order!
Guaranteeing the absence of aliasing
While your algorithm -- checking the counts yourself -- works for now, it would be better to simply ask Rc whether it is aliased or not.
fn is_aliased<T>(t: &mut Rc<T>) -> bool { Rc::get_mut(t).is_some() }
The implementation of get_mut will be adjusted should the implementation of Rc change in ways you have not foreseen.
Sendable content
While your implementation of MyStruct currently puts String (which is Send) into Rc, it could tomorrow change to Rc<str>, and then all bets are off.
Therefore, the sendable check needs to be implemented at the Rc level itself, otherwise you need to audit any change to whatever Rc holds.
fn sendable<T: Send>(mut t: Rc<T>) -> Result<Rc<T>, ...> {
if !is_aliased(&mut t) {
Ok(t)
} else {
...
}
}
Thread-safe Rc internals
And that... cannot be guaranteed.
Since Rc is not Send, its implementation can be optimized in a variety of ways:
The entire memory could be allocated using a thread-local arena.
The counters could be allocated using a thread-local arena, separately, so as to seamlessly convert to/from Box.
...
This is not the case at the moment, AFAIK, however the API allows it, so the next release could definitely take advantage of this.
What should you do?
You could make pack_for_sending unsafe, and dutifully document all assumptions that are counted on -- I suggest using get_mut to remove one of them. Then, on each new release of Rust, you'd have to double-check each assumption to ensure that your usage if still safe.
Or, if you do not mind making an allocation, you could write a conversion to Arc<T> yourself (see Playground):
fn into_arc<T>(this: Rc<T>) -> Result<Arc<T>, Rc<T>> {
Rc::try_unwrap(this).map(|t| Arc::new(t))
}
Or, you could write a RFC proposing a Rc <-> Arc conversion!
The API would be:
fn Rc<T: Send>::into_arc(this: Self) -> Result<Arc<T>, Rc<T>>
fn Arc<T>::into_rc(this: Self) -> Result<Rc<T>, Arc<T>>
This could be made very efficiently inside std, and could be of use to others.
Then, you'd convert from MyStruct to MySendableStruct, just moving the fields and converting Rc to Arc as you go, send to another thread, then convert back to MyStruct.
And you would not need any unsafe...
The only difference between Arc and Rc is that Arc uses atomic counters. The counters are only accessed when the pointer is cloned or dropped, so the difference between the two is negligible in applications which just share pointers between long-lived threads.
If you have never cloned the Rc, it is safe to send between threads. However, if you can guarantee that the pointer is unique then you can make the same guarantee about a raw value, without using a smart pointer at all!
This all seems quite fragile, for little benefit; future changes to the code might not meet your assumptions, and you will end up with Undefined Behaviour. I suggest that you at least try making some benchmarks with Arc. Only consider approaches like this when you measure a performance problem.
You might also consider using the archery crate, which provides a reference-counted pointer that abstracts over atomicity.

Is there a way to allocate directly to the heap without using the unstable box syntax? [duplicate]

In this code...
struct Test { a: i32, b: i64 }
fn foo() -> Box<Test> { // Stack frame:
let v = Test { a: 123, b: 456 }; // 12 bytes
Box::new(v) // `usize` bytes (`*const T` in `Box`)
}
... as far as I understand (ignoring possible optimizations), v gets allocated on the stack and then copied to the heap, before being returned in a Box.
And this code...
fn foo() -> Box<Test> {
Box::new(Test { a: 123, b: 456 })
}
...shouldn't be any different, presumably, since there should be a temporary variable for struct allocation (assuming compiler doesn't have any special semantics for the instantiation expression inside Box::new()).
I've found Do values in return position always get allocated in the parents stack frame or receiving Box?. Regarding my specific question, it only proposes the experimental box syntax, but mostly talks about compiler optimizations (copy elision).
So my question remains: using stable Rust, how does one allocate structs directly on the heap, without relying on compiler optimizations?
As of Rust 1.39, there seems to be only one way in stable to allocate memory on the heap directly - by using std::alloc::alloc (note that the docs state that it is expected to be deprecated). It's reasonably unsafe.
Example:
#[derive(Debug)]
struct Test {
a: i64,
b: &'static str,
}
fn main() {
use std::alloc::{alloc, dealloc, Layout};
unsafe {
let layout = Layout::new::<Test>();
let ptr = alloc(layout) as *mut Test;
(*ptr).a = 42;
(*ptr).b = "testing";
let bx = Box::from_raw(ptr);
println!("{:?}", bx);
}
}
This approach is used in the unstable method Box::new_uninit.
It turns out there's even a crate for avoiding memcpy calls (among other things): copyless. This crate also uses an approach based on this.
You seem to be looking for the box_syntax feature, however as of Rust 1.39.0 it is not stable and only available with a nightly compiler. It also seems like this feature will not be stabilized any time soon, and might have a different design if it ever gets stabilized.
On a nightly compiler, you can write:
#![feature(box_syntax)]
struct Test { a: i32, b: i64 }
fn foo() -> Box<Test> {
box Test { a: 123, b: 456 }
}
Is there a way to allocate directly to the heap without box?
No. If there was, it wouldn't need a language change.
People tend to avoid this by using the unstable syntax indirectly, such as by using one of the standard containers which, in turn, uses it internally.
See also:
How to allocate arrays on the heap in Rust 1.0?
Is there any way to allocate a standard Rust array directly on the heap, skipping the stack entirely?
What does the box keyword do?
What is the <- symbol in Rust?
I recently had the same problem. Based on the answers here and other places, I wrote a simple function for heap allocation:
pub fn unsafe_allocate<T>() -> Box<T> {
let mut grid_box: Box<T>;
unsafe {
use std::alloc::{alloc, dealloc, Layout};
let layout = Layout::new::<T>();
let ptr = alloc(layout) as *mut T;
grid_box = Box::from_raw(ptr);
}
return grid_box;
}
This will create a region in memory automatically sized after T and unsafely convince Rust that that memory region is an actual T value. The memory may contain arbitrary data; you should not assume all values are 0.
Example use:
let mut triangles: Box<[Triangle; 100000]> = unsafe_allocate::<[Triangle; 100000]>();

Resources