~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/include/linux/brlock.h

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #ifndef __LINUX_BRLOCK_H
  2 #define __LINUX_BRLOCK_H
  3 
  4 /*
  5  * 'Big Reader' read-write spinlocks.
  6  *
  7  * super-fast read/write locks, with write-side penalty. The point
  8  * is to have a per-CPU read/write lock. Readers lock their CPU-local
  9  * readlock, writers must lock all locks to get write access. These
 10  * CPU-read-write locks are semantically identical to normal rwlocks.
 11  * Memory usage is higher as well. (NR_CPUS*L1_CACHE_BYTES bytes)
 12  *
 13  * The most important feature is that these spinlocks do not cause
 14  * cacheline ping-pong in the 'most readonly data' case.
 15  *
 16  * Copyright 2000, Ingo Molnar <mingo@redhat.com>
 17  *
 18  * Registry idea and naming [ crutial! :-) ] by:
 19  *
 20  *                 David S. Miller <davem@redhat.com>
 21  *
 22  * David has an implementation that doesnt use atomic operations in
 23  * the read branch via memory ordering tricks - i guess we need to
 24  * split this up into a per-arch thing? The atomicity issue is a
 25  * secondary item in profiles, at least on x86 platforms.
 26  *
 27  * The atomic op version overhead is indeed a big deal on
 28  * load-locked/store-conditional cpus (ALPHA/MIPS/PPC) and
 29  * compare-and-swap cpus (Sparc64).  So we control which
 30  * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM
 31  */
 32 
 33 /* Register bigreader lock indices here. */
 34 enum brlock_indices {
 35         BR_GLOBALIRQ_LOCK,
 36         BR_NETPROTO_LOCK,
 37 
 38         __BR_END
 39 };
 40 
 41 #include <linux/config.h>
 42 
 43 #ifdef CONFIG_SMP
 44 
 45 #include <linux/cache.h>
 46 #include <linux/spinlock.h>
 47 
 48 #if defined(__i386__) || defined(__ia64__)
 49 #define __BRLOCK_USE_ATOMICS
 50 #else
 51 #undef __BRLOCK_USE_ATOMICS
 52 #endif
 53 
 54 #ifdef __BRLOCK_USE_ATOMICS
 55 typedef rwlock_t        brlock_read_lock_t;
 56 #else
 57 typedef unsigned int    brlock_read_lock_t;
 58 #endif
 59 
 60 /*
 61  * align last allocated index to the next cacheline:
 62  */
 63 #define __BR_IDX_MAX \
 64         (((sizeof(brlock_read_lock_t)*__BR_END + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) / sizeof(brlock_read_lock_t))
 65 
 66 extern brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX];
 67 
 68 #ifndef __BRLOCK_USE_ATOMICS
 69 struct br_wrlock {
 70         spinlock_t lock;
 71 } __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
 72 
 73 extern struct br_wrlock __br_write_locks[__BR_IDX_MAX];
 74 #endif
 75 
 76 extern void __br_lock_usage_bug (void);
 77 
 78 #ifdef __BRLOCK_USE_ATOMICS
 79 
 80 static inline void br_read_lock (enum brlock_indices idx)
 81 {
 82         /*
 83          * This causes a link-time bug message if an
 84          * invalid index is used:
 85          */
 86         if (idx >= __BR_END)
 87                 __br_lock_usage_bug();
 88 
 89         read_lock(&__brlock_array[smp_processor_id()][idx]);
 90 }
 91 
 92 static inline void br_read_unlock (enum brlock_indices idx)
 93 {
 94         if (idx >= __BR_END)
 95                 __br_lock_usage_bug();
 96 
 97         read_unlock(&__brlock_array[smp_processor_id()][idx]);
 98 }
 99 
