Skip to content
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

Support atomic CAS on no-std pre-v6 ARM targets (e.g., thumbv4t-none-eabi) #26

Closed
taiki-e opened this issue Aug 8, 2022 · 4 comments · Fixed by #28
Closed

Support atomic CAS on no-std pre-v6 ARM targets (e.g., thumbv4t-none-eabi) #26

taiki-e opened this issue Aug 8, 2022 · 4 comments · Fixed by #28
Labels
C-enhancement Category: A new feature or an improvement for an existing one O-arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state

Comments

@taiki-e
Copy link
Owner

taiki-e commented Aug 8, 2022

Pre-v6 ARM targets (except for Linux) don't support atomic CAS.

As far as I know, there are several ways to support this:

@taiki-e taiki-e added C-enhancement Category: A new feature or an improvement for an existing one O-arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state labels Aug 8, 2022
@taiki-e taiki-e added the help wanted Extra attention is needed label Aug 8, 2022
@Lokathor
Copy link

Lokathor commented Aug 8, 2022

Speaking as the thumbv4t-none-eabi and armv4t-none-eabi maintainer:

  • the SWP spinlock is fundamentally broken logically in single core + interrupt situations. At any given moment, the lock is not held and you can just do whatever you want, or the lock is held but you'll never get it (because the person running can't execute while you do) so spinning will never complete. The only thing that really works is for interrupt handler code to be forced ("somehow") to use something like a try_lock method and immediately give up on failure (because, again, the main thread holds the lock and can't release it while the interrupt handler is running).
  • Interrupts can be turned off at the CPU level using CPSR but that's kinda touchy to mess with, and probably Rust shouldn't attempt to do that. Also, I don't think the standard library should ever automatically disable interrupts, but if it's for such a short period of time as a CAS then maybe it's okay. Also important: I'd have to look it up to be positive, but I'm 99% sure you can't mess with CPSR from User mode. And it's maybe unlikely that a program would bother to use User mode with no_std, but, they could, and then the CPSR disabling would break.
  • The atomic builtins can be implemented (probably weak linked) within the compiler-builtins crate, so that's probably a good plan for having a default impl which people can override if they need. Of course they would probably be implemented by disabling interrupts using CPSR.
  • 3rd party crates can always do whatever I guess.

@taiki-e
Copy link
Owner Author

taiki-e commented Aug 9, 2022

@Lokathor Thanks for your comment!

the SWP spinlock is fundamentally broken logically in single core + interrupt situations. At any given moment, the lock is not held and you can just do whatever you want, or the lock is held but you'll never get it (because the person running can't execute while you do) so spinning will never complete.

Oh, that's really bad... Thanks for the detailed explanation!

I don't think the standard library should ever automatically disable interrupts, but if it's for such a short period of time as a CAS then maybe it's okay.

This crate's interrupt disabling-based implementation will only1 be enabled if the end-user explicitly enables the unsafe cfg, so I think it's okay if we update the cfg documentation to make it clear that it disables interrupts.

Also important: I'd have to look it up to be positive, but I'm 99% sure you can't mess with CPSR from User mode. And it's maybe unlikely that a program would bother to use User mode with no_std, but, they could, and then the CPSR disabling would break.

Ah, that is indeed important. I think other targets have similar issues and we need to update the cfg documentation to mention it. (Since it requires explicitly enabling unsafe cfg anyway, I think it's okay as long as it's properly documented.)

The atomic builtins can be implemented (probably weak linked) within the compiler-builtins crate, so that's probably a good plan for having a default impl which people can override if they need.

Using a weak definition to provide a default implementation that can be overridden is a very interesting idea!

Footnotes

  1. Except for AVR which is definitely single core and LLVM also generates code to disable interrupts in atomic ops by default.

@taiki-e
Copy link
Owner Author

taiki-e commented Aug 9, 2022

Updated docs by 5759f3c, and opened #28 to support disabling interrupts.

(That said, I think the full fix to this problem would require either atomic builtins or third-party crate support.)

@taiki-e
Copy link
Owner Author

taiki-e commented Aug 15, 2022

(For atomic builtins, it is now tracked by #33)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-enhancement Category: A new feature or an improvement for an existing one O-arm Target: 32-bit Arm processors (armv6, armv7, thumb...), including 64-bit Arm in AArch32 state
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants