This section has been greatly expanded and clarified. Signed-off-by: Michael Witten <mfwitten@xxxxxxxxx> --- Documentation/DocBook/kernel-hacking.tmpl | 111 +++++++++++++++++++++++++++-- 1 files changed, 105 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl index 2ddc79a..f995e7f 100644 --- a/Documentation/DocBook/kernel-hacking.tmpl +++ b/Documentation/DocBook/kernel-hacking.tmpl @@ -679,12 +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>atomic</firstterm> (that is, 'indivisible'). The routines + discussed here are helpful in creating such + <firstterm>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 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 atomic block calls a function that runs + another such atomic block? In that case, this latter atomic block + might run <function>local_irq_enable()</function> + before the first atomic block finishes, thereby ruining the 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 an atomic block and then restoring + that same status upon exiting the atomic 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 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. + </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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html