|
|
Log in / Subscribe / Register

volatile

volatile

Posted Oct 4, 2021 18:50 UTC (Mon) by tialaramex (subscriber, #21167)
Parent article: McKenney: So You Want to Rust the Linux Kernel?

So, Rust actually ships, today, what you'd actually want, a pair of generic intrinsics for volatile reads and writes. Provide a suitably aligned pointer and you can read, or write, any implemented data type. Rust promises this read (or write) doesn't tear and won't get re-ordered, duplicated, optimised out etc. since performing the read (or write) has side effects invisible to the compiler (except that ZSTs can be elided because, fancy as MMIO is, reading or writing *nothing* does not have side effects). On most systems, of course, the intrinsic evaluates to a single machine code instruction.

This is roughly what Paul and co. have asked for in P1382R1 for C++ which makes sense because, as I said, it's what you'd actually want.

But what jumps out at me is that although Rust provides this intrinsic, which is exactly what you'd want here, Paul apparently proposes that what Rust ought to do instead is wrap the Linux kernel features that try to coerce a C compiler into doing what you want despite the C language standard not promising anything useful. Why? Is it because Paul didn't know these intrinsics already exist?


to post comments

volatile

Posted Oct 4, 2021 19:52 UTC (Mon) by PaulMcKenney (✭ supporter ✭, #9624) [Link] (4 responses)

It is because some architectures' implementations of Linux-kernel READ_ONCE() and WRITE_ONCE() are required to do more than just a volatile access, and in some cases this "more" is controlled by a Linux-kernel Kconfig option. Yes, you could duplicate this logic in Rust code, but it might be simpler to just rely on the existing LInux-kernel code, especially to begin with.

Developer's and maintainer's choice, though! ;-)

volatile

Posted Oct 7, 2021 10:45 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (3 responses)

Can you say a bit more, or a bit more concretely, than "some architectures" and "some cases" where this cheap-looking feature might actually be arbitrarily more complicated and need wrapping?

volatile

Posted Oct 7, 2021 16:06 UTC (Thu) by PaulMcKenney (✭ supporter ✭, #9624) [Link] (2 responses)

DEC Alpha needs a full memory-barrier instruction after the load emitted by READ_ONCE().

Itanium needs a READ_ONCE() to emit an acquire-load instruction and a WRITE_ONCE() to emit a store-release instruction, but the C compiler takes care of that for us. Plus it is not obvious that Rust would ever need to care about this particular case.

ARMv8 needs a READ_ONCE() to emit an acquire-load instruction, but only in kernel builds that enable LTO, that is, builds that have CONFIG_LTO or similar enabled. (This choice stems from concerns that LTO breaks address, data, and/or control dependencies.)

So not massively complex, but something that needs to be kept track of.

volatile

Posted Oct 8, 2021 19:24 UTC (Fri) by tialaramex (subscriber, #21167) [Link] (1 responses)

So, if I'm not misunderstanding you need acquire-release semantics (you don't need to ask for them on x86 because x86 always has acquire-release semantics), that's what all of these cases seem to be doing.

Because x86 doesn't care, I don't actually know and it wouldn't surprise me if the existing volatile intrinsics already have acquire-release on every platform. But even if not it does still feel like this makes more sense as a (new) intrinsic than trying to call into C every time.

volatile

Posted Oct 8, 2021 20:09 UTC (Fri) by PaulMcKenney (✭ supporter ✭, #9624) [Link]

Why not take a look at the actual Rust documentation and implementation to see what the Rust volatile intrinsics actually guarantee across architectures?


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds