Commit 560cb12a4080a48b84da8b96878cafbd193c4d64

Authored by Peter Zijlstra
Committed by Ingo Molnar
1 parent d4608dd5b4

locking,arch: Rewrite generic atomic support

Rewrite generic atomic support to only require cmpxchg(), generate all
other primitives from that.

Furthermore reduce the endless repetition for all these primitives to
a few CPP macros. This way we get more for less lines.

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140508135852.940119622@infradead.org
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-arch@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

Showing 3 changed files with 148 additions and 147 deletions Side-by-side Diff

include/asm-generic/atomic.h
... ... @@ -18,14 +18,100 @@
18 18 #include <asm/cmpxchg.h>
19 19 #include <asm/barrier.h>
20 20  
  21 +/*
  22 + * atomic_$op() - $op integer to atomic variable
  23 + * @i: integer value to $op
  24 + * @v: pointer to the atomic variable
  25 + *
  26 + * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use
  27 + * smp_mb__{before,after}_atomic().
  28 + */
  29 +
  30 +/*
  31 + * atomic_$op_return() - $op interer to atomic variable and returns the result
  32 + * @i: integer value to $op
  33 + * @v: pointer to the atomic variable
  34 + *
  35 + * Atomically $ops @i to @v. Does imply a full memory barrier.
  36 + */
  37 +
21 38 #ifdef CONFIG_SMP
22   -/* Force people to define core atomics */
23   -# if !defined(atomic_add_return) || !defined(atomic_sub_return) || \
24   - !defined(atomic_clear_mask) || !defined(atomic_set_mask)
25   -# error "SMP requires a little arch-specific magic"
26   -# endif
  39 +
  40 +/* we can build all atomic primitives from cmpxchg */
  41 +
  42 +#define ATOMIC_OP(op, c_op) \
  43 +static inline void atomic_##op(int i, atomic_t *v) \
  44 +{ \
  45 + int c, old; \
  46 + \
  47 + c = v->counter; \
  48 + while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \
  49 + c = old; \
  50 +}
  51 +
  52 +#define ATOMIC_OP_RETURN(op, c_op) \
  53 +static inline int atomic_##op##_return(int i, atomic_t *v) \
  54 +{ \
  55 + int c, old; \
  56 + \
  57 + c = v->counter; \
  58 + while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \
  59 + c = old; \
  60 + \
  61 + return c c_op i; \
  62 +}
  63 +
  64 +#else
  65 +
  66 +#include <linux/irqflags.h>
  67 +
  68 +#define ATOMIC_OP(op, c_op) \
  69 +static inline void atomic_##op(int i, atomic_t *v) \
  70 +{ \
  71 + unsigned long flags; \
  72 + \
  73 + raw_local_irq_save(flags); \
  74 + v->counter = v->counter c_op i; \
  75 + raw_local_irq_restore(flags); \
  76 +}
  77 +
  78 +#define ATOMIC_OP_RETURN(op, c_op) \
  79 +static inline int atomic_##op##_return(int i, atomic_t *v) \
  80 +{ \
  81 + unsigned long flags; \
  82 + int ret; \
  83 + \
  84 + raw_local_irq_save(flags); \
  85 + ret = (v->counter = v->counter c_op i); \
  86 + raw_local_irq_restore(flags); \
  87 + \
  88 + return ret; \
  89 +}
  90 +
  91 +#endif /* CONFIG_SMP */
  92 +
  93 +#ifndef atomic_add_return
  94 +ATOMIC_OP_RETURN(add, +)
27 95 #endif
28 96  
  97 +#ifndef atomic_sub_return
  98 +ATOMIC_OP_RETURN(sub, -)
  99 +#endif
  100 +
  101 +#ifndef atomic_clear_mask
  102 +ATOMIC_OP(and, &)
  103 +#define atomic_clear_mask(i, v) atomic_and(~(i), (v))
  104 +#endif
  105 +
  106 +#ifndef atomic_set_mask
  107 +#define CONFIG_ARCH_HAS_ATOMIC_OR
  108 +ATOMIC_OP(or, |)
  109 +#define atomic_set_mask(i, v) atomic_or((i), (v))
  110 +#endif
  111 +
  112 +#undef ATOMIC_OP_RETURN
  113 +#undef ATOMIC_OP
  114 +
29 115 /*
30 116 * Atomic operations that C can't guarantee us. Useful for
31 117 * resource counting etc..
... ... @@ -33,8 +119,6 @@
33 119  
34 120 #define ATOMIC_INIT(i) { (i) }
35 121  
36   -#ifdef __KERNEL__
37   -
38 122 /**
39 123 * atomic_read - read atomic variable
40 124 * @v: pointer of type atomic_t
... ... @@ -56,52 +140,6 @@
56 140  
57 141 #include <linux/irqflags.h>
58 142  
59   -/**
60   - * atomic_add_return - add integer to atomic variable
61   - * @i: integer value to add
62   - * @v: pointer of type atomic_t
63   - *
64   - * Atomically adds @i to @v and returns the result
65   - */
66   -#ifndef atomic_add_return
67   -static inline int atomic_add_return(int i, atomic_t *v)
68   -{
69   - unsigned long flags;
70   - int temp;
71   -
72   - raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */
73   - temp = v->counter;
74   - temp += i;
75   - v->counter = temp;
76   - raw_local_irq_restore(flags);
77   -
78   - return temp;
79   -}
80   -#endif
81   -
82   -/**
83   - * atomic_sub_return - subtract integer from atomic variable
84   - * @i: integer value to subtract
85   - * @v: pointer of type atomic_t
86   - *
87   - * Atomically subtracts @i from @v and returns the result
88   - */
89   -#ifndef atomic_sub_return
90   -static inline int atomic_sub_return(int i, atomic_t *v)
91   -{
92   - unsigned long flags;
93   - int temp;
94   -
95   - raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */
96   - temp = v->counter;
97   - temp -= i;
98   - v->counter = temp;
99   - raw_local_irq_restore(flags);
100   -
101   - return temp;
102   -}
103   -#endif
104   -
105 143 static inline int atomic_add_negative(int i, atomic_t *v)
106 144 {
107 145 return atomic_add_return(i, v) < 0;
108 146  
... ... @@ -139,50 +177,12 @@
139 177  
140 178 static inline int __atomic_add_unless(atomic_t *v, int a, int u)
141 179 {
142   - int c, old;
143   - c = atomic_read(v);
144   - while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c)
145   - c = old;
146   - return c;
  180 + int c, old;
  181 + c = atomic_read(v);
  182 + while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c)
  183 + c = old;
  184 + return c;
147 185 }
148 186  
149   -/**
150   - * atomic_clear_mask - Atomically clear bits in atomic variable
151   - * @mask: Mask of the bits to be cleared
152   - * @v: pointer of type atomic_t
153   - *
154   - * Atomically clears the bits set in @mask from @v
155   - */
156   -#ifndef atomic_clear_mask
157   -static inline void atomic_clear_mask(unsigned long mask, atomic_t *v)
158   -{
159   - unsigned long flags;
160   -
161   - mask = ~mask;
162   - raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */
163   - v->counter &= mask;
164   - raw_local_irq_restore(flags);
165   -}
166   -#endif
167   -
168   -/**
169   - * atomic_set_mask - Atomically set bits in atomic variable
170   - * @mask: Mask of the bits to be set
171   - * @v: pointer of type atomic_t
172   - *
173   - * Atomically sets the bits set in @mask in @v
174   - */
175   -#ifndef atomic_set_mask
176   -static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
177   -{
178   - unsigned long flags;
179   -
180   - raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */
181   - v->counter |= mask;
182   - raw_local_irq_restore(flags);
183   -}
184   -#endif
185   -
186   -#endif /* __KERNEL__ */
187 187 #endif /* __ASM_GENERIC_ATOMIC_H */
include/asm-generic/atomic64.h
... ... @@ -20,10 +20,22 @@
20 20  
21 21 extern long long atomic64_read(const atomic64_t *v);
22 22 extern void atomic64_set(atomic64_t *v, long long i);
23   -extern void atomic64_add(long long a, atomic64_t *v);
24   -extern long long atomic64_add_return(long long a, atomic64_t *v);
25   -extern void atomic64_sub(long long a, atomic64_t *v);
26   -extern long long atomic64_sub_return(long long a, atomic64_t *v);
  23 +
  24 +#define ATOMIC64_OP(op) \
  25 +extern void atomic64_##op(long long a, atomic64_t *v);
  26 +
  27 +#define ATOMIC64_OP_RETURN(op) \
  28 +extern long long atomic64_##op##_return(long long a, atomic64_t *v);
  29 +
  30 +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op)
  31 +
  32 +ATOMIC64_OPS(add)
  33 +ATOMIC64_OPS(sub)
  34 +
  35 +#undef ATOMIC64_OPS
  36 +#undef ATOMIC64_OP_RETURN
  37 +#undef ATOMIC64_OP
  38 +
27 39 extern long long atomic64_dec_if_positive(atomic64_t *v);
28 40 extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n);
29 41 extern long long atomic64_xchg(atomic64_t *v, long long new);
... ... @@ -70,53 +70,42 @@
70 70 }
71 71 EXPORT_SYMBOL(atomic64_set);
72 72  
73   -void atomic64_add(long long a, atomic64_t *v)
74   -{
75   - unsigned long flags;
76   - raw_spinlock_t *lock = lock_addr(v);
  73 +#define ATOMIC64_OP(op, c_op) \
  74 +void atomic64_##op(long long a, atomic64_t *v) \
  75 +{ \
  76 + unsigned long flags; \
  77 + raw_spinlock_t *lock = lock_addr(v); \
  78 + \
  79 + raw_spin_lock_irqsave(lock, flags); \
  80 + v->counter c_op a; \
  81 + raw_spin_unlock_irqrestore(lock, flags); \
  82 +} \
  83 +EXPORT_SYMBOL(atomic64_##op);
77 84  
78   - raw_spin_lock_irqsave(lock, flags);
79   - v->counter += a;
80   - raw_spin_unlock_irqrestore(lock, flags);
81   -}
82   -EXPORT_SYMBOL(atomic64_add);
  85 +#define ATOMIC64_OP_RETURN(op, c_op) \
  86 +long long atomic64_##op##_return(long long a, atomic64_t *v) \
  87 +{ \
  88 + unsigned long flags; \
  89 + raw_spinlock_t *lock = lock_addr(v); \
  90 + long long val; \
  91 + \
  92 + raw_spin_lock_irqsave(lock, flags); \
  93 + val = (v->counter c_op a); \
  94 + raw_spin_unlock_irqrestore(lock, flags); \
  95 + return val; \
  96 +} \
  97 +EXPORT_SYMBOL(atomic64_##op##_return);
83 98  
84   -long long atomic64_add_return(long long a, atomic64_t *v)
85   -{
86   - unsigned long flags;
87   - raw_spinlock_t *lock = lock_addr(v);
88   - long long val;
  99 +#define ATOMIC64_OPS(op, c_op) \
  100 + ATOMIC64_OP(op, c_op) \
  101 + ATOMIC64_OP_RETURN(op, c_op)
89 102  
90   - raw_spin_lock_irqsave(lock, flags);
91   - val = v->counter += a;
92   - raw_spin_unlock_irqrestore(lock, flags);
93   - return val;
94   -}
95   -EXPORT_SYMBOL(atomic64_add_return);
  103 +ATOMIC64_OPS(add, +=)
  104 +ATOMIC64_OPS(sub, -=)
96 105  
97   -void atomic64_sub(long long a, atomic64_t *v)
98   -{
99   - unsigned long flags;
100   - raw_spinlock_t *lock = lock_addr(v);
101   -
102   - raw_spin_lock_irqsave(lock, flags);
103   - v->counter -= a;
104   - raw_spin_unlock_irqrestore(lock, flags);
105   -}
106   -EXPORT_SYMBOL(atomic64_sub);
107   -
108   -long long atomic64_sub_return(long long a, atomic64_t *v)
109   -{
110   - unsigned long flags;
111   - raw_spinlock_t *lock = lock_addr(v);
112   - long long val;
113   -
114   - raw_spin_lock_irqsave(lock, flags);
115   - val = v->counter -= a;
116   - raw_spin_unlock_irqrestore(lock, flags);
117   - return val;
118   -}
119   -EXPORT_SYMBOL(atomic64_sub_return);
  106 +#undef ATOMIC64_OPS
  107 +#undef ATOMIC64_OP_RETURN
  108 +#undef ATOMIC64_OP
120 109  
121 110 long long atomic64_dec_if_positive(atomic64_t *v)
122 111 {