-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Add missing atomic operations to AtomicPtr #71004
Conversation
r? @shepmaster (rust_highfive has picked a reviewer for you, use r? to override) |
This adds various `fetch_` methods to `AtomicPtr` that are present on other `Atomic*` types. It does so such that libraries that depend on atomic operations on pointers do not have to cast those pointers to `usize` and fiddle around with `AtomicUsize` instead. Note that this patch currently implements `fetch_add` and `fetch_sub` without considering the size of the pointer target. This is unlike regular pointer additions and subtractions. The rationale for this is that for atomic operations, the user may indeed wish to truly increment by 1, which is difficult if all deltas are interpreted in increments of the type's size. This patch effectively resurrects the change from rust-lang#10154. Based on rust-lang#12949 (comment), the rationale for not making the changes at the time no longer hold.
cc @RalfJung |
Honestly I don't think this really helps for crossbeam-rs/crossbeam#464. And it seems rather inconsistent to have |
Yeah, adding these is more to allow libraries that need atomic ops on pointers not have to use |
Reassigning as this is above my paygrade... r? @sfackler |
Maybe. OTOH, these cannot actually be implemented without internally casting to |
Hmm, yeah, that's a good point. I honestly don't know what the "right thing" to do here is. It seems weird to force users to turn pointers into numbers to add to them atomically, but maybe it does make sense to force them to do it to do things like XORs? It's a strange line to draw though I think. One question that comes to mind for me here is whether there is an advantage to rustc to know that a bitwise XOR/AND/OR is happening specifically to a pointer. If we make the user do the cast, then the compiler sort of loses insight into that fact, whereas if we do the cast internally, then at least we know that's what's going on. I don't know if that buys us anything, at least at the moment, but keeping that internally in the compiler seems like it gives the compiler strictly more information? |
Well, it could. But I currently don't see anything we could do with that information, amongst the various proposals for int-ptr-cast semantics that I have seen or worked on (excluding the clearly insane ones...). |
I guess the question then is whether we then continue to keep the conversion explicit, or whether we make the APIs ready for some such improvement potentially coming down the line, to try and pre-emptively make people use the "more semantically rich" API. |
Ping from Triage: Any update on this or movement offline, @jonhoo? |
I think |
I don't think Xor, BitAnd etc on pointers are meaningful, they basically can only be explained via "cast to integer, do thing, cast back". For add and sub, I agree these could be meaningful. I am not sure what the motivation for adding them is, though -- what is the problem this is solving? This got triggered by Miri having issues with leak detecting when atomic operations are performed on pointers (rust-lang/miri#1350), but the PR doesn't really help much with that. It would have to replace some more ptr <-> int casts by transmutes (#70765), which is sketchy at best. Ideally LLVM would provide atomic operations on pointers directly so we wouldn't have to hack around the lack of that in Rust. Besides, the fact that they work in bytes when usually our pointer arithmetic works in units of |
I would say that adding these methods is not to explicitly address a problem, but rather to remove a restriction wherein users currently have to cast pointers to usize in order to perform atomic operations on them. The underlying hope being that this introduces additional semantic information that may be useful later. |
|
||
/// Adds to the current pointer, returning the previous pointer. | ||
/// | ||
/// Unlike other pointer additions, `fetch_add` increments directly by the provided value, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would this divergence from normal pointers be preferable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry, I wrote this in the PR/commit, but not in the docs:
The rationale for this is that for atomic operations, the user may indeed wish to truly increment by 1, which is difficult if all deltas are interpreted in increments of the type's size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would a user of a pointer-that-is-atomic want to increment by 1 and a user of a pointer-that-is-not-atomic not want to increment by 1?
#[cfg(target_has_atomic = "ptr")] | ||
#[unstable(feature = "atomic_ptr_fetch_op", issue = "none")] | ||
pub fn fetch_add(&self, val: usize, order: Ordering) -> *mut T { | ||
// SAFETY: data races are prevented by atomic intrinsics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to have anything to do with the actual sources of unsafety in the block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that safety comment mirrors that of the other atomic ops, and reflects the reason the atomic_add
unsafety is safe. Are you referring to the additional unsafety in transmuting from a usize
to a *mut T
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unsafe calls in that block are 1. transmuting, and 2. calling the unsafe intrinsic that takes a raw pointer.
I'd expect the semantics of this to match those of raw pointers, i.e. If you want to add/sub bytes, the name should call that out, (e.g. In general I'm not convinced that this feature has many use-cases. |
Okay, it sounds like the building consensus is that this feature is probably not useful or helpful in the near future, and raises more questions than it answers, so I'm going to go ahead and close this. We can always resurrect it should things change down the road. Thanks for the feedback! |
This adds various
fetch_
methods toAtomicPtr
that are present onother
Atomic*
types. It does so such that libraries that depend onatomic operations on pointers do not have to cast those pointers to
usize
and fiddle around withAtomicUsize
instead.Note that this patch currently implements
fetch_add
andfetch_sub
without considering the size of the pointer target. This is unlike
regular pointer additions and subtractions. The rationale for this is
that for atomic operations, the user may indeed wish to truly increment
by 1, which is difficult if all deltas are interpreted in increments of
the type's size.
This patch effectively resurrects the change from #10154. Based on
#12949 (comment),
the rationale for not making the changes at the time no longer hold.