On 10/30/06, Colin <[EMAIL PROTECTED]> wrote:
Erm, memory barriers aren't things that need to be "acquired" and
"released"; think of them as synchronisation points. Reasoning about
just one CPU we could say that a memory barrier ensures that all
memory operations that, in the instruction stream, occur before the
barrier, are also actually performed before the barrier, and that no
memory operation that, in the instruction stream, occurs after the
barrier, is performed before the barrier (at least that's the case
for the most general two-way read-write-barrier).
An atomic write operation (to an appropriately sized object) therefore
simply means that a CPU, on the bus, actually performs the write in a
way that other CPUs can/must see it.
Similarly an atomic read does not acquire anything, it just must make
sure that the read operation actually takes place, and takes into
account any changes to the data that another CPU might have made.
Does this halfway explain why they are necessary?
On further thought: Perhaps you are mixing up memory barriers and the
"load-locked, store-conditional" pair of memory accesses?
According to the Solaris 10 manual, I'm not sure that your description
matches. AFAICT from just the manual, the membar_enter() function
blocks the system from doing any store/loads until membar_exit() is
called.
The membar_enter() function is a generic memory barrier used
during lock entry. It is placed after the memory operation
that acquires the lock to guarantee that the lock protects
its data. No stores from after the memory barrier will reach
visibility and no loads from after the barrier will be
resolved before the lock acquisition reaches global visibil-
ity.
The membar_exit() function is a generic memory barrier used
during lock exit. It is placed before the memory opera-
tion that releases the lock to guarantee that the lock pro-
tects its data. All loads and stores issued before the bar-
rier will be resolved before the subsequent lock update
reaches visibility.
The membar_enter() and membar_exit() functions are used
together to allow regions of code to be in relaxed store
order and then ensure that the load or store order is main-
tained at a higher level. They are useful in the implementa-
tion of mutex exclusion locks.
Now, if I look at the actual implementation of
membar_enter()/membar_exit() for Solaris, it becomes a bit clearer:
http://cvs.opensolaris.org/source/xref/on/usr/src/common/atomic/amd64/atomic.s
The both use 'mfence' on AMD64. The AMD x86-64 manual:
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf
'mfence' is on page 182 of Vol 3:
---
Acts as a barrier to force strong memory ordering (serialization)
between load and store instructions preceding the MFENCE, and load and
store instructions that follow the MFENCE. A weakly-ordered memory
system allows the hardware to reorder reads and writes between the
processor and memory. The MFENCE instruction guarantees that the
system completes all previous memory accesses before executing
subsequent accesses.
---
So, in response to my question about whether membar_enter() needs a
call to membar_exit(), the answer is apparently 'no.' membar_enter()
and membar_exit() have no real relationship to each other - it just
indicates when they should be invoked not that it actually does
anything. It seems that the folks at Sun just picked horrible names
for this API.
Thanks for clarifying.
So, if I run 'testatomic' it should just do everything I need in order
to test this, right? Or, should we shore up those tests too? If
'testatomic' is sufficient, I can test on Sparc and x86 later this
week if no one beats me to it.
Thanks. -- justin