This patch enables the <atomic> header on systems without thread support, such as for example ARMv7em baremetal targets.
It consists essentially of three changes:
- Do not blindly refuse <atomic> when _LIBCPP_HAS_NO_THREADS is defined. I removed corresponding #error at the top of <atomic>. Furthermore, I changed the logic in <__config> where _LIBCPP_HAS_NO_ATOMIC_HEADER is determined to ignore _LIBCPP_HAS_NO_THREADS.
- In <__config>, define _LIBCPP_ATOMIC_ONLY_USE_BUILTINS when _LIBCPP_HAS_NO_THREADS is defined (instead of just when _LIBCPP_FREESTANDING is defined), since there is no other way to implement <atomic> without thread support. Arguably, when building without thread support, one is effectively doing a freestanding compilation, so one could require the user to supply “-ffreestanding”. However, it seems that this is not usually done on the systems I work with. Furthermore, it is conceivable that one wants to build libc++ for a hosted platform that does not supports threads but still would want to have support for atomics.
- In memory.cpp, change #ifdef _LIBCPP_HAS_NO_ATOMIC_HEADER to #ifdef _LIBCPP_HAS_NO_THREADS. Since this ifdef protects against the use of threading primitives, the latter seems more correct, while the former leads to compilation errors with the new logic for _LIBCPP_HAS_NO_ATOMIC_HEADER. It seems to indicate that the implementation of <memory> uses threading primitives instead of atomics. Therefore, in standalone builds, where concurrency comes in the form of interrupts rather than threads, one has to be careful with the use of <memory>. If at some point libc++ on baremetal becomes officially supported, that issue should probably be documented somewhere.
Of course, so far my patch fails to provide tests for the issue, which I’m not sure how to proceed with. I have never run any of the LLVM tests myself, as this seems to be extra challenging for cross-builds for baremetal. I did manually test the built libc++ in a simple (“blinky”) project that uses hardware timer interrupts to trigger state changes, relying on <atomic> for synchronisation. It appears to work, contrary to the non-atomic version of it.