100 #else /* ! __BRLOCK_USE_ATOMICS */
101 static inline void br_read_lock (enum brlock_indices idx)
102 {
103         unsigned int *ctr;
104         spinlock_t *lock;
105 
106         /*
107          * This causes a link-time bug message if an
108          * invalid index is used:
109          */
110         if (idx >= __BR_END)
111                 __br_lock_usage_bug();
112 
113         ctr = &__brlock_array[smp_processor_id()][idx];
114         lock = &__br_write_locks[idx].lock;
115 again:
116         (*ctr)++;
117         mb();
118         if (spin_is_locked(lock)) {
119                 (*ctr)--;
120                 wmb(); /*
121                         * The release of the ctr must become visible
122                         * to the other cpus eventually thus wmb(),
123                         * we don't care if spin_is_locked is reordered
124                         * before the releasing of the ctr.
125                         * However IMHO this wmb() is superflous even in theory.
126                         * It would not be superflous only if on the
127                         * other CPUs doing a ldl_l instead of an ldl
128                         * would make a difference and I don't think this is
129                         * the case.
130                         * I'd like to clarify this issue further
131                         * but for now this is a slow path so adding the
132                         * wmb() will keep us on the safe side.
133                         */
134                 while (spin_is_locked(lock))
135                         barrier();
136                 goto again;
137         }
138 }
139 
140 static inline void br_read_unlock (enum brlock_indices idx)
141 {
142         unsigned int *ctr;
143 
144         if (idx >= __BR_END)
145                 __br_lock_usage_bug();
146 
147         ctr = &__brlock_array[smp_processor_id()][idx];
148 
149         wmb();
150         (*ctr)--;
151 }
152 #endif /* __BRLOCK_USE_ATOMICS */
153 
154 /* write path not inlined - it's rare and larger */
155 
156 extern void FASTCALL(__br_write_lock (enum brlock_indices idx));
157 extern void FASTCALL(__br_write_unlock (enum brlock_indices idx));
158 
159 static inline void br_write_lock (enum brlock_indices idx)
160 {
161         if (idx >= __BR_END)
162                 __br_lock_usage_bug();
163         __br_write_lock(idx);
164 }
165 
166 static inline void br_write_unlock (enum brlock_indices idx)
167 {
168         if (idx >= __BR_END)
169                 __br_lock_usage_bug();
170         __br_write_unlock(idx);
171 }
172 
173 #else
174 # define br_read_lock(idx)      ((void)(idx))
175 # define br_read_unlock(idx)    ((void)(idx))
176 # define br_write_lock(idx)     ((void)(idx))
177 # define br_write_unlock(idx)   ((void)(idx))
178 #endif
179 
180 /*
181  * Now enumerate all of the possible sw/hw IRQ protected
182  * versions of the interfaces.
183  */
184 #define br_read_lock_irqsave(idx, flags) \
185         do { local_irq_save(flags); br_read_lock(idx); } while (0)
186 
187 #define br_read_lock_irq(idx) \
188         do { local_irq_disable(); br_read_lock(idx); } while (0)
189 
190 #define br_read_lock_bh(idx) \
191         do { local_bh_disable(); br_read_lock(idx); } while (0)
192 
193 #define br_write_lock_irqsave(idx, flags) \
194         do { local_irq_save(flags); br_write_lock(idx); } while (0)
195 
196 #define br_write_lock_irq(idx) \
197         do { local_irq_disable(); br_write_lock(idx); } while (0)
198 
199 #define br_write_lock_bh(idx) \
200         do { local_bh_disable(); br_write_lock(idx); } while (0)
201 
202 #define br_read_unlock_irqrestore(idx, flags) \
203         do { br_read_unlock(irx); local_irq_restore(flags); } while (0)
204 
205 #define br_read_unlock_irq(idx) \
206         do { br_read_unlock(idx); local_irq_enable(); } while (0)
207 
208 #define br_read_unlock_bh(idx) \
209         do { br_read_unlock(idx); local_bh_enable(); } while (0)
210 
211 #define br_write_unlock_irqrestore(idx, flags) \
212         do { br_write_unlock(irx); local_irq_restore(flags); } while (0)
213 
214 #define br_write_unlock_irq(idx) \
215         do { br_write_unlock(idx); local_irq_enable(); } while (0)
216 
217 #define br_write_unlock_bh(idx) \
218         do { br_write_unlock(idx); local_bh_enable(); } while (0)
219 
220 #endif /* __LINUX_BRLOCK_H */
221 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.