Change:
cpu: "generic-rv32".into(), // While the RiscV32IMC architecture does not natively support atomics, ESP-IDF does support <del> // the __atomic* and __sync* GCC builtins, so setting `max_atomic_width` to `Some(64)` </del> <ins> // the __atomic* and __sync* GCC builtins, so setting `max_atomic_width` to `Some(32)` </ins> // and `atomic_cas` to `true` will cause the compiler to emit libcalls to these builtins. // // Support for atomics is necessary for the Rust STD library, which is supported by the ESP-IDF framework. <del> max_atomic_width: Some(64), </del> <ins> max_atomic_width: Some(32), </ins> atomic_cas: true, features: "+m,+c".into(),

Discussion:
maxatomicwidth of these targets is currently set to 64 However, as mentioned in , esp-idf's 64-bit atomic builtins use global spinlocks on multi-core systems: And it violates what the standard library is intended to guarantee. Since riscv32 does not have 64-bit atomic instructions, I do not believe there is any way to fix this problem other than setting maxatomic_width of these targets to 32. cc (mentioned because you both are ) label +A-atomic +I-unsound
WG-prioritization assigning priority (). label -I-prioritize +P-low
Sorry to revive this old issue. At the time I just trusted your judgement when you removed the implementation from the as my understanding of this subject mater was (and still is) limited. The problem is, we now we have - and - without diving into the details of the new issue just yet - we (or I) really need to understand what exactly a "lock-free" atomic does mean and how exactly an atomic that is allowed to "wait" is different_ from a "lockful" atomic (all atomics in are allowed to wait but are NOT allowed to use locks as per ). To give you a concrete example where I struggle: for the target, you removed the support for on the basis that it uses a global spinlock (in the presence of multiple cores). But why did you consider this spinlock a "lock" and not a "wait" (as per the terminology of the documentation from above)? Because this spinlock (oversimplifying a bit here) is nothing else than a . A "wait", if you wish. The spinlock implementation is essentially (in pseudocode): So why is the above ^^^ a "lock" and not just a "wait"? And could you give an example of a "wait" which is not a "lock"?
To quote wikipedia Your would starve all threads if any thread that calls it permanently gets stopped while the lock on is held. CPU's generally have NMI's which bypass , so if the NMI handler gets stuck (which it is allowed to, eg because it depends on itself) or NMI's are triggered back to back without any instruction executing in between, has no effect at all on the lock-freedom.

A lock-free but non-wait-free implementation allows some threads get stuck, but still requires that at least one thread can continue at some point. Only a non-lock-free implementation is allowed to have all threads that attempt to perform atomic operations to get permanently stuck.
So are you saying that In the presence of NMI the above code is NOT lock free However in the absence of NMI, the above code would be lock free? (it is another topic if we can guarantee the absence of NMI or its weaker variant - that the NMI code never touches )?
As for Wouldn't that mean the whole "user-space" (non-interrupt code) = all threads would starve, and nothing would make progress anyway. Including threads that utilize native atomics only. Asking, because I don't see how that particular example (NMIs firing back to back) applies here, as it would (obviously?) starve absolutely everything else, hardware atomics or not?
I think it would be assuming that the underlying CPU core ensures that it will always keep making forward progress itself. So for example another core must not be able to shutdown any core that has held. Even an NMI handler which immediately returns would make it non-lock-free if there is a possibility that NMI's arrive back to back. If however the CPU guarantees to execute at least one instruction between returning from an NMI and calling the NMI handler again (eg because the only source of NMI's is a watchdog timer and the NMI handler is fast enough), then it should be fine when the NMI handler doesn't touch . With lock-free atomics if you suspend all userspace threads except for one, that one thread will always be able to make forward progress with regards to executing atomic operations. In case of a non-lock-free implementation it is possible that it blocks forever waiting on one of the suspended threads releasing the lock.
I think I might understand it a bit now. If you could confirm my two examples/statements below that would be greatly appreciated (thank you for bearing with me!

): why spinlock+disable-all-interrupts-except-nmi is not lock free in the presence of any NMI: Two cores, core0 and core1 Two threads, thread0 - pinned to core0, and thread1 - pinned to core1, both currently inside , but thread0 also got the "lock" and is in the midst of mutating , while thread1 still busyloops on the spinlock Suddenly thread0 gets suspended while still mutating because core0 suddenly receives a storm of never-ending empty NMIs and therefore thread0 cannot progress that's OK, because it is "suspended" by the NMI storm thread1 - unfortunately - cannot progress either, as it is stuck in the spinlock busy-loop - waiting on thread0, which is suspended forever because of the never-ending NMI storm =that's NOT OK, because thread1 is not suspended (because the NMI storm happens on the other core) - yet - it cannot make any progress a simple "disable-all-interrupts-except-NMI" implementation of software atomics (obviously without a spinlock as it is a single core) on single core systems is lock-free: Because - even though a thread might be in the midst of modifying the value of such a software atomic when interrupted by an avalanche of never-ending NMIs, by your definition, this thread (as well as all others on the single-core system) are "suspended" (by the NMI avalanche). So these not making progress is actually fine and the algorithms still qualifies as lock-free. Note also that the condition that the NMI handlers should not touch such software atomics is a MUST for this case (2), or else such a software implementation would of course be unsound. It is a must for the "lockful" implementation in case (1) from above as well, but for other reason (the NMI might deadlock).
Both examples are correct afaik.