[prev in list] [next in list] [prev in thread] [next in thread]
List: linux-doc
Subject: [PATCH 14/25] Docs: kernel-hacking: Rewrite local_irq_{disable,enable,save,restore}
From: Michael Witten <mfwitten () gmail ! com>
Date: 2010-02-27 7:10:57
Message-ID: 1268106578-29745-3-git-send-email-mfwitten () gmail ! com
[Download RAW message or body]
This section has been greatly expanded and clarified.
Signed-off-by: Michael Witten <mfwitten@gmail.com>
---
Documentation/DocBook/kernel-hacking.tmpl | 112 +++++++++++++++++++++++++++--
1 files changed, 106 insertions(+), 6 deletions(-)
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index aaf2be4..37901b9 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -679,11 +679,111 @@
</title>
- <para>
- These routines disable hard[ware] interrupts on the local CPU, and
- restore them. They are reentrant; saving the previous state in
- their one <varname>unsigned long flags</varname> argument. If you
- know that interrupts are enabled, you can simply use
- <function>local_irq_disable()</function> and
- <function>local_irq_enable()</function>.
- </para>
+ <para>
+ With respect to a CPU instruction, a <firstterm>local CPU</firstterm> is
+ a CPU that is executing that instruction.
+ </para>
+
+ <para>
+ Often, it is important to be able to execute a sequence of instructions
+ with the assurance that the corresponding local CPU won't be interrupted
+ until it has completed executing that sequence of instructions; under
+ these needs, such a sequence of instructions is considered as a whole to
+ be <firstterm>locally atomic</firstterm> (that is, 'indivisible' on the
+ corresponding local CPU). The routines discussed here are helpful in
+ creating such <firstterm>local atomicity</firstterm>.
+ </para>
+
+ <para>
+ The main purpose of these routines is to affect how a
+ local CPU treats hard[ware] interrupts: By executing
+ <function>local_irq_disable()</function>, a local CPU is instructed
+ to ignore hard interrupts; by executing
+ <function>local_irq_enable()</function>, a local CPU is instructed
+ to respond to hard interrupts. Consequently, in the simplest case,
+ a block of code can be rendered locally atomic by placing
+ <function>local_irq_disable()</function> before the block and
+ <function>local_irq_enable()</function> after the block.
+ </para>
+
+ <para>
+ However, what if one such locally atomic block calls a function that runs
+ another such locally atomic block? In that case, this latter block
+ might run <function>local_irq_enable()</function>
+ before the first block finishes, thereby ruining the local atomicity
+ of the first block.
+ </para>
+
+ <para>
+ This problem can be solved by noting whether a local CPU is already
+ ignoring hard interrupts when entering a locally atomic block, and then
+ restoring that same status upon exiting the block, all of which
+ can be achieved by replacing
+ <function>local_irq_{disable,enable}()</function> with
+ <function>local_irq_{save,restore}(<varname>flags</varname>)</function>
+ macros, where <varname>flags</varname> is a user-supplied stack-allocated
+ variable of type <emphasis>unsigned long</emphasis>
+ (note: it's <emphasis>not</emphasis> a pointer type).
+ </para>
+
+ <para>
+ The <function>local_irq_save(<varname>flags</varname>)</function> macro
+ exands around the <varname>flags</varname> variable to perform 2 tasks
+ on a local CPU:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The local CPU's relevant processor-state bits (including
+ <emphasis>at least</emphasis> those that affect hard interrupts) are
+ stored in <varname>flags</varname>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The local CPU is instructed to ignore hard interrupts; essentially
+ a call to <function>local_irq_disable()</function> is made.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The <function>local_irq_restore(<varname>flags</varname>)</function> macro
+ exands to instruct a local CPU to use as its relevant processor-state bits
+ the values stored in the <varname>flags</varname> variable.
+ </para>
+
+ <para>
+ Hence, if a local CPU is already ignoring hard interrupts when
+ <function>local_irq_save(<varname>flags</varname>)</function> is used,
+ then that local CPU will continue to ignore hard interrupts when the
+ corresponding
+ <function>local_irq_restore(<varname>flags</varname>)</function> is
+ used, thereby allowing for the nesting of locally atomic blocks. However,
+ if a local CPU is responding to hard interrupts when
+ <function>local_irq_save(<varname>flags</varname>)</function> is used,
+ then that local CPU will once again respond to hard interrupts when
+ the corresponding
+ <function>local_irq_restore(<varname>flags</varname>)</function>
+ is used, as if a call to <function>local_irq_enable()</function>
+ has been made.
+ </para>
+
+ <para>
+ Of course,
+ <function>local_irq_{save,restore}(<varname>flags</varname>)</function>
+ are more expensive in time and space than are
+ <function>local_irq_{disable,enable}()</function>. Consequently,
+ the latter should be used when it makes sense to do so.
+ </para>
+
+ <para>
+ These macros/functions are reentrant.
+ </para>
+
+ <para>
+ There are also other means by which kernel code can achieve synchronization
+ and atomicity through locking mechanisms, and they are especially important
+ for code that may run concurrently across multiple CPUs.
+ </para>
</sect1>
--
1.7.0.94.gf7311
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic