

The ACCESS_ONCE() macro (2012) - gaoprea
http://lwn.net/Articles/508991/

======
kazinator
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.

~~~
rdc12
"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

~~~
kazinator
But, say:

    
    
       for (;;) {
          /* ... */
          if (pthread_once(&once_var, once_routine))
            /* error */;
          /* ... */
       }
    

Here, we are ensuring that once_routine is called exactly once.

ACCESS_ONCE to me strongly suggests that the value is accessed once and cached
forever. E.g. ACCESS_ONCE(x) could expand to something like:

    
    
        ({
          static __flag;
          static typeof(x) __cached;
          if (!__flag) {
            __cached = (x);
            __flag = 1;
          }
          __cached;
        })
    

ANSI Common Lisp has load-time-value. You can use this anywhere:

    
    
       (defun myfunc ()
         (let ((foo (bar))
            ... ;; deeply nested
            (let ((x (load-time-value (whatever))))
              ...))))
    

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.

------
cperciva
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.

~~~
cnvogel
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).

~~~
cperciva
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.

~~~
cnvogel
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.

~~~
cperciva
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.)

