Adding stuff to a particular existing crate? #63231

Well simply put - monkey patching code. Oh boy, I can feel the raised eyebrows already.

I am working on an embedded project. Worked on Cortex-M3 until now (thumbv7v-m), and recently switched to Cortex-M (thumbv6-m), and all hell broke lose.

The main issue is that the instruction set for the M0 does not contain ldrex / strex , so atomics cannot be implemented in a general case. This results in AtomicUSize and the like not being implemented which results in sync being left out of the alloc crate. Which results in a bunch of nasty stuff, such as missing Arc and Weak , without which it is extremely difficult to share stuff between multiple threads when running above say FreeRTOS .

But there are a lot of other crates that would normally work, but won't compile because they are using Arc or Weak .

The atomics CAN be implemented in most cases by disabling interrupts (if allowed by the processor state) for the duration of the operation, and taking EXTRA care in the non maskable interrupts. Neither that the processor allows interrupts to be disabled nor that no atomics are accessed from the NMI can be verified by the compiler, but in many if not most cases holds true. And even if the processor state doesn't allow interrupts to be disabled the functionality could be implemented using a syscall (yeah that's slow - but it will help putting the processor in a state where it can disable interrupts).

This means that I could supply an implementation of atomics that I KNOW that works in my particular use-case, I am aware of it's drawbacks, and I accept them. Issue a few fat warnings for whoever works on the project after myself, and SHOULD be able to use Arc and Weak , and anything else that depends on atomic operations.

But that would mean I would need to create the implementation of atomics inside the core crate and allow the alloc crate to inlcude the alloc::sync module, which I cannot do.

Alternatively I can write my own hackyatomics::alloc::sync module, which would simply pub use the alloc::sync on targets that support it, and use my hacky way otherwise, but that means that every dependency would need to be changed to use hackyatomics::alloc::sync::Arc instead of alloc::sync::Arc in all cases. Which is a PIA.

So. The question: Is there a way to basically monkey-patch a module into another crate? This is probably not the best solution for the use-case above, but is this something that would be worth having a discussion about? Obviously this would be restricted to binary crates (only binary crates would be allowed to define overrides / monkey-patches, otherwise all hell would brake loose. But binary crates are leaf crates, and if you do something stupid, only your own code will stop compiling, and you KNOW you did something that could end up doing that sooner or later. (Exactly the reason why I think orphan rules should be relaxed for binary crates, but that's another discussion).

2 Likes

You could try using a custom target json and setting atomic-cas to true and max-atomic-width to whatever you want to support. Then implement the necessary library functions that LLVM will emit when an atomic operation is needed. You can use this file in compiler-builtins as a base to see how it can be done.

How can a custom target json be defined and used? seems like xargo is now in maintenance mode, what is the alternative for it?

xargo still works fine.