⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel-locking.tmpl

📁 linux 内核源代码
💻 TMPL
📖 第 1 页 / 共 5 页
字号:
       to justify the extra complexity.     </para>     <para>       You'll need to use <function>spin_lock()</function> and        <function>spin_unlock()</function> for shared data.     </para>    </sect2>    <sect2 id="lock-softirqs-different">     <title>Different Softirqs</title>     <para>       You'll need to use <function>spin_lock()</function> and       <function>spin_unlock()</function> for shared data, whether it       be a timer, tasklet, different softirq or the same or another       softirq: any of them could be running on a different CPU.     </para>    </sect2>   </sect1>  </chapter>  <chapter id="hardirq-context">   <title>Hard IRQ Context</title>   <para>     Hardware interrupts usually communicate with a     tasklet or softirq.  Frequently this involves putting work in a     queue, which the softirq will take out.   </para>   <sect1 id="hardirq-softirq">    <title>Locking Between Hard IRQ and Softirqs/Tasklets</title>    <para>      If a hardware irq handler shares data with a softirq, you have      two concerns.  Firstly, the softirq processing can be      interrupted by a hardware interrupt, and secondly, the      critical region could be entered by a hardware interrupt on      another CPU.  This is where <function>spin_lock_irq()</function> is       used.  It is defined to disable interrupts on that cpu, then grab       the lock. <function>spin_unlock_irq()</function> does the reverse.    </para>    <para>      The irq handler does not to use      <function>spin_lock_irq()</function>, because the softirq cannot      run while the irq handler is running: it can use      <function>spin_lock()</function>, which is slightly faster.  The      only exception would be if a different hardware irq handler uses      the same lock: <function>spin_lock_irq()</function> will stop      that from interrupting us.    </para>    <para>      This works perfectly for UP as well: the spin lock vanishes,      and this macro simply becomes <function>local_irq_disable()</function>      (<filename class="headerfile">include/asm/smp.h</filename>), which      protects you from the softirq/tasklet/BH being run.    </para>    <para>      <function>spin_lock_irqsave()</function>       (<filename>include/linux/spinlock.h</filename>) is a variant      which saves whether interrupts were on or off in a flags word,      which is passed to <function>spin_unlock_irqrestore()</function>.  This      means that the same code can be used inside an hard irq handler (where      interrupts are already off) and in softirqs (where the irq      disabling is required).    </para>    <para>      Note that softirqs (and hence tasklets and timers) are run on      return from hardware interrupts, so      <function>spin_lock_irq()</function> also stops these.  In that      sense, <function>spin_lock_irqsave()</function> is the most      general and powerful locking function.    </para>   </sect1>   <sect1 id="hardirq-hardirq">    <title>Locking Between Two Hard IRQ Handlers</title>    <para>      It is rare to have to share data between two IRQ handlers, but      if you do, <function>spin_lock_irqsave()</function> should be      used: it is architecture-specific whether all interrupts are      disabled inside irq handlers themselves.    </para>   </sect1>  </chapter>  <chapter id="cheatsheet">   <title>Cheat Sheet For Locking</title>   <para>     Pete Zaitcev gives the following summary:   </para>   <itemizedlist>      <listitem>	<para>          If you are in a process context (any syscall) and want to	lock other process out, use a semaphore.  You can take a semaphore	and sleep (<function>copy_from_user*(</function> or	<function>kmalloc(x,GFP_KERNEL)</function>).      </para>      </listitem>      <listitem>	<para>	Otherwise (== data can be touched in an interrupt), use	<function>spin_lock_irqsave()</function> and	<function>spin_unlock_irqrestore()</function>.	</para>      </listitem>      <listitem>	<para>	Avoid holding spinlock for more than 5 lines of code and	across any function call (except accessors like	<function>readb</function>).	</para>      </listitem>    </itemizedlist>   <sect1 id="minimum-lock-reqirements">   <title>Table of Minimum Requirements</title>   <para> The following table lists the <emphasis>minimum</emphasis>	locking requirements between various contexts.  In some cases,	the same context can only be running on one CPU at a time, so	no locking is required for that context (eg. a particular	thread can only run on one CPU at a time, but if it needs	shares data with another thread, locking is required).   </para>   <para>	Remember the advice above: you can always use	<function>spin_lock_irqsave()</function>, which is a superset	of all other spinlock primitives.   </para>   <table><title>Table of Locking Requirements</title><tgroup cols="11"><tbody><row><entry></entry><entry>IRQ Handler A</entry><entry>IRQ Handler B</entry><entry>Softirq A</entry><entry>Softirq B</entry><entry>Tasklet A</entry><entry>Tasklet B</entry><entry>Timer A</entry><entry>Timer B</entry><entry>User Context A</entry><entry>User Context B</entry></row><row><entry>IRQ Handler A</entry><entry>None</entry></row><row><entry>IRQ Handler B</entry><entry>SLIS</entry><entry>None</entry></row><row><entry>Softirq A</entry><entry>SLI</entry><entry>SLI</entry><entry>SL</entry></row><row><entry>Softirq B</entry><entry>SLI</entry><entry>SLI</entry><entry>SL</entry><entry>SL</entry></row><row><entry>Tasklet A</entry><entry>SLI</entry><entry>SLI</entry><entry>SL</entry><entry>SL</entry><entry>None</entry></row><row><entry>Tasklet B</entry><entry>SLI</entry><entry>SLI</entry><entry>SL</entry><entry>SL</entry><entry>SL</entry><entry>None</entry></row><row><entry>Timer A</entry><entry>SLI</entry><entry>SLI</entry><entry>SL</entry><entry>SL</entry><entry>SL</entry><entry>SL</entry><entry>None</entry></row><row><entry>Timer B</entry><entry>SLI</entry><entry>SLI</entry><entry>SL</entry><entry>SL</entry><entry>SL</entry><entry>SL</entry><entry>SL</entry><entry>None</entry></row><row><entry>User Context A</entry><entry>SLI</entry><entry>SLI</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>None</entry></row><row><entry>User Context B</entry><entry>SLI</entry><entry>SLI</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>SLBH</entry><entry>DI</entry><entry>None</entry></row></tbody></tgroup></table>   <table><title>Legend for Locking Requirements Table</title><tgroup cols="2"><tbody><row><entry>SLIS</entry><entry>spin_lock_irqsave</entry></row><row><entry>SLI</entry><entry>spin_lock_irq</entry></row><row><entry>SL</entry><entry>spin_lock</entry></row><row><entry>SLBH</entry><entry>spin_lock_bh</entry></row><row><entry>DI</entry><entry>down_interruptible</entry></row></tbody></tgroup></table></sect1></chapter>  <chapter id="Examples">   <title>Common Examples</title>    <para>Let's step through a simple example: a cache of number to namemappings.  The cache keeps a count of how often each of the objects isused, and when it gets full, throws out the least used one.    </para>   <sect1 id="examples-usercontext">    <title>All In User Context</title>    <para>For our first example, we assume that all operations are in usercontext (ie. from system calls), so we can sleep.  This means we canuse a semaphore to protect the cache and all the objects withinit.  Here's the code:    </para>    <programlisting>#include &lt;linux/list.h&gt;#include &lt;linux/slab.h&gt;#include &lt;linux/string.h&gt;#include &lt;asm/semaphore.h&gt;#include &lt;asm/errno.h&gt;struct object{        struct list_head list;        int id;        char name[32];        int popularity;};/* Protects the cache, cache_num, and the objects within it */static DECLARE_MUTEX(cache_lock);static LIST_HEAD(cache);static unsigned int cache_num = 0;#define MAX_CACHE_SIZE 10/* Must be holding cache_lock */static struct object *__cache_find(int id){        struct object *i;        list_for_each_entry(i, &amp;cache, list)                if (i-&gt;id == id) {                        i-&gt;popularity++;                        return i;                }        return NULL;}/* Must be holding cache_lock */static void __cache_delete(struct object *obj){        BUG_ON(!obj);        list_del(&amp;obj-&gt;list);        kfree(obj);        cache_num--;}/* Must be holding cache_lock */static void __cache_add(struct object *obj){        list_add(&amp;obj-&gt;list, &amp;cache);        if (++cache_num > MAX_CACHE_SIZE) {                struct object *i, *outcast = NULL;                list_for_each_entry(i, &amp;cache, list) {                        if (!outcast || i-&gt;popularity &lt; outcast-&gt;popularity)                                outcast = i;                }                __cache_delete(outcast);        }}int cache_add(int id, const char *name){        struct object *obj;        if ((obj = kmalloc(sizeof(*obj), GFP_KERNEL)) == NULL)                return -ENOMEM;        strlcpy(obj-&gt;name, name, sizeof(obj-&gt;name));        obj-&gt;id = id;        obj-&gt;popularity = 0;        down(&amp;cache_lock);        __cache_add(obj);        up(&amp;cache_lock);        return 0;}void cache_delete(int id){        down(&amp;cache_lock);        __cache_delete(__cache_find(id));        up(&amp;cache_lock);}int cache_find(int id, char *name){        struct object *obj;        int ret = -ENOENT;        down(&amp;cache_lock);        obj = __cache_find(id);        if (obj) {                ret = 0;                strcpy(name, obj-&gt;name);        }        up(&amp;cache_lock);        return ret;}</programlisting>    <para>Note that we always make sure we have the cache_lock when we add,delete, or look up the cache: both the cache infrastructure itself andthe contents of the objects are protected by the lock.  In this caseit's easy, since we copy the data for the user, and never let themaccess the objects directly.    </para>    <para>There is a slight (and common) optimization here: in<function>cache_add</function> we set up the fields of the objectbefore grabbing the lock.  This is safe, as no-one else can access ituntil we put it in cache.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -