It has a confusing name, suggesting that it is intended to prevent multiple accesses. (Contrast with `pthread_once` for instance: a mechanism for once-only initialization.)
In fact, the very example given in the article shows that without the ACCESS_ONCE, the compiler moved the access outside of the loop---thereby ensuring that it's accessed just once, ironically!!! Whereas by using ACCESS_ONCE, we ensure that it's accessed as many times as the loop is iterated, not only once.
Basically this just does some kind of volatile access, and so the name should reflect that:
foo = VOLATILE_READ(bar);
Then the number of times it is accessed is implied from the agreement between abstract and actual semantics. In the abstract semantics, and expression is evaluated once for each invocation of whatever encloses it. If an expression is unconditionally evaluated in a loop that iterates 100 times, then it is evaluated 100 times. Hoisting it out of the loop would be an optimization which is forbidden by agreement with the abstract semantics.
"In fact, the very example given in the article shows that without the ACCESS_ONCE, the compiler moved the access outside of the loop---thereby ensuring that it's accessed just once, ironically!!! Whereas by using ACCESS_ONCE, we ensure that it's accessed as many times as the loop is iterated, not only once."
But that is just a consequence of putting a call to ACCESS_ONCE inside a loop. But it is retaining the property that it is only read from memory once per iteration.
It would be way more confusing if the programmer only wanted read once for the whole loop and still put the statement inside the loop.
I do think that knowing that it is being called in a loop context, implies that it should only be accessed once per iteration
The load-time-value form is evaluated when the module is loaded and the value is stashed. Then whenever myfunc is called and that code is evaluated, the previously stashed value is retrieved; the (whatever) is not evaluated any more.
The silly thing here is that this macro is not guaranteed to accomplish anything. The C standard limits how compilers can optimize accesses to volatile objects, but says nothing about accesses to non-volatile objects which are accessed via volatile-qualified pointers.
That's certainly true if you mix accesses to the same object via volatile and non-volatile pointers. It's even explicitly undefined in the standard. (C99 §6.7.3/5). [while in practice it will work most of the time]
But if you always access a certain object through casts to ((volatile )&x), I don't see how this should be different than accesses to a globally declared "volatile x" variable, as pointers are guaranteed to not change if casted hence-and-forth (§6.3.2.3/7).
The key text is in C99 §6.7.4: "An object that has volatile-qualified type...". Note that this does not say "An object accessed via a pointer to a volatile-qualified type": What matters is the type of the underlying object, i.e., how it is originally defined.
Ok, that's quite some language-lawyering going on here ;-), and while I enjoy it, I'm completely aware of the fact that in practice the behavior of actual implementation (in software, compilers, operating systems) always trumps theoretic considerations.
That being said...
§6.5.3.1/4 The unary * operator denotes indirection. (...) the result is an lvalue designating the object.
So, I believe that there will be no difference in access to something declared as
volatile X v;
v = ...;
and
X v;
*((volatile X*)&v) = ...;
if the access to v will always be performed through such a cast, as ((volatile..)) will always denote the same "volatile" X object stored in v, independent of the fact that storage to the volatile X object is allocated in a "nonvolatile" X object.
In practice most compilers respect the volatile keyword on a pointer target type. But if you want to conform to the standard you need to look at what the standard says, not merely how it's commonly implemented.
§6.5.3.1/4 The unary * operator denotes indirection.
(...) the result is an lvalue designating the object.
Yes, but calling the sky green doesn't make it so. Dereferencing a pointer to an object yields that object, and the object is volatile or not depending on whether it was declared as volatile; whether you say that it's volatile before you dereference the pointer is irrelevant. (That is, irrelevant to the requirements of the standard; it's very relevant to most compilers, because it's usually impossible to prove whether the object ultimately being accessed is volatile or not.)
It is not in the C standard but the way GCC implements it is that it is hands-off with optimizations to any volatile variables and pointers. And since Linux is only compiled with GCC, it works.
People porting to llvm and icc have to do whatever it takes so that all the gadgets defined by the kernel work in those compilers as expected.
ISO C standard conformance isn't entirely irrelevant, but thereabouts.
There is no such thing as building systems from the ground up without controlling compilers beyond what is specified in the applicable language standards.
In fact, the very example given in the article shows that without the ACCESS_ONCE, the compiler moved the access outside of the loop---thereby ensuring that it's accessed just once, ironically!!! Whereas by using ACCESS_ONCE, we ensure that it's accessed as many times as the loop is iterated, not only once.
Basically this just does some kind of volatile access, and so the name should reflect that:
Then the number of times it is accessed is implied from the agreement between abstract and actual semantics. In the abstract semantics, and expression is evaluated once for each invocation of whatever encloses it. If an expression is unconditionally evaluated in a loop that iterates 100 times, then it is evaluated 100 times. Hoisting it out of the loop would be an optimization which is forbidden by agreement with the abstract semantics.