Reputation: 85
Does this usage of compare_exchange
produce defined behavior?
use std::sync::atomic::{AtomicPtr, Ordering};
struct Dummy {
foo: i64,
bar: i64,
}
fn main() {
let ptr = &mut Dummy { foo: 1, bar: 2 };
let some_ptr = AtomicPtr::new(ptr);
let other_ptr = &mut Dummy { foo: 10, bar: 10 };
let value = some_ptr.compare_exchange(ptr, other_ptr, Ordering::SeqCst, Ordering::Relaxed);
}
If it is defined, what is the defined behavior? Will Rust use double width CAS for the above operation on supported architectures like x86_64?
Upvotes: 0
Views: 1179
Reputation: 155226
Does this usage of
compare_exchange
produce defined behavior?
Barring a bug in the compiler or the standard library, safe Rust should never result in undefined behavior in the C and C++ sense. Additionally, creating and manipulating pointers is always safe, it's only dereferencing them or converting them to references that requires explicit unsafe
because the programmer needs to provide guarantees that the compiler cannot verify. Whether a particular call to a safe function does what you expect is another matter, of course.
If it is defined, what is the defined behavior?
The behavior is that specified by the documentation: the address some_ptr
points to is compared to the one ptr
points to and, if they match, some_ptr
is atomically updated to point to the address provided by other_ptr
. The previous pointer is returned in either case. Since your code initializes some_ptr
from ptr
and doesn't create a thread that could change it, it will result in some_ptr
pointing to the address provided by other_ptr
, and returning ptr
.
Will Rust use double width CAS for the above operation on supported architectures like x86_64?
AtomicPtr::compare_exchange()
only compares and swaps the pointer, which is as wide as usize
(64 bits on modern hardware) and there is no reason for double-width CAS.
But I think I understand how the confusion might have arisen: the docs of compare_exchange
speak of value of a pointer. This "value" is not the value of the pointed-to data, it's just the underlying *mut T
pointer, which only represents a memory address. Just like an AtomicBool
's value is bool
, an AtomicPtr
value is a pointer.
The docs would be slightly more precise if they spoke of the "address <x> points to" instead of "value of <x>", but that's more verbose. (The shorter "address of <pointer>" would again be ambiguous because it might be understood to refer to the address where the pointer itself is held.)
Upvotes: 2