lglock: introduce special lglock and brlock spin locks
[linux-2.6.git] / include / linux / lglock.h
1 /*
2  * Specialised local-global spinlock. Can only be declared as global variables
3  * to avoid overhead and keep things simple (and we don't want to start using
4  * these inside dynamically allocated structures).
5  *
6  * "local/global locks" (lglocks) can be used to:
7  *
8  * - Provide fast exclusive access to per-CPU data, with exclusive access to
9  *   another CPU's data allowed but possibly subject to contention, and to
10  *   provide very slow exclusive access to all per-CPU data.
11  * - Or to provide very fast and scalable read serialisation, and to provide
12  *   very slow exclusive serialisation of data (not necessarily per-CPU data).
13  *
14  * Brlocks are also implemented as a short-hand notation for the latter use
15  * case.
16  *
17  * Copyright 2009, 2010, Nick Piggin, Novell Inc.
18  */
19 #ifndef __LINUX_LGLOCK_H
20 #define __LINUX_LGLOCK_H
21
22 #include <linux/spinlock.h>
23 #include <linux/lockdep.h>
24 #include <linux/percpu.h>
25
26 /* can make br locks by using local lock for read side, global lock for write */
27 #define br_lock_init(name)      name##_lock_init()
28 #define br_read_lock(name)      name##_local_lock()
29 #define br_read_unlock(name)    name##_local_unlock()
30 #define br_write_lock(name)     name##_global_lock_online()
31 #define br_write_unlock(name)   name##_global_unlock_online()
32
33 #define DECLARE_BRLOCK(name)    DECLARE_LGLOCK(name)
34 #define DEFINE_BRLOCK(name)     DEFINE_LGLOCK(name)
35
36
37 #define lg_lock_init(name)      name##_lock_init()
38 #define lg_local_lock(name)     name##_local_lock()
39 #define lg_local_unlock(name)   name##_local_unlock()
40 #define lg_local_lock_cpu(name, cpu)    name##_local_lock_cpu(cpu)
41 #define lg_local_unlock_cpu(name, cpu)  name##_local_unlock_cpu(cpu)
42 #define lg_global_lock(name)    name##_global_lock()
43 #define lg_global_unlock(name)  name##_global_unlock()
44 #define lg_global_lock_online(name) name##_global_lock_online()
45 #define lg_global_unlock_online(name) name##_global_unlock_online()
46
47 #ifdef CONFIG_DEBUG_LOCK_ALLOC
48 #define LOCKDEP_INIT_MAP lockdep_init_map
49
50 #define DEFINE_LGLOCK_LOCKDEP(name)                                     \
51  struct lock_class_key name##_lock_key;                                 \
52  struct lockdep_map name##_lock_dep_map;                                \
53  EXPORT_SYMBOL(name##_lock_dep_map)
54
55 #else
56 #define LOCKDEP_INIT_MAP(a, b, c, d)
57
58 #define DEFINE_LGLOCK_LOCKDEP(name)
59 #endif
60
61
62 #define DECLARE_LGLOCK(name)                                            \
63  extern void name##_lock_init(void);                                    \
64  extern void name##_local_lock(void);                                   \
65  extern void name##_local_unlock(void);                                 \
66  extern void name##_local_lock_cpu(int cpu);                            \
67  extern void name##_local_unlock_cpu(int cpu);                          \
68  extern void name##_global_lock(void);                                  \
69  extern void name##_global_unlock(void);                                \
70  extern void name##_global_lock_online(void);                           \
71  extern void name##_global_unlock_online(void);                         \
72
73 #define DEFINE_LGLOCK(name)                                             \
74                                                                         \
75  DEFINE_PER_CPU(arch_spinlock_t, name##_lock);                          \
76  DEFINE_LGLOCK_LOCKDEP(name);                                           \
77                                                                         \
78  void name##_lock_init(void) {                                          \
79         int i;                                                          \
80         LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \
81         for_each_possible_cpu(i) {                                      \
82                 arch_spinlock_t *lock;                                  \
83                 lock = &per_cpu(name##_lock, i);                        \
84                 *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;     \
85         }                                                               \
86  }                                                                      \
87  EXPORT_SYMBOL(name##_lock_init);                                       \
88                                                                         \
89  void name##_local_lock(void) {                                         \
90         arch_spinlock_t *lock;                                          \
91         preempt_disable();                                              \
92         rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_);     \
93         lock = &__get_cpu_var(name##_lock);                             \
94         arch_spin_lock(lock);                                           \
95  }                                                                      \
96  EXPORT_SYMBOL(name##_local_lock);                                      \
97                                                                         \
98  void name##_local_unlock(void) {                                       \
99         arch_spinlock_t *lock;                                          \
100         rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_);             \
101         lock = &__get_cpu_var(name##_lock);                             \
102         arch_spin_unlock(lock);                                         \
103         preempt_enable();                                               \
104  }                                                                      \
105  EXPORT_SYMBOL(name##_local_unlock);                                    \
106                                                                         \
107  void name##_local_lock_cpu(int cpu) {                                  \
108         arch_spinlock_t *lock;                                          \
109         preempt_disable();                                              \
110         rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_);     \
111         lock = &per_cpu(name##_lock, cpu);                              \
112         arch_spin_lock(lock);                                           \
113  }                                                                      \
114  EXPORT_SYMBOL(name##_local_lock_cpu);                                  \
115                                                                         \
116  void name##_local_unlock_cpu(int cpu) {                                \
117         arch_spinlock_t *lock;                                          \
118         rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_);             \
119         lock = &per_cpu(name##_lock, cpu);                              \
120         arch_spin_unlock(lock);                                         \
121         preempt_enable();                                               \
122  }                                                                      \
123  EXPORT_SYMBOL(name##_local_unlock_cpu);                                \
124                                                                         \
125  void name##_global_lock_online(void) {                                 \
126         int i;                                                          \
127         preempt_disable();                                              \
128         rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_);           \
129         for_each_online_cpu(i) {                                        \
130                 arch_spinlock_t *lock;                                  \
131                 lock = &per_cpu(name##_lock, i);                        \
132                 arch_spin_lock(lock);                                   \
133         }                                                               \
134  }                                                                      \
135  EXPORT_SYMBOL(name##_global_lock_online);                              \
136                                                                         \
137  void name##_global_unlock_online(void) {                               \
138         int i;                                                          \
139         rwlock_release(&name##_lock_dep_map, 1, _RET_IP_);              \
140         for_each_online_cpu(i) {                                        \
141                 arch_spinlock_t *lock;                                  \
142                 lock = &per_cpu(name##_lock, i);                        \
143                 arch_spin_unlock(lock);                                 \
144         }                                                               \
145         preempt_enable();                                               \
146  }                                                                      \
147  EXPORT_SYMBOL(name##_global_unlock_online);                            \
148                                                                         \
149  void name##_global_lock(void) {                                        \
150         int i;                                                          \
151         preempt_disable();                                              \
152         rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_);           \
153         for_each_online_cpu(i) {                                        \
154                 arch_spinlock_t *lock;                                  \
155                 lock = &per_cpu(name##_lock, i);                        \
156                 arch_spin_lock(lock);                                   \
157         }                                                               \
158  }                                                                      \
159  EXPORT_SYMBOL(name##_global_lock);                                     \
160                                                                         \
161  void name##_global_unlock(void) {                                      \
162         int i;                                                          \
163         rwlock_release(&name##_lock_dep_map, 1, _RET_IP_);              \
164         for_each_online_cpu(i) {                                        \
165                 arch_spinlock_t *lock;                                  \
166                 lock = &per_cpu(name##_lock, i);                        \
167                 arch_spin_unlock(lock);                                 \
168         }                                                               \
169         preempt_enable();                                               \
170  }                                                                      \
171  EXPORT_SYMBOL(name##_global_unlock);
172 #endif