|
@@ -219,10 +219,10 @@
|
|
|
</para>
|
|
|
|
|
|
<sect1 id="lock-intro">
|
|
|
- <title>Three Main Types of Kernel Locks: Spinlocks, Mutexes and Semaphores</title>
|
|
|
+ <title>Two Main Types of Kernel Locks: Spinlocks and Mutexes</title>
|
|
|
|
|
|
<para>
|
|
|
- There are three main types of kernel locks. The fundamental type
|
|
|
+ There are two main types of kernel locks. The fundamental type
|
|
|
is the spinlock
|
|
|
(<filename class="headerfile">include/asm/spinlock.h</filename>),
|
|
|
which is a very simple single-holder lock: if you can't get the
|
|
@@ -239,14 +239,6 @@
|
|
|
can't sleep (see <xref linkend="sleeping-things"/>), and so have to
|
|
|
use a spinlock instead.
|
|
|
</para>
|
|
|
- <para>
|
|
|
- The third type is a semaphore
|
|
|
- (<filename class="headerfile">include/linux/semaphore.h</filename>): it
|
|
|
- can have more than one holder at any time (the number decided at
|
|
|
- initialization time), although it is most commonly used as a
|
|
|
- single-holder lock (a mutex). If you can't get a semaphore, your
|
|
|
- task will be suspended and later on woken up - just like for mutexes.
|
|
|
- </para>
|
|
|
<para>
|
|
|
Neither type of lock is recursive: see
|
|
|
<xref linkend="deadlock"/>.
|
|
@@ -278,7 +270,7 @@
|
|
|
</para>
|
|
|
|
|
|
<para>
|
|
|
- Semaphores still exist, because they are required for
|
|
|
+ Mutexes still exist, because they are required for
|
|
|
synchronization between <firstterm linkend="gloss-usercontext">user
|
|
|
contexts</firstterm>, as we will see below.
|
|
|
</para>
|
|
@@ -289,18 +281,17 @@
|
|
|
|
|
|
<para>
|
|
|
If you have a data structure which is only ever accessed from
|
|
|
- user context, then you can use a simple semaphore
|
|
|
- (<filename>linux/linux/semaphore.h</filename>) to protect it. This
|
|
|
- is the most trivial case: you initialize the semaphore to the number
|
|
|
- of resources available (usually 1), and call
|
|
|
- <function>down_interruptible()</function> to grab the semaphore, and
|
|
|
- <function>up()</function> to release it. There is also a
|
|
|
- <function>down()</function>, which should be avoided, because it
|
|
|
+ user context, then you can use a simple mutex
|
|
|
+ (<filename>include/linux/mutex.h</filename>) to protect it. This
|
|
|
+ is the most trivial case: you initialize the mutex. Then you can
|
|
|
+ call <function>mutex_lock_interruptible()</function> to grab the mutex,
|
|
|
+ and <function>mutex_unlock()</function> to release it. There is also a
|
|
|
+ <function>mutex_lock()</function>, which should be avoided, because it
|
|
|
will not return if a signal is received.
|
|
|
</para>
|
|
|
|
|
|
<para>
|
|
|
- Example: <filename>linux/net/core/netfilter.c</filename> allows
|
|
|
+ Example: <filename>net/netfilter/nf_sockopt.c</filename> allows
|
|
|
registration of new <function>setsockopt()</function> and
|
|
|
<function>getsockopt()</function> calls, with
|
|
|
<function>nf_register_sockopt()</function>. Registration and
|
|
@@ -515,7 +506,7 @@
|
|
|
<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
|
|
|
+ lock other process out, use a mutex. You can take a mutex
|
|
|
and sleep (<function>copy_from_user*(</function> or
|
|
|
<function>kmalloc(x,GFP_KERNEL)</function>).
|
|
|
</para>
|
|
@@ -662,7 +653,7 @@
|
|
|
<entry>SLBH</entry>
|
|
|
<entry>SLBH</entry>
|
|
|
<entry>SLBH</entry>
|
|
|
-<entry>DI</entry>
|
|
|
+<entry>MLI</entry>
|
|
|
<entry>None</entry>
|
|
|
</row>
|
|
|
|
|
@@ -692,8 +683,8 @@
|
|
|
<entry>spin_lock_bh</entry>
|
|
|
</row>
|
|
|
<row>
|
|
|
-<entry>DI</entry>
|
|
|
-<entry>down_interruptible</entry>
|
|
|
+<entry>MLI</entry>
|
|
|
+<entry>mutex_lock_interruptible</entry>
|
|
|
</row>
|
|
|
|
|
|
</tbody>
|
|
@@ -1310,7 +1301,7 @@ as Alan Cox says, <quote>Lock data, not code</quote>.
|
|
|
<para>
|
|
|
There is a coding bug where a piece of code tries to grab a
|
|
|
spinlock twice: it will spin forever, waiting for the lock to
|
|
|
- be released (spinlocks, rwlocks and semaphores are not
|
|
|
+ be released (spinlocks, rwlocks and mutexes are not
|
|
|
recursive in Linux). This is trivial to diagnose: not a
|
|
|
stay-up-five-nights-talk-to-fluffy-code-bunnies kind of
|
|
|
problem.
|
|
@@ -1335,7 +1326,7 @@ as Alan Cox says, <quote>Lock data, not code</quote>.
|
|
|
|
|
|
<para>
|
|
|
This complete lockup is easy to diagnose: on SMP boxes the
|
|
|
- watchdog timer or compiling with <symbol>DEBUG_SPINLOCKS</symbol> set
|
|
|
+ watchdog timer or compiling with <symbol>DEBUG_SPINLOCK</symbol> set
|
|
|
(<filename>include/linux/spinlock.h</filename>) will show this up
|
|
|
immediately when it happens.
|
|
|
</para>
|
|
@@ -1558,7 +1549,7 @@ the amount of locking which needs to be done.
|
|
|
<title>Read/Write Lock Variants</title>
|
|
|
|
|
|
<para>
|
|
|
- Both spinlocks and semaphores have read/write variants:
|
|
|
+ Both spinlocks and mutexes have read/write variants:
|
|
|
<type>rwlock_t</type> and <structname>struct rw_semaphore</structname>.
|
|
|
These divide users into two classes: the readers and the writers. If
|
|
|
you are only reading the data, you can get a read lock, but to write to
|
|
@@ -1681,7 +1672,7 @@ the amount of locking which needs to be done.
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/string.h>
|
|
|
+#include <linux/rcupdate.h>
|
|
|
- #include <linux/semaphore.h>
|
|
|
+ #include <linux/mutex.h>
|
|
|
#include <asm/errno.h>
|
|
|
|
|
|
struct object
|
|
@@ -1913,7 +1904,7 @@ machines due to caching.
|
|
|
</listitem>
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- <function> put_user()</function>
|
|
|
+ <function>put_user()</function>
|
|
|
</para>
|
|
|
</listitem>
|
|
|
</itemizedlist>
|
|
@@ -1927,13 +1918,13 @@ machines due to caching.
|
|
|
|
|
|
<listitem>
|
|
|
<para>
|
|
|
- <function>down_interruptible()</function> and
|
|
|
- <function>down()</function>
|
|
|
+ <function>mutex_lock_interruptible()</function> and
|
|
|
+ <function>mutex_lock()</function>
|
|
|
</para>
|
|
|
<para>
|
|
|
- There is a <function>down_trylock()</function> which can be
|
|
|
+ There is a <function>mutex_trylock()</function> which can be
|
|
|
used inside interrupt context, as it will not sleep.
|
|
|
- <function>up()</function> will also never sleep.
|
|
|
+ <function>mutex_unlock()</function> will also never sleep.
|
|
|
</para>
|
|
|
</listitem>
|
|
|
</itemizedlist>
|
|
@@ -2023,7 +2014,7 @@ machines due to caching.
|
|
|
<para>
|
|
|
Prior to 2.5, or when <symbol>CONFIG_PREEMPT</symbol> is
|
|
|
unset, processes in user context inside the kernel would not
|
|
|
- preempt each other (ie. you had that CPU until you have it up,
|
|
|
+ preempt each other (ie. you had that CPU until you gave it up,
|
|
|
except for interrupts). With the addition of
|
|
|
<symbol>CONFIG_PREEMPT</symbol> in 2.5.4, this changed: when
|
|
|
in user context, higher priority tasks can "cut in": spinlocks
|