-
Notifications
You must be signed in to change notification settings - Fork 288
Review and possibly deprecate all transactional memory intrinsics across architectures #1521
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
Comments
The rollback is a full state rollback to the point where the transaction started. This includes all memory accesses, register contents and the program counter. There is no observable difference compared to having the failed transaction never occurring in the first place. |
What happens if memory accesses were observed by other threads/processes? What happens if there was any kind of syscall? |
A syscall or context switch will immediately abort the transaction. The memory accesses can't be observed by other cpu cores afaik. I don't know if it will cause the reads from the other cpu cores to wait until the transaction has ended or if it will cause the transaction to abort though. |
Hm, maybe there's no problem then? I opened this based on @jacobbramley's comment here, but maybe I misunderstood the scope of this. |
Something that makes intrinsics worse than inline asm is that unless you follow very specific rules about what the transaction does (eg at most N memory accesses, no instructions outside this specific set, at most M total instructions), it is almost certainly going to be aborted by the cpu. |
I had completely missed that detail, sorry.
Arm TME has some restrictions, but none look ominous. If Rust does something that causes a transaction to fail, then control flow is reset back to the start, and users of TME have to implement a fallback anyway (e.g. with a mutex). Not all failure reasons can be address by simply retrying. This is all rather new to me, but the comments above suggest that this behaviour is likely to be similar to that in other architectures, too. |
Arm TME doesn't allow DSB barriers, which the compiler may emit. I am also very certain that the actual implementation inside arm cpu's puts a limit on the amount of buffered memory locations buffered by the transaction and exceeding this would result in an abort, likely constrained by the size and associativity of the L1 cache. On intel cpu's at least only 8 memory locations are guaranteed to be accessible on cpu's with 8 way associative L1 cache. I did expect up to 5 (store return value on stack, access return address and stack pointer to return from the block starting the transaction and push return address and stack pointer for the block ending the trabsaction) of these to be used up by the inline asm implementation in cg_clif, leaving only 3 for actual use, which in debug mode will more realistically be closer to 1 with the extra stack copies rustc inserts in the MIR it generates. |
I wouldn't expect the compiler to routinely emit a
... which is not ideal, but not incorrect. You get a similar effect if you hit one of the implementation-defined limits on buffered memory, etc. We rely on the user implementing a suitable fallback, but they're supposed to do that anyway. |
Okay so looks like there's not a problem here, at least not a safety / correctness issue. Closing the issue. |
Transactional memory intrinsics might affect the behavior of other instructions in ways that is incompatible with Rust being able to generate its own code properly: if a transactional memory "rollback" un-does some write to a stack variable Rust did, then things can start to go wrong in arbitrary ways.
We should probably deprecate all transactional memory intrinsics across architectures, similar to FP environment access. I don't know which architectures even have such intrinsics.
The text was updated successfully, but these errors were encountered: