public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Corbet <corbet@lwn.net>
To: akpm@linux-foundation.org
Cc: linux-kernel@vger.kernel.org,
	Johannes Stezenbach <js@linuxtv.org>,
	Jesper Juhl <jesper.juhl@gmail.com>,
	Randy Dunlap <randy.dunlap@oracle.com>,
	Heikki Orsila <shdl@zakalwe.fi>, "H. Peter Anvin" <hpa@zytor.com>,
	Satyam Sharma <satyam.sharma@gmail.com>,
	jimmy bahuleyan <knight.camelot@gmail.com>,
	Stefan Richter <stefanr@s5r6.in-berlin.de>
Subject: [PATCH] "volatile considered harmful", take 3
Date: Fri, 11 May 2007 11:36:40 -0600	[thread overview]
Message-ID: <12700.1178905000@lwn.net> (raw)

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 <corbet@lwn.net>

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. 

             reply	other threads:[~2007-05-11 17:36 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-11 17:36 Jonathan Corbet [this message]
2007-05-11 21:25 ` [PATCH] "volatile considered harmful", take 3 Jesper Juhl
2007-05-12  3:21 ` Satyam Sharma
2007-05-12  4:29   ` Jeff Garzik
2007-05-12  5:34   ` H. Peter Anvin
2007-05-12  5:41     ` H. Peter Anvin
2007-05-12  6:15     ` Satyam Sharma
2007-05-12  6:21       ` H. Peter Anvin
2007-05-12  7:02         ` Satyam Sharma
2007-05-12  7:13           ` H. Peter Anvin
2007-05-12  7:28             ` Satyam Sharma
2007-05-12  7:53             ` Stefan Richter
2007-05-12 11:51               ` Heikki Orsila
2007-05-12 18:06               ` H. Peter Anvin
2007-05-12  7:22           ` Stefan Richter
2007-05-12  7:33             ` jimmy bahuleyan
2007-05-12  7:45               ` Jeff Garzik
2007-05-12 19:17         ` Dr. David Alan Gilbert
     [not found] <8jHg3-1T2-5@gated-at.bofh.it>
     [not found] ` <8jQt5-7As-3@gated-at.bofh.it>
     [not found]   ` <8jSuQ-28J-21@gated-at.bofh.it>
     [not found]     ` <8jT7y-39x-9@gated-at.bofh.it>
2007-05-13  0:00       ` Bodo Eggert
2007-05-14  3:37         ` Satyam Sharma
2007-05-17 23:51           ` Bill Davidsen
2007-05-18  3:13             ` Satyam Sharma

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=12700.1178905000@lwn.net \
    --to=corbet@lwn.net \
    --cc=akpm@linux-foundation.org \
    --cc=hpa@zytor.com \
    --cc=jesper.juhl@gmail.com \
    --cc=js@linuxtv.org \
    --cc=knight.camelot@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=randy.dunlap@oracle.com \
    --cc=satyam.sharma@gmail.com \
    --cc=shdl@zakalwe.fi \
    --cc=stefanr@s5r6.in-berlin.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox