2007-05-11 17:36:48

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH] "volatile considered harmful", take 3

Here's another version of the volatile document. Once again, I've tried
to address all of the comments. There haven't really been any recent
comments addressing the correctness of the document; people have been
more concerned with how it's expressed. I'm glad to see files in
Documentation/ held to a high standard of writing, but, unless somebody
has a factual issue this time around I would like to declare Mission
Accomplished and move on.

Thanks,

jon

---

Encourage developers to avoid the volatile type class in kernel code.

Signed-off-by: Jonathan Corbet <[email protected]>

diff --git a/Documentation/volatile-considered-harmful.txt b/Documentation/volatile-considered-harmful.txt
new file mode 100644
index 0000000..955c309
--- /dev/null
+++ b/Documentation/volatile-considered-harmful.txt
@@ -0,0 +1,119 @@
+Why the "volatile" type class should not be used
+------------------------------------------------
+
+C programmers have often taken volatile to mean that the variable could be
+changed outside of the current thread of execution; as a result, they are
+sometimes tempted to use it in kernel code when shared data structures are
+being used. In other words, they have been known to treat volatile types
+as a sort of easy atomic variable, which they are not. The use of volatile in
+kernel code is almost never correct; this document describes why.
+
+The key point to understand with regard to volatile is that its purpose is
+to suppress optimization, which is almost never what one really wants to
+do. In the kernel, one must protect shared data structures against
+unwanted concurrent access, which is very much a different task. The
+process of protecting against unwanted concurrency will also avoid almost
+all optimization-related problems in a more efficient way.
+
+Like volatile, the kernel primitives which make concurrent access to data
+safe (spinlocks, mutexes, memory barriers, etc.) are designed to prevent
+unwanted optimization. If they are being used properly, there will be no
+need to use volatile as well. If volatile is still necessary, there is
+almost certainly a bug in the code somewhere. In properly-written kernel
+code, volatile can only serve to slow things down.
+
+Consider a typical block of kernel code:
+
+ spin_lock(&the_lock);
+ do_something_on(&shared_data);
+ do_something_else_with(&shared_data);
+ spin_unlock(&the_lock);
+
+If all the code follows the locking rules, the value of shared_data cannot
+change unexpectedly while the_lock is held. Any other code which might
+want to play with that data will be waiting on the lock. The spinlock
+primitives act as memory barriers - they are explicitly written to do so -
+meaning that data accesses will not be optimized across them. So the
+compiler might think it knows what will be in shared_data, but the
+spin_lock() call, since it acts as a memory barrier, will force it to
+forget anything it knows. There will be no optimization problems with
+accesses to that data.
+
+If shared_data were declared volatile, the locking would still be
+necessary. But the compiler would also be prevented from optimizing access
+to shared_data _within_ the critical section, when we know that nobody else
+can be working with it. While the lock is held, shared_data is not
+volatile. When dealing with shared data, proper locking makes volatile
+unnecessary - and potentially harmful.
+
+The volatile storage class was originally meant for memory-mapped I/O
+registers. Within the kernel, register accesses, too, should be protected
+by locks, but one also does not want the compiler "optimizing" register
+accesses within a critical section. But, within the kernel, I/O memory
+accesses are always done through accessor functions; accessing I/O memory
+directly through pointers is frowned upon and does not work on all
+architectures. Those accessors are written to prevent unwanted
+optimization, so, once again, volatile is unnecessary.
+
+Another situation where one might be tempted to use volatile is
+when the processor is busy-waiting on the value of a variable. The right
+way to perform a busy wait is:
+
+ while (my_variable != what_i_want)
+ cpu_relax();
+
+The cpu_relax() call can lower CPU power consumption or yield to a
+hyperthreaded twin processor; it also happens to serve as a memory barrier,
+so, once again, volatile is unnecessary. Of course, busy-waiting is
+generally an anti-social act to begin with.
+
+There are still a few rare situations where volatile makes sense in the
+kernel:
+
+ - The above-mentioned accessor functions might use volatile on
+ architectures where direct I/O memory access does work. Essentially,
+ each accessor call becomes a little critical section on its own and
+ ensures that the access happens as expected by the programmer.
+
+ - Inline assembly code which changes memory, but which has no other
+ visible side effects, risks being deleted by GCC. Adding the volatile
+ keyword to asm statements will prevent this removal.
+
+ - The jiffies variable is special in that it can have a different value
+ every time it is referenced, but it can be read without any special
+ locking. So jiffies can be volatile, but the addition of other
+ variables of this type is strongly frowned upon. Jiffies is considered
+ to be a "stupid legacy" issue (Linus's words) in this regard; fixing it
+ would be more trouble than it is worth.
+
+ - Pointers to data structures in coherent memory which might be modified
+ by I/O devices can, sometimes, legitimately be volatile. A ring buffer
+ used by a network adapter, where that adapter changes pointers to
+ indicate which descriptors have been processed, is an example of this
+ type of situation.
+
+For most code, none of the above justifications for volatile apply. As a
+result, the use of volatile is likely to be seen as a bug and will bring
+additional scrutiny to the code. Developers who are tempted to use
+volatile should take a step back and think about what they are truly trying
+to accomplish.
+
+Patches to remove volatile variables are generally welcome - as long as
+they come with a justification which shows that the concurrency issues have
+been properly thought through.
+
+
+NOTES
+-----
+
+[1] http://lwn.net/Articles/233481/
+[2] http://lwn.net/Articles/233482/
+
+CREDITS
+-------
+
+Original impetus and research by Randy Dunlap
+Written by Jonathan Corbet
+Improvements via coments from Satyam Sharma, Johannes Stezenbach, Jesper
+ Juhl, Heikki Orsila, H. Peter Anvin, Philipp Hahn, and Stefan
+ Richter.


2007-05-11 21:25:27

by Jesper Juhl

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

On 11/05/07, Jonathan Corbet <[email protected]> wrote:
> Here's another version of the volatile document. Once again, I've tried
> to address all of the comments. There haven't really been any recent
> comments addressing the correctness of the document; people have been
> more concerned with how it's expressed. I'm glad to see files in
> Documentation/ held to a high standard of writing, but, unless somebody
> has a factual issue this time around I would like to declare Mission
> Accomplished and move on.
>
> Thanks,
>
> jon
>
> ---
>
> Encourage developers to avoid the volatile type class in kernel code.
>
> Signed-off-by: Jonathan Corbet <[email protected]>
>

Looks good to me.

Signed-off-by: Jesper Juhl <[email protected]>


--
Jesper Juhl <[email protected]>
Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html
Plain text mails only, please http://www.expita.com/nomime.html

2007-05-12 03:21:33

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

On 5/11/07, Jonathan Corbet <[email protected]> wrote:
> Here's another version of the volatile document. Once again, I've tried
> to address all of the comments. There haven't really been any recent
> comments addressing the correctness of the document; people have been
> more concerned with how it's expressed. I'm glad to see files in
> Documentation/ held to a high standard of writing, but, unless somebody
> has a factual issue this time around I would like to declare Mission
> Accomplished and move on.

The document looks good, but whether:

> + - Pointers to data structures in coherent memory which might be modified
> + by I/O devices can, sometimes, legitimately be volatile. A ring buffer
> + used by a network adapter, where that adapter changes pointers to
> + indicate which descriptors have been processed, is an example of this
> + type of situation.

is a legitimate use case for volatile is still not clear to me (I
agree with Alan's
comment in a previous thread that this seems to be a case where a memory
barrier would be applicable^Wbetter, actually). I could be wrong here, so
would be nice if Peter explains why volatile is legitimate here.

Otherwise, it's fine with me.

Thanks,
Satyam

2007-05-12 04:29:56

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma wrote:
> On 5/11/07, Jonathan Corbet <[email protected]> wrote:
>> + - Pointers to data structures in coherent memory which might be
>> modified
>> + by I/O devices can, sometimes, legitimately be volatile. A ring
>> buffer
>> + used by a network adapter, where that adapter changes pointers to
>> + indicate which descriptors have been processed, is an example of
>> this
>> + type of situation.
>
> is a legitimate use case for volatile is still not clear to me (I

IMO it is not. We do /not/ want to encourage volatile use in those
cases, and indeed, it's not necessary even if you can rationalize the
use of the English word "volatile" to describe the situation.

Drivers work quite well without volatile in such situations.

Jeff


2007-05-12 05:36:21

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma wrote:
>
>> + - Pointers to data structures in coherent memory which might be
>> modified
>> + by I/O devices can, sometimes, legitimately be volatile. A ring
>> buffer
>> + used by a network adapter, where that adapter changes pointers to
>> + indicate which descriptors have been processed, is an example of
>> this
>> + type of situation.
>
> is a legitimate use case for volatile is still not clear to me (I
> agree with Alan's
> comment in a previous thread that this seems to be a case where a memory
> barrier would be applicable^Wbetter, actually). I could be wrong here, so
> would be nice if Peter explains why volatile is legitimate here.
>
> Otherwise, it's fine with me.
>

I don't see why Alan's way is necessarily better; it should work but is
more heavy-handed as it's disabling *all* optimization such as loop
invariants across the barrier.

-hpa

2007-05-12 05:42:17

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

H. Peter Anvin wrote:
>
> I don't see why Alan's way is necessarily better; it should work but is
> more heavy-handed as it's disabling *all* optimization such as loop
> invariants across the barrier.
>

To expand on this further: the way this probably *should* be handled,
Linux-style, is with internally-volatile versions of le32_to_cpup() and
friends. That obeys the concept that the volatility should be
associated with an operation, not a data structure, and, being related
to an I/O device, should have its endianness explicitly declared.

Right now those macros don't exist, however.

-hpa

2007-05-12 06:15:52

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

On 5/12/07, H. Peter Anvin <[email protected]> wrote:
> Satyam Sharma wrote:
> >
> >> + - Pointers to data structures in coherent memory which might be
> >> modified
> >> + by I/O devices can, sometimes, legitimately be volatile. A ring
> >> buffer
> >> + used by a network adapter, where that adapter changes pointers to
> >> + indicate which descriptors have been processed, is an example of
> >> this
> >> + type of situation.
> >
> > is a legitimate use case for volatile is still not clear to me (I
> > agree with Alan's
> > comment in a previous thread that this seems to be a case where a memory
> > barrier would be applicable^Wbetter, actually). I could be wrong here, so
> > would be nice if Peter explains why volatile is legitimate here.
> >
> > Otherwise, it's fine with me.
> >
>
> I don't see why Alan's way is necessarily better;

Because volatile is ill-defined? Or actually, *undefined* (well,
implementation-defined is as good as that)? It's *so* _vague_,
one doesn't _feel_ like using it at all!

We already have a complete API containing optimization barriers,
load/store/full memory barriers. With well-defined and
well-understood semantics. Just ... _why_ use volatile?

> it should work but is

It will _always_ work. In fact you can't really say the same for
volatile. We already assume the compiler _actually_ took some
pains to stuff meaning into C's (lack of) definition of volatile and
implement it -- but in what sense, nobody knows (the C standard
doesn't, so what are we).

> more heavy-handed as it's disabling *all* optimization such as loop
> invariants across the barrier.

This is a legitimate criticism, I agree.

Thanks,
Satyam

2007-05-12 06:21:46

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma wrote:
>
> Because volatile is ill-defined? Or actually, *undefined* (well,
> implementation-defined is as good as that)? It's *so* _vague_,
> one doesn't _feel_ like using it at all!
>

Sorry, that's just utter crap. Linux isn't written in some mythical C
which only exists in standard document, it is written in a particular
subset of GNU C. "volatile" is well enough defined in that context, it
is just frequently misused.

> We already have a complete API containing optimization barriers,
> load/store/full memory barriers. With well-defined and
> well-understood semantics. Just ... _why_ use volatile?

See below.

> It will _always_ work. In fact you can't really say the same for
> volatile. We already assume the compiler _actually_ took some
> pains to stuff meaning into C's (lack of) definition of volatile and
> implement it -- but in what sense, nobody knows (the C standard
> doesn't, so what are we).

It will always work within the context of GNU C.

>> more heavy-handed as it's disabling *all* optimization such as loop
>> invariants across the barrier.
>
> This is a legitimate criticism, I agree.

There you have it.

-hpa

2007-05-12 07:02:25

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

On 5/12/07, H. Peter Anvin <[email protected]> wrote:
> Satyam Sharma wrote:
> >
> > Because volatile is ill-defined? Or actually, *undefined* (well,
> > implementation-defined is as good as that)? It's *so* _vague_,
> > one doesn't _feel_ like using it at all!
> >
>
> Sorry, that's just utter crap. Linux isn't written in some mythical C
> which only exists in standard document, it is written in a particular
> subset of GNU C. "volatile" is well enough defined in that context, it
> is just frequently misused.

Of course, volatile _is_ defined (well, _anything_ that is implemented
_is_ defined, after all) in the context of GNU C, and if you're saying
that the kernel (and all its subsystems) is and should _continue_ to
be (the purpose of this document) written within that context, then
that's your opinion and I would not disagree with you. If you do
prefer to continue using that dialect, then I wouldn't stop you either.

Personally, I'd prefer writing in a slightly more portable / larger
context (using well-defined and understood APIs), thank you, and
hope you'd allow me to do so myself.

Coming back to the document, we do need to document / find
consensus on the "preferred" way to do similar business in the
kernel, and my opinion as far as that is concerned is to shun
volatile wherever possible (which includes the case originally
discussed above).

Satyam

2007-05-12 07:14:49

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma wrote:
>>
>> Sorry, that's just utter crap. Linux isn't written in some mythical C
>> which only exists in standard document, it is written in a particular
>> subset of GNU C. "volatile" is well enough defined in that context, it
>> is just frequently misused.
>
> Of course, volatile _is_ defined (well, _anything_ that is implemented
> _is_ defined, after all) in the context of GNU C, and if you're saying
> that the kernel (and all its subsystems) is and should _continue_ to
> be (the purpose of this document) written within that context, then
> that's your opinion and I would not disagree with you. If you do
> prefer to continue using that dialect, then I wouldn't stop you either.
>

This isn't just an opinion, this is the language the Linux kernel is
written in today, and has been for the duration of its 16-year
existence. It contains *many* constructs that are not defined in, for
example, C99, and it would in fact be impossible to write the Linux
kernel using only C99-compliant constructs.

> Personally, I'd prefer writing in a slightly more portable / larger
> context (using well-defined and understood APIs), thank you, and
> hope you'd allow me to do so myself.

There is no such "slightly more portable/larger context/well-defined and
understood" context in existence. If you think so, you're deluding
yourself.

-hpa

2007-05-12 07:22:34

by Stefan Richter

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma wrote:
> Coming back to the document, we do need to document / find
> consensus on the "preferred" way to do similar business in the
> kernel, and my opinion as far as that is concerned is to shun
> volatile wherever possible (which includes the case originally
> discussed above).

I too recommend that volatile-considered-harmful.txt is not watered down
by an ever growing "but if" list. If anybody knows what he does, he
still can program in a deviating way --- provided that he leaves a brief
comment in the code, telling why it is possible and beneficial to use
the volatile qualifier in this special case.
--
Stefan Richter
-=====-=-=== -=-= -==--
http://arcgraph.de/sr/

2007-05-12 07:28:29

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

On 5/12/07, H. Peter Anvin <[email protected]> wrote:
> Satyam Sharma wrote:
> >>
> >> Sorry, that's just utter crap. Linux isn't written in some mythical C
> >> which only exists in standard document, it is written in a particular
> >> subset of GNU C. "volatile" is well enough defined in that context, it
> >> is just frequently misused.
> >
> > Of course, volatile _is_ defined (well, _anything_ that is implemented
> > _is_ defined, after all) in the context of GNU C, and if you're saying
> > that the kernel (and all its subsystems) is and should _continue_ to
> > be (the purpose of this document) written within that context, then
> > that's your opinion and I would not disagree with you. If you do
> > prefer to continue using that dialect, then I wouldn't stop you either.
> >
>
> This isn't just an opinion, this is the language the Linux kernel is
> written in today, and has been for the duration of its 16-year

I said "and should _continue_ to be (the purpose of this document)
written within that context, then that's your opinion". That "is" before
the "and should ..." was not meant to be combined with "your
opinion".

> existence. It contains *many* constructs that are not defined in, for
> example, C99, and it would in fact be impossible to write the Linux
> kernel using only C99-compliant constructs.

And that is not what I attempt to do (or even suggest) either. Which is
why I do *not* disagree with the jiffies clause -- it exists in that
document merely to _inform_ readers about _current_ behaviour /
dialect of the kernel and not to influence code written in the future.
The problem with the last clause is that it explicitly influences
*future* code (by coming in as a "rare situation where volatile
makes sense in the kernel").

> > Personally, I'd prefer writing in a slightly more portable / larger
> > context (using well-defined and understood APIs), thank you, and
> > hope you'd allow me to do so myself.
>
> There is no such "slightly more portable/larger context/well-defined and
> understood" context in existence. If you think so, you're deluding
> yourself.

If you remember my original mail was in the "_why_ use volatile" tone,
which means to _dissuade_ future spurious additions of volatile to the
kernel. Now this _is_ a matter of opinion: I personally prefer as much
(if not all) future code to be dialect-independent, you might not.

Satyam

2007-05-12 07:34:17

by jimmy bahuleyan

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Stefan Richter wrote:
> Satyam Sharma wrote:
>> Coming back to the document, we do need to document / find
>> consensus on the "preferred" way to do similar business in the
>> kernel, and my opinion as far as that is concerned is to shun
>> volatile wherever possible (which includes the case originally
>> discussed above).
>
> I too recommend that volatile-considered-harmful.txt is not watered down
> by an ever growing "but if" list. If anybody knows what he does, he
> still can program in a deviating way --- provided that he leaves a brief
> comment in the code, telling why it is possible and beneficial to use
> the volatile qualifier in this special case.

yes, this seems the better option. generally, the more complex rules you
have, the more people tend to break it (either through not being able t
comprehend it or cos it's too difficult to follow).

i believe, the doc here is pretty unambiguous regarding the fact that
volatile should be avoided. And as Stefan pointed out, anyone who feels
the need to use, must surely _know_ what he is doing & hence is in a
position t make that decision (followed ofcourse with a doc of why it
was done).

it would be better we didn't grow the list of exceptions - IMHO.

-jb
--
Tact is the art of making a point without making an enemy.

2007-05-12 07:46:17

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

jimmy bahuleyan wrote:
> i believe, the doc here is pretty unambiguous regarding the fact that
> volatile should be avoided. And as Stefan pointed out, anyone who feels
> the need to use, must surely _know_ what he is doing & hence is in a
> position t make that decision

Honestly, the above quoted paragraph states the situation better than
any long, complicated document.

Jeff


2007-05-12 07:54:00

by Stefan Richter

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

H. Peter Anvin wrote:
[slightly off topic: GCCisms in Linux kernel]
> It contains *many* constructs that are not defined in, for
> example, C99, and it would in fact be impossible to write the Linux
> kernel using only C99-compliant constructs.

True. On the other hand, it is possible to keep large parts of the
kernel independent of compiler implementation details. And it is not
only possible but also beneficial, e.g. because the compiler's
implementation changes over time.
--
Stefan Richter
-=====-=-=== -=-= -==--
http://arcgraph.de/sr/

2007-05-12 11:52:46

by Heikki Orsila

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

On Sat, May 12, 2007 at 09:53:03AM +0200, Stefan Richter wrote:
> H. Peter Anvin wrote:
> [slightly off topic: GCCisms in Linux kernel]
> > It contains *many* constructs that are not defined in, for
> > example, C99, and it would in fact be impossible to write the Linux
> > kernel using only C99-compliant constructs.
>
> True. On the other hand, it is possible to keep large parts of the
> kernel independent of compiler implementation details. And it is not
> only possible but also beneficial, e.g. because the compiler's
> implementation changes over time.

I think the most important reason for portable code is that new readers
are more familiar with effects of the code.

--
Heikki Orsila Barbie's law:
[email protected] "Math is hard, let's go shopping!"
http://www.iki.fi/shd

2007-05-12 18:07:55

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Stefan Richter wrote:
> H. Peter Anvin wrote:
> [slightly off topic: GCCisms in Linux kernel]
>> It contains *many* constructs that are not defined in, for
>> example, C99, and it would in fact be impossible to write the Linux
>> kernel using only C99-compliant constructs.
>
> True. On the other hand, it is possible to keep large parts of the
> kernel independent of compiler implementation details. And it is not
> only possible but also beneficial, e.g. because the compiler's
> implementation changes over time.

It is, but this is not likely to be one of those things.

Either way, I fully agree with the following (from Jeff):

> jimmy bahuleyan wrote:
>> i believe, the doc here is pretty unambiguous regarding the fact that
>> volatile should be avoided. And as Stefan pointed out, anyone who feels
>> the need to use, must surely _know_ what he is doing & hence is in a
>> position t make that decision
>
> Honestly, the above quoted paragraph states the situation better than any long, complicated document.

-hpa

2007-05-12 19:57:16

by Dr. David Alan Gilbert

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

* H. Peter Anvin ([email protected]) wrote:
> Satyam Sharma wrote:
> >
> > Because volatile is ill-defined? Or actually, *undefined* (well,
> > implementation-defined is as good as that)? It's *so* _vague_,
> > one doesn't _feel_ like using it at all!
> >
>
> Sorry, that's just utter crap. Linux isn't written in some mythical C
> which only exists in standard document, it is written in a particular
> subset of GNU C. "volatile" is well enough defined in that context, it
> is just frequently misused.

Where? I don't ever recall seeing something that defines Gcc's behaviour
with volatile on different architectures.
I know on some architectures gcc generates different instructions
for volatile accesses (e.g. load acquire/store release on IA64); I'd
be pleasently surprised if gcc's behaviour was consistent accross
architectures.

Dave
--
-----Open up your eyes, open up your mind, open up your code -------
/ Dr. David Alan Gilbert | Running GNU/Linux on Alpha,68K| Happy \
\ gro.gilbert @ treblig.org | MIPS,x86,ARM,SPARC,PPC & HPPA | In Hex /
\ _________________________|_____ http://www.treblig.org |_______/

2007-05-13 00:00:52

by Bodo Eggert

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma <[email protected]> wrote:

> In fact you can't really say the same for
> volatile. We already assume the compiler _actually_ took some
> pains to stuff meaning into C's (lack of) definition of volatile and
> implement it -- but in what sense, nobody knows (the C standard
^^^^^^^^^^^^^^
> doesn't, so what are we).
^^^^^^^
It does:

ISO/IEC 9899:1999 (E)

5.1.2.3 Program execution

5 The least requirements on a conforming implementation are:
At sequence points, volatile objects are stable in the sense that previous
accesses are complete and subsequent accesses have not yet occurred.

9 Alternatively, an implementation might perform various optimizations
within each translation unit, such that the actual semantics would agree
with the abstract semantics only when making function calls across
translation unit boundaries. In such an implementation, at the time of each
function entry and function return where the calling function and the
called function are in different translation units, the values of all
externally linked objects and of all objects accessible via pointers
therein would agree with the abstract semantics. Furthermore, at the time
of each such function entry the values of the parameters of the called
function and of all objects accessible via pointers therein would agree
with the abstract semantics. In this type of implementation, objects
referred to by interrupt service routines activated by the signal function
would require explicit specification of volatile storage, as well as other
implementation-defined restrictions.


6.7.3 Type qualifiers

6 An object that has volatile-qualified type may be modified in ways unknown
to the implementation or have other unknown side effects. Therefore any
expression referring to such an object shall be evaluated strictly according
to the rules of the abstract machine, as described in 5.1.2.3. Furthermore,
at every sequence point the value last stored in the object shall agree with
that prescribed by the abstract machine, except as modified by the unknown
factors mentioned previously.114) What constitutes an access to an object
that has volatile-qualified type is implementation-defined.

<snip>

It does not guarantee ordering or consistency beyond the scope of the
assembler layer, especially the CPU or other hardware may be free to cache
or reorder load/stores to these volatile objects (see e.g. MTRR), which is
why you'll usurally want to use something completely different. If you know
an object to not be modified from outside the scope of the C state machine
and it does not have relevant side effects, you can however use volatile
(likely on an atomic value).

I think you should say something like:

1) Don't use volatile
2) Read memory-barriers.txt carefully!
3) If you still use volatile, explain
a) Why it's nescensary
b) Why it's enough (see (2))
to specify volatile on that object. Be sure to consider hardware cache and
reordering, as well as prohibited optimizations on volatile access and on
functions possibly doing volatile access.
--
Top 100 things you don't want the sysadmin to say:
14. Any more trouble from you and your account gets moved to the 750

Fri?, Spammer: [email protected] [email protected]

2007-05-14 03:37:26

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Hi Bodo,

On 5/13/07, Bodo Eggert <[email protected]> wrote:
> Satyam Sharma <[email protected]> wrote:
>
> > In fact you can't really say the same for
> > volatile. We already assume the compiler _actually_ took some
> > pains to stuff meaning into C's (lack of) definition of volatile and
> > implement it -- but in what sense, nobody knows (the C standard
> ^^^^^^^^^^^^^^
> > doesn't, so what are we).
> ^^^^^^^
> It does:

I don't think so ... the ambiguity in 6.7.3:6 is why.

> ISO/IEC 9899:1999 (E)
>
> 5.1.2.3 Program execution
>
> 5 The least requirements on a conforming implementation are:
> At sequence points, volatile objects are stable in the sense that previous
> accesses are complete and subsequent accesses have not yet occurred.

Worthy goal, indeed, but you've yourself pointed out later in your mail
why this may not be possible for a compiler/assembler to guarantee safely
(in a sense that the programmer usually wants, anyway), even with the C
standard-blessed "volatile" type-qualifier, what with the *hardware*
optimizing memory accesses _independently_ at a granularity finer than
the "sequence points" understood by a compiler.

> 9 Alternatively, an implementation might perform various optimizations
> within each translation unit, such that the actual semantics would agree
> with the abstract semantics only when making function calls across
> translation unit boundaries. In such an implementation, at the time of each
> function entry and function return where the calling function and the
> called function are in different translation units, the values of all
> externally linked objects and of all objects accessible via pointers
> therein would agree with the abstract semantics. Furthermore, at the time
> of each such function entry the values of the parameters of the called
> function and of all objects accessible via pointers therein would agree
> with the abstract semantics. In this type of implementation, objects
> referred to by interrupt service routines activated by the signal function
> would require explicit specification of volatile storage, as well as other
> implementation-defined restrictions.
>
>
> 6.7.3 Type qualifiers
>
> 6 An object that has volatile-qualified type may be modified in ways unknown
> to the implementation or have other unknown side effects. Therefore any
> expression referring to such an object shall be evaluated strictly according
> to the rules of the abstract machine, as described in 5.1.2.3. Furthermore,
> at every sequence point the value last stored in the object shall agree with
> that prescribed by the abstract machine, except as modified by the unknown
> factors mentioned previously.114) What constitutes an access to an object
> that has volatile-qualified type is implementation-defined.

The way I read it, "What constitutes an access to an object that has
volatile-qualified type is implementation-defined" is the standard's way
of saying: "All bets are off." Actually I wonder how the various _compiler
implementations_ read this clause (and whether *all* of them read it
consistently and equally, which is what a portable codebase probably
wants), because _their_ interpretation of this clause is more important
than mine, after all. But I don't really see how generic C code that uses
"volatile" can also claim dialect-independence.

So, IMO, the trouble with the volatile type-qualifier is that it is (what
should have been defined as in the first place, and what is in effect)
a _compiler extension_ *masquerading* as a _language keyword_.

*Unfortunately* (the trouble with C itself, is that a *committee* has made
it into ... something ... that it should not have made it into) -- anyway,
unfortunately C took it upon itself to solve a problem that it did not
have (and does not even bring about) in the first place: and the
half-hearted (or vague, call it what you will) attempt _then_ ends up
being a problem -- by making people _feel_ as if they are doing things
right, when that is probably not the case.

[ And we've not even touched the issue of whether the _same_ compiler's
implementation of volatile across archs/platforms is consistent. ]

> It does not guarantee ordering or consistency beyond the scope of the
> assembler layer, especially the CPU or other hardware may be free to cache
> or reorder load/stores to these volatile objects (see e.g. MTRR), which is
> why you'll usurally want to use something completely different. If you know

Exactly. So this combined with the issue above, is the last nail in volatile's
coffin as far as I'm concerned.

> an object to not be modified from outside the scope of the C state machine
> and it does not have relevant side effects, you can however use volatile
> (likely on an atomic value).

Yes, but I'd prefer to stick to the straight-and-narrow (well-defined-and-
well-understood), and avoid volatile altogether. The kernel codebase does
contain APIs that allow one to avoid it and are also what one probably
wants for most situations.

