-
Notifications
You must be signed in to change notification settings - Fork 59
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
How can we allow read-read races between atomic and non-atomic accesses? #483
Comments
The PTX memory model allows these races. The fact that these races are not allowed in C++, is not due to the C++ memory model, but due to pre-conditions in the C++ atomic and atomic_ref abstractions. These preconditions are there to enable the implementation to fake atomic memory operations using locks. A lower-level software-exposure for these operations that guarantees "either lock-freedom or fails (to compile or at runtime)" would not need this limitation. |
Rollup merge of rust-lang#128778 - RalfJung:atomic-read-read-races, r=Mark-Simulacrum atomics: allow atomic and non-atomic reads to race We currently define our atomics in terms of C++ `atomic_ref`. That has the unfortunate side-effect of making it UB for an atomic and a non-atomic read to race (concretely, [this code](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d1a743774e60923db33def7fe314d754) has UB). There's really no good reason for this, all the academic models of the C++ memory model I am aware of allow this -- C++ just disallows this because of their insistence on an "object model" with typed memory, where `atomic_ref` temporarily creates an "atomic object" that may not be accesses via regular non-atomic operations. So instead of tying our operations to `atomic_ref`, let us tie them directly to the underlying C++ memory model. I am not sure what is the best way to phrase this, so here's a first attempt. We also carve out an exception from the "no mixed-size atomic accesses" rule to permit mixed-size atomic reads -- given that we permit mixed-size non-atomic reads, it seems odd that this would be disallowed for atomic reads. However, when an atomic write races with any other atomic operation, they must use the same size. With this change, it is finally the case that every non-atomic access can be replaced by an atomic access without introducing UB. Cc `@rust-lang/opsem` `@chorman0773` `@m-ou-se` `@WaffleLapkin` `@Amanieu` Fixes rust-lang/unsafe-code-guidelines#483
…ulacrum atomics: allow atomic and non-atomic reads to race We currently define our atomics in terms of C++ `atomic_ref`. That has the unfortunate side-effect of making it UB for an atomic and a non-atomic read to race (concretely, [this code](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d1a743774e60923db33def7fe314d754) has UB). There's really no good reason for this, all the academic models of the C++ memory model I am aware of allow this -- C++ just disallows this because of their insistence on an "object model" with typed memory, where `atomic_ref` temporarily creates an "atomic object" that may not be accesses via regular non-atomic operations. So instead of tying our operations to `atomic_ref`, let us tie them directly to the underlying C++ memory model. I am not sure what is the best way to phrase this, so here's a first attempt. We also carve out an exception from the "no mixed-size atomic accesses" rule to permit mixed-size atomic reads -- given that we permit mixed-size non-atomic reads, it seems odd that this would be disallowed for atomic reads. However, when an atomic write races with any other atomic operation, they must use the same size. With this change, it is finally the case that every non-atomic access can be replaced by an atomic access without introducing UB. Cc `@rust-lang/opsem` `@chorman0773` `@m-ou-se` `@WaffleLapkin` `@Amanieu` Fixes rust-lang/unsafe-code-guidelines#483
Currently, we document read-read races where one access is atomic and one is not to be UB. This is born out of the fact that one cannot write code in C++ that has such a race: if one creates an atomic_ref so perform atomic accesses to an object previously used non-atomically, then for as long as the atomic_ref exists, one may not use non-atomic accesses at all.
However, this is a very unfortunate limitation. First of all it means replacing a non-atomic access by an atomic one can actually introduce UB (even if there are no alignment issues), which is silly. Secondly it defies intuition. I do think we should allow such code. However, then we have to change the way we document our atomics; specifically, this part:
My hope is that we can still use the C++ memory model, but instead of documenting which C++ library functions our Rust operations correspond to, we "link directly with the memory model" in the sense of documenting that certain Rust operations correspond to certain operations directly in the C++ model (reads/writes/RMWs). I'll have to look more closely at how the C++ standard documents the memory model to understand how this could be done; so far I've only read the CS papers that formalize this model. ;)
The text was updated successfully, but these errors were encountered: