Defines ACCESS_ONCE(x) macro (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 4 May 2013 06:41:57 +0000 (23:41 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 4 May 2013 06:41:57 +0000 (23:41 -0700)
This forces a one-time read of the value x.   I've been meaning to do
this for a while - we have a lot of synchronization code that assumes
that data is only loaded once, at a specific point in time.  Eventually
I'll go through older code and start using this.

Check out http://lwn.net/Articles/508991/ for more info.

This will also help with code that wants to force a read-in (say, from
global state to thread state) for performance reasons.

Keep in mind that we continue to need memory barriers, like the wmb(),
wrmb(), etc, since this has nothing to do with the processor's ordering
of operations, and also has nothing to do with writing values.

This is fairly similar to a cmb(), in that both tell the compiler that
memory values may have changed.  One slight difference is that a cmb()
(and rmb/wmb on x86) involves an asm volatile, which should prevent the
compiler from reordering the accesses (I think!).  AFAIK, the compiler
could reorder:

local_x = ACCESS_ONCE(x);
local_y = ACCESS_ONCE(y);

and if it is important to actually read x before y, then you want to do:

local_x = ACCESS_ONCE(x);
rmb(); /* on x86, this is just an asm volatile("" ::: "memory") */
local_y = ACCESS_ONCE(y);

The rmb() orders the x and y reads, and the ACCESS_ONCE prevents the
compiler from trying to read in x in the future when using local_x.

Finally, note that any use of an rwmb() (where we want to enforce the
read happens before the write) will probably want to use an ACCESS_ONCE,
unless we are okay with reading the value again after the write.

Reinstall your kernel header.

kern/include/ros/common.h

index 6670875..3540d05 100644 (file)
@@ -115,6 +115,10 @@ static inline bool mult_will_overflow_u64(uint64_t a, uint64_t b)
        (type*)((char*)ptr - offsetof(type, member));                             \
 })
 
+/* Force the reading exactly once of x.  You may still need mbs().  See
+ * http://lwn.net/Articles/508991/ for more info. */
+#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+
 // Ivy currently can only handle 63 bits (OCaml thing), so use this to make
 // a uint64_t programatically
 #define UINT64(upper, lower) ( (((uint64_t)(upper)) << 32) | (lower) )