Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.27-rc2 259 lines 6.0 kB view raw
1#ifndef __ARCH_I386_ATOMIC__ 2#define __ARCH_I386_ATOMIC__ 3 4#include <linux/compiler.h> 5#include <asm/processor.h> 6#include <asm/cmpxchg.h> 7 8/* 9 * Atomic operations that C can't guarantee us. Useful for 10 * resource counting etc.. 11 */ 12 13/* 14 * Make sure gcc doesn't try to be clever and move things around 15 * on us. We need to use _exactly_ the address the user gave us, 16 * not some alias that contains the same information. 17 */ 18typedef struct { 19 int counter; 20} atomic_t; 21 22#define ATOMIC_INIT(i) { (i) } 23 24/** 25 * atomic_read - read atomic variable 26 * @v: pointer of type atomic_t 27 * 28 * Atomically reads the value of @v. 29 */ 30#define atomic_read(v) ((v)->counter) 31 32/** 33 * atomic_set - set atomic variable 34 * @v: pointer of type atomic_t 35 * @i: required value 36 * 37 * Atomically sets the value of @v to @i. 38 */ 39#define atomic_set(v, i) (((v)->counter) = (i)) 40 41/** 42 * atomic_add - add integer to atomic variable 43 * @i: integer value to add 44 * @v: pointer of type atomic_t 45 * 46 * Atomically adds @i to @v. 47 */ 48static inline void atomic_add(int i, atomic_t *v) 49{ 50 asm volatile(LOCK_PREFIX "addl %1,%0" 51 : "+m" (v->counter) 52 : "ir" (i)); 53} 54 55/** 56 * atomic_sub - subtract integer from atomic variable 57 * @i: integer value to subtract 58 * @v: pointer of type atomic_t 59 * 60 * Atomically subtracts @i from @v. 61 */ 62static inline void atomic_sub(int i, atomic_t *v) 63{ 64 asm volatile(LOCK_PREFIX "subl %1,%0" 65 : "+m" (v->counter) 66 : "ir" (i)); 67} 68 69/** 70 * atomic_sub_and_test - subtract value from variable and test result 71 * @i: integer value to subtract 72 * @v: pointer of type atomic_t 73 * 74 * Atomically subtracts @i from @v and returns 75 * true if the result is zero, or false for all 76 * other cases. 77 */ 78static inline int atomic_sub_and_test(int i, atomic_t *v) 79{ 80 unsigned char c; 81 82 asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" 83 : "+m" (v->counter), "=qm" (c) 84 : "ir" (i) : "memory"); 85 return c; 86} 87 88/** 89 * atomic_inc - increment atomic variable 90 * @v: pointer of type atomic_t 91 * 92 * Atomically increments @v by 1. 93 */ 94static inline void atomic_inc(atomic_t *v) 95{ 96 asm volatile(LOCK_PREFIX "incl %0" 97 : "+m" (v->counter)); 98} 99 100/** 101 * atomic_dec - decrement atomic variable 102 * @v: pointer of type atomic_t 103 * 104 * Atomically decrements @v by 1. 105 */ 106static inline void atomic_dec(atomic_t *v) 107{ 108 asm volatile(LOCK_PREFIX "decl %0" 109 : "+m" (v->counter)); 110} 111 112/** 113 * atomic_dec_and_test - decrement and test 114 * @v: pointer of type atomic_t 115 * 116 * Atomically decrements @v by 1 and 117 * returns true if the result is 0, or false for all other 118 * cases. 119 */ 120static inline int atomic_dec_and_test(atomic_t *v) 121{ 122 unsigned char c; 123 124 asm volatile(LOCK_PREFIX "decl %0; sete %1" 125 : "+m" (v->counter), "=qm" (c) 126 : : "memory"); 127 return c != 0; 128} 129 130/** 131 * atomic_inc_and_test - increment and test 132 * @v: pointer of type atomic_t 133 * 134 * Atomically increments @v by 1 135 * and returns true if the result is zero, or false for all 136 * other cases. 137 */ 138static inline int atomic_inc_and_test(atomic_t *v) 139{ 140 unsigned char c; 141 142 asm volatile(LOCK_PREFIX "incl %0; sete %1" 143 : "+m" (v->counter), "=qm" (c) 144 : : "memory"); 145 return c != 0; 146} 147 148/** 149 * atomic_add_negative - add and test if negative 150 * @v: pointer of type atomic_t 151 * @i: integer value to add 152 * 153 * Atomically adds @i to @v and returns true 154 * if the result is negative, or false when 155 * result is greater than or equal to zero. 156 */ 157static inline int atomic_add_negative(int i, atomic_t *v) 158{ 159 unsigned char c; 160 161 asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" 162 : "+m" (v->counter), "=qm" (c) 163 : "ir" (i) : "memory"); 164 return c; 165} 166 167/** 168 * atomic_add_return - add integer and return 169 * @v: pointer of type atomic_t 170 * @i: integer value to add 171 * 172 * Atomically adds @i to @v and returns @i + @v 173 */ 174static inline int atomic_add_return(int i, atomic_t *v) 175{ 176 int __i; 177#ifdef CONFIG_M386 178 unsigned long flags; 179 if (unlikely(boot_cpu_data.x86 <= 3)) 180 goto no_xadd; 181#endif 182 /* Modern 486+ processor */ 183 __i = i; 184 asm volatile(LOCK_PREFIX "xaddl %0, %1" 185 : "+r" (i), "+m" (v->counter) 186 : : "memory"); 187 return i + __i; 188 189#ifdef CONFIG_M386 190no_xadd: /* Legacy 386 processor */ 191 local_irq_save(flags); 192 __i = atomic_read(v); 193 atomic_set(v, i + __i); 194 local_irq_restore(flags); 195 return i + __i; 196#endif 197} 198 199/** 200 * atomic_sub_return - subtract integer and return 201 * @v: pointer of type atomic_t 202 * @i: integer value to subtract 203 * 204 * Atomically subtracts @i from @v and returns @v - @i 205 */ 206static inline int atomic_sub_return(int i, atomic_t *v) 207{ 208 return atomic_add_return(-i, v); 209} 210 211#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 212#define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) 213 214/** 215 * atomic_add_unless - add unless the number is already a given value 216 * @v: pointer of type atomic_t 217 * @a: the amount to add to v... 218 * @u: ...unless v is equal to u. 219 * 220 * Atomically adds @a to @v, so long as @v was not already @u. 221 * Returns non-zero if @v was not @u, and zero otherwise. 222 */ 223static inline int atomic_add_unless(atomic_t *v, int a, int u) 224{ 225 int c, old; 226 c = atomic_read(v); 227 for (;;) { 228 if (unlikely(c == (u))) 229 break; 230 old = atomic_cmpxchg((v), c, c + (a)); 231 if (likely(old == c)) 232 break; 233 c = old; 234 } 235 return c != (u); 236} 237 238#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 239 240#define atomic_inc_return(v) (atomic_add_return(1, v)) 241#define atomic_dec_return(v) (atomic_sub_return(1, v)) 242 243/* These are x86-specific, used by some header files */ 244#define atomic_clear_mask(mask, addr) \ 245 asm volatile(LOCK_PREFIX "andl %0,%1" \ 246 : : "r" (~(mask)), "m" (*(addr)) : "memory") 247 248#define atomic_set_mask(mask, addr) \ 249 asm volatile(LOCK_PREFIX "orl %0,%1" \ 250 : : "r" (mask), "m" (*(addr)) : "memory") 251 252/* Atomic operations are already serializing on x86 */ 253#define smp_mb__before_atomic_dec() barrier() 254#define smp_mb__after_atomic_dec() barrier() 255#define smp_mb__before_atomic_inc() barrier() 256#define smp_mb__after_atomic_inc() barrier() 257 258#include <asm-generic/atomic.h> 259#endif