> I think you should say something like:
>
> 1) Don't use volatile
> 2) Read memory-barriers.txt carefully!
> 3) If you still use volatile, explain
> a) Why it's nescensary
> b) Why it's enough (see (2))
> to specify volatile on that object. Be sure to consider hardware cache and
> reordering, as well as prohibited optimizations on volatile access and on
> functions possibly doing volatile access.

Yeah, I agree with the wording above, also with Jimmy's summary that Jeff
and Peter agreed to already.

Satyam

2007-05-17 23:51:26

by Bill Davidsen

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Satyam Sharma wrote:

> *Unfortunately* (the trouble with C itself, is that a *committee* has made
> it into ... something ... that it should not have made it into) -- anyway,
> unfortunately C took it upon itself to solve a problem that it did not
> have (and does not even bring about) in the first place: and the
> half-hearted (or vague, call it what you will) attempt _then_ ends up
> being a problem -- by making people _feel_ as if they are doing things
> right, when that is probably not the case.
>
> [ And we've not even touched the issue of whether the _same_ compiler's
> implementation of volatile across archs/platforms is consistent. ]
>
Pardon, I was GE's representative to the original X3J11 committee, and
'volatile' was added to "codify existing practice" which is one of the
goals of a standard. The extension existed, in at least two forms, to
allow handling of memory mapped hardware. So the committee did not take
it upon itself, it was a part of the defined duty of the committee.

