aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@swan.cs.unc.edu>2007-02-20 11:58:47 -0500
committerBjoern Brandenburg <bbb@swan.cs.unc.edu>2007-02-20 11:58:47 -0500
commitaab9254bb83d68824e5cb3f8e82cf2c6aad8acf4 (patch)
tree4b84523b831b5cbc6be8c605f60544bf8b035d9d
parentd8a908c44424ddf913a02a4d39d3da23f6756b01 (diff)
Implement queue locks based on the primitives provided atomic.h
This re-implements the queue locks for the new LITMUS version. Major differences to the previous implementation: 1) platform independent implementation - no manual assembly code in the queue lock implementation required 2) Recursive acquiring of the locks is not possible! None of the other Linux locking primitives allow it, so it is consistent and we weren't using it anyway as far as I know. 3) The number of "processes" in the implementation is fixed to NR_CPUS. Anything else doesn't really make sense in the kernel anyway.
-rw-r--r--include/linux/queuelock.h120
1 files changed, 88 insertions, 32 deletions
diff --git a/include/linux/queuelock.h b/include/linux/queuelock.h
index 044422b856..aaefdcaa4c 100644
--- a/include/linux/queuelock.h
+++ b/include/linux/queuelock.h
@@ -1,32 +1,88 @@
1#ifndef _UNC_QUEUE_LOCK_H_ 1#ifndef _UNC_QUEUELOCK_H_
2#define _UNC_QUEUE_LOCK_H_ 2#define _UNC_QUEUELOCK_H_
3/** 3/**
4* Queue lock 4* Queue lock
5* 5*
6* 6* This is an implementation of T. Anderson's queue lock.
7* CLEANUP: Q-Locks to be re-implemented properly for the new LITMUS. 7* It strives to follow the normal Linux locking conventions
8* Until then, we just use spin locks to make the code compile. 8* as much as possible. The rules for acquiring a lock are:
9*/ 9*
10 10* 1) The caller must ensure interrupts and preemptions are disabled.
11#include <linux/spinlock.h> 11*
12 12* 2) The caller _cannot_ recursively acquire the lock.
13typedef spinlock_t queuelock_t; 13*
14 14* 3) The caller may not sleep while holding the lock. This is currently
15 15* not enforced, but it will not work.
16 16*/
17/* The new linux-like queue lock API. 17
18 18#include <linux/spinlock.h>
19 int init_queuelock(queuelock_t* lock, int num_procs); 19#include <linux/cache.h>
20 void queue_lock_wipe(queuelock_t * lock); 20#include <asm/atomic.h>
21 void queue_lock(queuelock_t *); 21#include <linux/cpumask.h>
22 void queue_unlock(queuelock_t *); 22#include <linux/smp.h>
23 23
24*/ 24typedef struct {
25 25 /* pad the values being spun on to make sure
26 26 that they are cache local
27#define queue_lock_init(lock) spin_lock_init(lock) 27 */
28#define queue_lock_wipe(lock) spin_lock_init(lock) 28 union {
29#define queue_lock(lock) spin_lock(lock) 29 enum {
30#define queue_unlock(lock) spin_unlock(lock) 30 MUST_WAIT,
31 31 HAS_LOCK
32#endif /* _UNC_QUEUE_LOCK_H_ */ 32 } val;
33 char padding[SMP_CACHE_BYTES];
34 } slots[NR_CPUS];
35
36 /* since spin_slot is not being spun on it can be
37 * in a shared cache line. next_slot will be evicted
38 * anyway on every attempt to acquire the lock.
39 */
40 int spin_slot[NR_CPUS];
41
42 /* The next slot that will be available.
43 */
44 atomic_t next_slot;
45} queuelock_t;
46
47
48static inline void queue_lock_init(queuelock_t *lock)
49{
50 int i;
51 for_each_possible_cpu(i) {
52 lock->slots[i].val = MUST_WAIT;
53 lock->spin_slot[i] = i;
54 }
55 lock->slots[i].val = HAS_LOCK;
56 atomic_set(&lock->next_slot, 0);
57}
58
59
60static inline void queue_lock(queuelock_t *lock)
61{
62 int me = smp_processor_id();
63 /* Get slot to spin on. atomic_inc_return() returns the incremented
64 * value, so take one of again
65 */
66 lock->spin_slot[me] = atomic_inc_return(&lock->next_slot) - 1;
67 /* check for wrap-around
68 * This could probably optimized away if we ensure that NR_CPUS divides
69 * INT_MAX...
70 */
71 if (unlikely(lock->spin_slot[me] == NR_CPUS - 1))
72 atomic_add(-NR_CPUS, &lock->next_slot);
73 /* range limit*/
74 lock->spin_slot[me] %= NR_CPUS;
75 /* spin until you acquire the lock */
76 while (lock->slots[lock->spin_slot[me]].val == MUST_WAIT);
77 /* reset the lock */
78 lock->slots[lock->spin_slot[me]].val = MUST_WAIT;
79}
80
81
82static inline void queue_unlock(queuelock_t *lock)
83{
84 int me = smp_processor_id();
85 lock->slots[(lock->spin_slot[me] + 1) % NR_CPUS].val = HAS_LOCK;
86}
87
88#endif /* _UNC_QUEUELOCK_H_ */