Abishek0398
Abishek0398

Reputation: 85

What is the behavior of AtomicPtr::compare_exchange when used on a pointer to a struct?

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

Answers (1)

user4815162342
user4815162342

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

Related Questions