Add SyncUnsafeCell. by m-ou-se · Pull Request #95438 · rust-lang/rust (original) (raw)

(Edited to provide full context)

I've found myself needing something like SyncUnsafeCell when working with hardware.

In the Atmel SAME70 microcontroller, the hardware uses DMA (direct memory access) in order to send and receive ethernet frames. In order to do that (messy PoC code here), the process looks (roughly) like this:

In this case, the Buffer Descriptors act as the synchronization mechanism between the hardware and software. It is common in embedded rust to consider the hardware as a "separate thread", as it often executes asynchronously from the main software, in this case receiving and sending ethernet frames.

Additionally, it is considered "safest" to use static memory buffers when interacting with DMA, as memory on the stack can suffer from the same kind of "liveness" issues as you have with sharing stack data to multiple threads (basically: if you forget to 'turn off' the DMA before leaving the relevant stack frame: oops! memory corruption!).

For both the Buffer Descriptors and the Buffers themselves, they need to be UnsafeCells as the hardware can change the contents of either without interaction from the software. However, this means that I want both a static (for DMA stability/safety), as well as UnsafeCell (for correct behavior in the presence of multiple "thread" r/w access).

Safety is guaranteed by using a certain bit in the buffer descriptor in order to denote "ownership" of a given buffer. For example, when receiving frames:

This is (admittedly) a long-winded example of the same situation/use-case that @m-ou-se described, using an atomicbool/bit to synchronize access, but this is a decently common pattern in the embedded world, and leads to a swath of unsafe impl {Sync|Send} definitions, which I think would better communicate intent with a dedicated SyncUnsafeCell type.