single producer, single consumer

I

Ian Collins

James said:
According to the standard, accessing through a const lvalue is
"observable behavior". The standard also says, however, that
what constitutes an access is implementation defined. Which
means that in practice, the only assumption you can make based
on the standard is that what constitutes an access will be
documented. Which is nice, but... it means that just about
anything you do which involves volatile is implementation
defined, and thus non-portable. (There's also the fact that
I've yet to find this documentation---required by the
standard---for any compiler, which means per se that none of the
compilers I'm familiar with are standard conform.)

In practice, the general rule with regards to volatile is that
the compiler turns off all optimization with regards to that one
access (and doesn't change any other accesses). Which is about
as useful on a modern machine as simply saying that volatile is
a no-op.

The key phrase, at least from the C specification is:

"An object that has volatile-qualified type may be modified in ways
unknown to the implementation or have other unknown side effects"

Which says a lot more than volatile is a no-op, at least for those of us
who write device drivers!
 
J

James Kanze

The key phrase, at least from the C specification is:
"An object that has volatile-qualified type may be modified in
ways unknown to the implementation or have other unknown side
effects"
Which says a lot more than volatile is a no-op, at least for
those of us who write device drivers!

Certainly, and while it's hard to read any formal, normative
meaning into that statement, it's certainly a very clear
statement of intent.

IIRC, it is presented as part of a statement of intent. But I
don't have any of my C documentation available at present to
check with. There's also a rule that accesses (reads and
writes) to volatile variables is observable behavior. But (at
least if my memory serves me correctly), it also says that what
constitutes an access is implementation defined. This has two
consequences:

-- The implementation is required to document it. As far as I
can tell, this means that I've never seen a conformant
implementation, since I've yet to be able to find such
documentation. (G++ does have a section §4.10 where it
claims to document "What constitutes an access to an object
that has volatile-qualified type". Regretfully, the couple
of paragraphs in the section manage to not say anything
concrete.)

-- Judging from the generated code, most compilers (well, g++,
Sun CC and the versions of VC++ that I'm using) define an
"access" as something along the lines of "having executed a
load or store instruction in the instruction stream". Given
modern processors, this definition is more or less useless,
and (at least IMHO) definitely violates the intention. (One
would expect "access" to be defined in terms of something
happening on the actual "object", e.g a read or write cycle
inmain memory or something similar.)

See, for example, §8.2 of the Sparc Architecture Manual, in
particular the fifth paragraph, "The value semantics of
operations on I/O locations are not defined by the memory
models, but the constraints on the order in which operations are
performed is the same as it would be if the I/O locations were
real memory", plus the "Compatibility Note" which follows
(non-normative, but explanitory of the above):

Operations to I/O locations are not guaranteed to be
sequentially consistent between themselves, as they are
in SPARC-V8. SPARC-V9 does not distinguish real memory
from I/O locations in terms of ordering. All references,
both to I/O locations and real memory, conform to the
memory model’s order constraints. References to I/O
locations may need to be interspersed with MEMBAR
instructions to guarantee the desired ordering. Loads
following stores to locations with side effects may
return unexpected results due to lookaside into the
processor’s store buffer, which may subsume the memory
transaction. This can be avoided by using a MEMBAR
#LookAside.

This means that it may not be possible to write a device driver
in pure C or C++, and be sure it works. Alternatively, the
hardware may do something to impose Total Store Order on
accesses to the memory mapped IO. This is only a problem with
the more relaxed models. There's even a hint at the end of §8.2
suggesting that hardware implementations treat addresses that
might be memory mapped IO using a sequentially consistent
model. So you really have to check the documentation of your
hardware, and maybe be prepared for the worst.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top