X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=Documentation%2FDocBook%2Fkernel-locking.tmpl;h=77c42f40be5d66ecb0b2235ef3dd1300301eafa8;hb=e9b62693ae0a1e13ccc97a6792d9a7770c8d1b5b;hp=644c3884fab94eb22001e8876f20a36e7e1d7995;hpb=2e2d0dcc1bd7ca7c26ea5e29efb7f34bbd564f1c;p=safe%2Fjmp%2Flinux-2.6
diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
index 644c388..77c42f4 100644
--- a/Documentation/DocBook/kernel-locking.tmpl
+++ b/Documentation/DocBook/kernel-locking.tmpl
@@ -219,7 +219,7 @@
- Two Main Types of Kernel Locks: Spinlocks and Semaphores
+ Three Main Types of Kernel Locks: Spinlocks, Mutexes and Semaphores
There are three main types of kernel locks. The fundamental type
@@ -241,7 +241,7 @@
The third type is a semaphore
- (): it
+ (): 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
@@ -290,7 +290,7 @@
If you have a data structure which is only ever accessed from
user context, then you can use a simple semaphore
- (linux/asm/semaphore.h) to protect it. This
+ (linux/linux/semaphore.h) to protect it. This
is the most trivial case: you initialize the semaphore to the number
of resources available (usually 1), and call
down_interruptible() to grab the semaphore, and
@@ -551,10 +551,12 @@
spin_lock_irqsave(), which is a superset
of all other spinlock primitives.
+
Table of Locking Requirements
+
IRQ Handler A
@@ -576,97 +578,128 @@
IRQ Handler B
-spin_lock_irqsave
+SLIS
None
Softirq A
-spin_lock_irq
-spin_lock_irq
-spin_lock
+SLI
+SLI
+SL
Softirq B
-spin_lock_irq
-spin_lock_irq
-spin_lock
-spin_lock
+SLI
+SLI
+SL
+SL
Tasklet A
-spin_lock_irq
-spin_lock_irq
-spin_lock
-spin_lock
+SLI
+SLI
+SL
+SL
None
Tasklet B
-spin_lock_irq
-spin_lock_irq
-spin_lock
-spin_lock
-spin_lock
+SLI
+SLI
+SL
+SL
+SL
None
Timer A
-spin_lock_irq
-spin_lock_irq
-spin_lock
-spin_lock
-spin_lock
-spin_lock
+SLI
+SLI
+SL
+SL
+SL
+SL
None
Timer B
-spin_lock_irq
-spin_lock_irq
-spin_lock
-spin_lock
-spin_lock
-spin_lock
-spin_lock
+SLI
+SLI
+SL
+SL
+SL
+SL
+SL
None
User Context A
-spin_lock_irq
-spin_lock_irq
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
+SLI
+SLI
+SLBH
+SLBH
+SLBH
+SLBH
+SLBH
+SLBH
None
User Context B
+SLI
+SLI
+SLBH
+SLBH
+SLBH
+SLBH
+SLBH
+SLBH
+DI
+None
+
+
+
+
+
+
+
+Legend for Locking Requirements Table
+
+
+
+
+SLIS
+spin_lock_irqsave
+
+
+SLI
spin_lock_irq
-spin_lock_irq
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
-spin_lock_bh
+
+
+SL
+spin_lock
+
+
+SLBH
spin_lock_bh
+
+
+DI
down_interruptible
-None
+
@@ -684,7 +717,7 @@ used, and when it gets full, throws out the least used one.
For our first example, we assume that all operations are in user
context (ie. from system calls), so we can sleep. This means we can
-use a semaphore to protect the cache and all the objects within
+use a mutex to protect the cache and all the objects within
it. Here's the code:
@@ -692,7 +725,7 @@ it. Here's the code:
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/errno.h>
struct object
@@ -704,7 +737,7 @@ struct object
};
/* Protects the cache, cache_num, and the objects within it */
-static DECLARE_MUTEX(cache_lock);
+static DEFINE_MUTEX(cache_lock);
static LIST_HEAD(cache);
static unsigned int cache_num = 0;
#define MAX_CACHE_SIZE 10
@@ -756,17 +789,17 @@ int cache_add(int id, const char *name)
obj->id = id;
obj->popularity = 0;
- down(&cache_lock);
+ mutex_lock(&cache_lock);
__cache_add(obj);
- up(&cache_lock);
+ mutex_unlock(&cache_lock);
return 0;
}
void cache_delete(int id)
{
- down(&cache_lock);
+ mutex_lock(&cache_lock);
__cache_delete(__cache_find(id));
- up(&cache_lock);
+ mutex_unlock(&cache_lock);
}
int cache_find(int id, char *name)
@@ -774,13 +807,13 @@ int cache_find(int id, char *name)
struct object *obj;
int ret = -ENOENT;
- down(&cache_lock);
+ mutex_lock(&cache_lock);
obj = __cache_find(id);
if (obj) {
ret = 0;
strcpy(name, obj->name);
}
- up(&cache_lock);
+ mutex_unlock(&cache_lock);
return ret;
}
@@ -820,8 +853,8 @@ The change is shown below, in standard patch format: the
int popularity;
};
--static DECLARE_MUTEX(cache_lock);
-+static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED;
+-static DEFINE_MUTEX(cache_lock);
++static DEFINE_SPINLOCK(cache_lock);
static LIST_HEAD(cache);
static unsigned int cache_num = 0;
#define MAX_CACHE_SIZE 10
@@ -837,22 +870,22 @@ The change is shown below, in standard patch format: the
obj->id = id;
obj->popularity = 0;
-- down(&cache_lock);
+- mutex_lock(&cache_lock);
+ spin_lock_irqsave(&cache_lock, flags);
__cache_add(obj);
-- up(&cache_lock);
+- mutex_unlock(&cache_lock);
+ spin_unlock_irqrestore(&cache_lock, flags);
return 0;
}
void cache_delete(int id)
{
-- down(&cache_lock);
+- mutex_lock(&cache_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&cache_lock, flags);
__cache_delete(__cache_find(id));
-- up(&cache_lock);
+- mutex_unlock(&cache_lock);
+ spin_unlock_irqrestore(&cache_lock, flags);
}
@@ -862,14 +895,14 @@ The change is shown below, in standard patch format: the
int ret = -ENOENT;
+ unsigned long flags;
-- down(&cache_lock);
+- mutex_lock(&cache_lock);
+ spin_lock_irqsave(&cache_lock, flags);
obj = __cache_find(id);
if (obj) {
ret = 0;
strcpy(name, obj->name);
}
-- up(&cache_lock);
+- mutex_unlock(&cache_lock);
+ spin_unlock_irqrestore(&cache_lock, flags);
return ret;
}
@@ -1205,7 +1238,7 @@ Here is the "lock-per-object" implementation:
- int popularity;
};
- static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(cache_lock);
@@ -77,6 +84,7 @@
obj->id = id;
obj->popularity = 0;
@@ -1623,7 +1656,7 @@ the amount of locking which needs to be done.
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/rcupdate.h>
- #include <asm/semaphore.h>
+ #include <linux/semaphore.h>
#include <asm/errno.h>
struct object