The intents was simple, clear, and limited, to tell the compiler that
every read of a variable in source code should result in a read, at that
point in the logic, and similar for writes. In other words, the code
should not be moved and should generate a real memory access every time.
People have tried to do many things with that limited concept since,
some with "clarification" and some with assuming the compiler knows when
to ignore volatile.

As someone noted about a committee, a committee is a poor way to get
innovation, and a good way to have a bunch of know legible people shoot
down bad ideas.

It was a fun experience, where I first learned the modern equivalent of
Occam's Razor, Plauger's "Law of least astonishment," which compiler
writers regularly violate :-(

--
Bill Davidsen <[email protected]>
"We have more to fear from the bungling of the incompetent than from
the machinations of the wicked." - from Slashdot

2007-05-18 03:13:30

by Satyam Sharma

[permalink] [raw]
Subject: Re: [PATCH] "volatile considered harmful", take 3

Hi Bill,

On 5/18/07, Bill Davidsen <[email protected]> wrote:
> Satyam Sharma wrote:
>
> > *Unfortunately* (the trouble with C itself, is that a *committee* has made
> > it into ... something ... that it should not have made it into) -- anyway,
> > unfortunately C took it upon itself to solve a problem that it did not
> > have (and does not even bring about) in the first place: and the
> > half-hearted (or vague, call it what you will) attempt _then_ ends up
> > being a problem -- by making people _feel_ as if they are doing things
> > right, when that is probably not the case.
> >
> > [ And we've not even touched the issue of whether the _same_ compiler's
> > implementation of volatile across archs/platforms is consistent. ]

> It was a fun experience, where I first learned the modern equivalent of
> Occam's Razor, Plauger's "Law of least astonishment," which compiler
> writers regularly violate :-(

Well, here it was a case of the standard committee violating the principle
of solving a problem _where_ it exists in the first place. As far as volatile
is concerned, the _language_ itself had absolutely no problems that
needed fixing ...

> Pardon, I was GE's representative to the original X3J11 committee, and
> 'volatile' was added to "codify existing practice" which is one of the
> goals of a standard. The extension existed, in at least two forms, to
> allow handling of memory mapped hardware. So the committee did not take
> it upon itself, it was a part of the defined duty of the committee.
>
> The intents was simple, clear, and limited, to tell the compiler that
> every read of a variable in source code should result in a read, at that
> point in the logic, and similar for writes. In other words, the code
> should not be moved and should generate a real memory access every time.
> People have tried to do many things with that limited concept since,
> some with "clarification" and some with assuming the compiler knows when
> to ignore volatile.

In fact I wish the standard just left this functionality entirely up to the
implementation.

After all, C (the _language_) does not mandate memory access
reordering / optimization by implementations so dumb compilers
(5.1.2.3:1) that do not do any are still conformant and hence
don't require the volatile extension (5.1.2.3:8). Implementations that
do perform optimization, otoh, _must_ then solve the possible problems
_themselves_ by providing an extension that allows the programmer
to turn it off (wherever necessary) to prevent those side-effects that the
implementation itself brought about by performing optimization in the
first place. That _compiler extension_ could then of course be called
anything (volatile, foo, bar, barrier, ...) and implemented in any way --
whatever is appropriate for that compiler [1].

[ Analogically, C (or any language) does not mandate the hardware
it runs on to reorder / optimize memory accesses. Those that do, must
clearly then also provide instructions like lfence/sfence/mfence as part
of their instruction set to solve potential issues that _their_ behaviour
brings about in the first place. How horribly wrong it would be for a
_language_ to try and go about solving this problem ... ]

So the way I see it, it's just a case of solving a problem _where_ it
exists in the first place.

Satyam

[1] Which begs the question, so if we wished (note past tense here)
to keep generic kernel code compiler-independent, what do we do in
situations where we want to disable _compiler optimizations_ temporarily
for some piece of code? => By defining macros / some API as part of
our codebase in implementation-specific headers that does whatever
needs to be done for _that_ compiler. => Which is precisely what we
have already and why I like/prefer that.