Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.27-rc5 473 lines 11 kB view raw
1#ifndef __ARCH_X86_64_ATOMIC__ 2#define __ARCH_X86_64_ATOMIC__ 3 4#include <asm/alternative.h> 5#include <asm/cmpxchg.h> 6 7/* atomic_t should be 32 bit signed type */ 8 9/* 10 * Atomic operations that C can't guarantee us. Useful for 11 * resource counting etc.. 12 */ 13 14/* 15 * Make sure gcc doesn't try to be clever and move things around 16 * on us. We need to use _exactly_ the address the user gave us, 17 * not some alias that contains the same information. 18 */ 19typedef struct { 20 int counter; 21} atomic_t; 22 23#define ATOMIC_INIT(i) { (i) } 24 25/** 26 * atomic_read - read atomic variable 27 * @v: pointer of type atomic_t 28 * 29 * Atomically reads the value of @v. 30 */ 31#define atomic_read(v) ((v)->counter) 32 33/** 34 * atomic_set - set atomic variable 35 * @v: pointer of type atomic_t 36 * @i: required value 37 * 38 * Atomically sets the value of @v to @i. 39 */ 40#define atomic_set(v, i) (((v)->counter) = (i)) 41 42/** 43 * atomic_add - add integer to atomic variable 44 * @i: integer value to add 45 * @v: pointer of type atomic_t 46 * 47 * Atomically adds @i to @v. 48 */ 49static inline void atomic_add(int i, atomic_t *v) 50{ 51 asm volatile(LOCK_PREFIX "addl %1,%0" 52 : "=m" (v->counter) 53 : "ir" (i), "m" (v->counter)); 54} 55 56/** 57 * atomic_sub - subtract the atomic variable 58 * @i: integer value to subtract 59 * @v: pointer of type atomic_t 60 * 61 * Atomically subtracts @i from @v. 62 */ 63static inline void atomic_sub(int i, atomic_t *v) 64{ 65 asm volatile(LOCK_PREFIX "subl %1,%0" 66 : "=m" (v->counter) 67 : "ir" (i), "m" (v->counter)); 68} 69 70/** 71 * atomic_sub_and_test - subtract value from variable and test result 72 * @i: integer value to subtract 73 * @v: pointer of type atomic_t 74 * 75 * Atomically subtracts @i from @v and returns 76 * true if the result is zero, or false for all 77 * other cases. 78 */ 79static inline int atomic_sub_and_test(int i, atomic_t *v) 80{ 81 unsigned char c; 82 83 asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" 84 : "=m" (v->counter), "=qm" (c) 85 : "ir" (i), "m" (v->counter) : "memory"); 86 return c; 87} 88 89/** 90 * atomic_inc - increment atomic variable 91 * @v: pointer of type atomic_t 92 * 93 * Atomically increments @v by 1. 94 */ 95static inline void atomic_inc(atomic_t *v) 96{ 97 asm volatile(LOCK_PREFIX "incl %0" 98 : "=m" (v->counter) 99 : "m" (v->counter)); 100} 101 102/** 103 * atomic_dec - decrement atomic variable 104 * @v: pointer of type atomic_t 105 * 106 * Atomically decrements @v by 1. 107 */ 108static inline void atomic_dec(atomic_t *v) 109{ 110 asm volatile(LOCK_PREFIX "decl %0" 111 : "=m" (v->counter) 112 : "m" (v->counter)); 113} 114 115/** 116 * atomic_dec_and_test - decrement and test 117 * @v: pointer of type atomic_t 118 * 119 * Atomically decrements @v by 1 and 120 * returns true if the result is 0, or false for all other 121 * cases. 122 */ 123static inline int atomic_dec_and_test(atomic_t *v) 124{ 125 unsigned char c; 126 127 asm volatile(LOCK_PREFIX "decl %0; sete %1" 128 : "=m" (v->counter), "=qm" (c) 129 : "m" (v->counter) : "memory"); 130 return c != 0; 131} 132 133/** 134 * atomic_inc_and_test - increment and test 135 * @v: pointer of type atomic_t 136 * 137 * Atomically increments @v by 1 138 * and returns true if the result is zero, or false for all 139 * other cases. 140 */ 141static inline int atomic_inc_and_test(atomic_t *v) 142{ 143 unsigned char c; 144 145 asm volatile(LOCK_PREFIX "incl %0; sete %1" 146 : "=m" (v->counter), "=qm" (c) 147 : "m" (v->counter) : "memory"); 148 return c != 0; 149} 150 151/** 152 * atomic_add_negative - add and test if negative 153 * @i: integer value to add 154 * @v: pointer of type atomic_t 155 * 156 * Atomically adds @i to @v and returns true 157 * if the result is negative, or false when 158 * result is greater than or equal to zero. 159 */ 160static inline int atomic_add_negative(int i, atomic_t *v) 161{ 162 unsigned char c; 163 164 asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" 165 : "=m" (v->counter), "=qm" (c) 166 : "ir" (i), "m" (v->counter) : "memory"); 167 return c; 168} 169 170/** 171 * atomic_add_return - add and return 172 * @i: integer value to add 173 * @v: pointer of type atomic_t 174 * 175 * Atomically adds @i to @v and returns @i + @v 176 */ 177static inline int atomic_add_return(int i, atomic_t *v) 178{ 179 int __i = i; 180 asm volatile(LOCK_PREFIX "xaddl %0, %1" 181 : "+r" (i), "+m" (v->counter) 182 : : "memory"); 183 return i + __i; 184} 185 186static inline int atomic_sub_return(int i, atomic_t *v) 187{ 188 return atomic_add_return(-i, v); 189} 190 191#define atomic_inc_return(v) (atomic_add_return(1, v)) 192#define atomic_dec_return(v) (atomic_sub_return(1, v)) 193 194/* An 64bit atomic type */ 195 196typedef struct { 197 long counter; 198} atomic64_t; 199 200#define ATOMIC64_INIT(i) { (i) } 201 202/** 203 * atomic64_read - read atomic64 variable 204 * @v: pointer of type atomic64_t 205 * 206 * Atomically reads the value of @v. 207 * Doesn't imply a read memory barrier. 208 */ 209#define atomic64_read(v) ((v)->counter) 210 211/** 212 * atomic64_set - set atomic64 variable 213 * @v: pointer to type atomic64_t 214 * @i: required value 215 * 216 * Atomically sets the value of @v to @i. 217 */ 218#define atomic64_set(v, i) (((v)->counter) = (i)) 219 220/** 221 * atomic64_add - add integer to atomic64 variable 222 * @i: integer value to add 223 * @v: pointer to type atomic64_t 224 * 225 * Atomically adds @i to @v. 226 */ 227static inline void atomic64_add(long i, atomic64_t *v) 228{ 229 asm volatile(LOCK_PREFIX "addq %1,%0" 230 : "=m" (v->counter) 231 : "er" (i), "m" (v->counter)); 232} 233 234/** 235 * atomic64_sub - subtract the atomic64 variable 236 * @i: integer value to subtract 237 * @v: pointer to type atomic64_t 238 * 239 * Atomically subtracts @i from @v. 240 */ 241static inline void atomic64_sub(long i, atomic64_t *v) 242{ 243 asm volatile(LOCK_PREFIX "subq %1,%0" 244 : "=m" (v->counter) 245 : "er" (i), "m" (v->counter)); 246} 247 248/** 249 * atomic64_sub_and_test - subtract value from variable and test result 250 * @i: integer value to subtract 251 * @v: pointer to type atomic64_t 252 * 253 * Atomically subtracts @i from @v and returns 254 * true if the result is zero, or false for all 255 * other cases. 256 */ 257static inline int atomic64_sub_and_test(long i, atomic64_t *v) 258{ 259 unsigned char c; 260 261 asm volatile(LOCK_PREFIX "subq %2,%0; sete %1" 262 : "=m" (v->counter), "=qm" (c) 263 : "er" (i), "m" (v->counter) : "memory"); 264 return c; 265} 266 267/** 268 * atomic64_inc - increment atomic64 variable 269 * @v: pointer to type atomic64_t 270 * 271 * Atomically increments @v by 1. 272 */ 273static inline void atomic64_inc(atomic64_t *v) 274{ 275 asm volatile(LOCK_PREFIX "incq %0" 276 : "=m" (v->counter) 277 : "m" (v->counter)); 278} 279 280/** 281 * atomic64_dec - decrement atomic64 variable 282 * @v: pointer to type atomic64_t 283 * 284 * Atomically decrements @v by 1. 285 */ 286static inline void atomic64_dec(atomic64_t *v) 287{ 288 asm volatile(LOCK_PREFIX "decq %0" 289 : "=m" (v->counter) 290 : "m" (v->counter)); 291} 292 293/** 294 * atomic64_dec_and_test - decrement and test 295 * @v: pointer to type atomic64_t 296 * 297 * Atomically decrements @v by 1 and 298 * returns true if the result is 0, or false for all other 299 * cases. 300 */ 301static inline int atomic64_dec_and_test(atomic64_t *v) 302{ 303 unsigned char c; 304 305 asm volatile(LOCK_PREFIX "decq %0; sete %1" 306 : "=m" (v->counter), "=qm" (c) 307 : "m" (v->counter) : "memory"); 308 return c != 0; 309} 310 311/** 312 * atomic64_inc_and_test - increment and test 313 * @v: pointer to type atomic64_t 314 * 315 * Atomically increments @v by 1 316 * and returns true if the result is zero, or false for all 317 * other cases. 318 */ 319static inline int atomic64_inc_and_test(atomic64_t *v) 320{ 321 unsigned char c; 322 323 asm volatile(LOCK_PREFIX "incq %0; sete %1" 324 : "=m" (v->counter), "=qm" (c) 325 : "m" (v->counter) : "memory"); 326 return c != 0; 327} 328 329/** 330 * atomic64_add_negative - add and test if negative 331 * @i: integer value to add 332 * @v: pointer to type atomic64_t 333 * 334 * Atomically adds @i to @v and returns true 335 * if the result is negative, or false when 336 * result is greater than or equal to zero. 337 */ 338static inline int atomic64_add_negative(long i, atomic64_t *v) 339{ 340 unsigned char c; 341 342 asm volatile(LOCK_PREFIX "addq %2,%0; sets %1" 343 : "=m" (v->counter), "=qm" (c) 344 : "er" (i), "m" (v->counter) : "memory"); 345 return c; 346} 347 348/** 349 * atomic64_add_return - add and return 350 * @i: integer value to add 351 * @v: pointer to type atomic64_t 352 * 353 * Atomically adds @i to @v and returns @i + @v 354 */ 355static inline long atomic64_add_return(long i, atomic64_t *v) 356{ 357 long __i = i; 358 asm volatile(LOCK_PREFIX "xaddq %0, %1;" 359 : "+r" (i), "+m" (v->counter) 360 : : "memory"); 361 return i + __i; 362} 363 364static inline long atomic64_sub_return(long i, atomic64_t *v) 365{ 366 return atomic64_add_return(-i, v); 367} 368 369#define atomic64_inc_return(v) (atomic64_add_return(1, (v))) 370#define atomic64_dec_return(v) (atomic64_sub_return(1, (v))) 371 372#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 373#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 374 375#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 376#define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) 377 378/** 379 * atomic_add_unless - add unless the number is a given value 380 * @v: pointer of type atomic_t 381 * @a: the amount to add to v... 382 * @u: ...unless v is equal to u. 383 * 384 * Atomically adds @a to @v, so long as it was not @u. 385 * Returns non-zero if @v was not @u, and zero otherwise. 386 */ 387static inline int atomic_add_unless(atomic_t *v, int a, int u) 388{ 389 int c, old; 390 c = atomic_read(v); 391 for (;;) { 392 if (unlikely(c == (u))) 393 break; 394 old = atomic_cmpxchg((v), c, c + (a)); 395 if (likely(old == c)) 396 break; 397 c = old; 398 } 399 return c != (u); 400} 401 402#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 403 404/** 405 * atomic64_add_unless - add unless the number is a given value 406 * @v: pointer of type atomic64_t 407 * @a: the amount to add to v... 408 * @u: ...unless v is equal to u. 409 * 410 * Atomically adds @a to @v, so long as it was not @u. 411 * Returns non-zero if @v was not @u, and zero otherwise. 412 */ 413static inline int atomic64_add_unless(atomic64_t *v, long a, long u) 414{ 415 long c, old; 416 c = atomic64_read(v); 417 for (;;) { 418 if (unlikely(c == (u))) 419 break; 420 old = atomic64_cmpxchg((v), c, c + (a)); 421 if (likely(old == c)) 422 break; 423 c = old; 424 } 425 return c != (u); 426} 427 428/** 429 * atomic_inc_short - increment of a short integer 430 * @v: pointer to type int 431 * 432 * Atomically adds 1 to @v 433 * Returns the new value of @u 434 */ 435static inline short int atomic_inc_short(short int *v) 436{ 437 asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v)); 438 return *v; 439} 440 441/** 442 * atomic_or_long - OR of two long integers 443 * @v1: pointer to type unsigned long 444 * @v2: pointer to type unsigned long 445 * 446 * Atomically ORs @v1 and @v2 447 * Returns the result of the OR 448 */ 449static inline void atomic_or_long(unsigned long *v1, unsigned long v2) 450{ 451 asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); 452} 453 454#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) 455 456/* These are x86-specific, used by some header files */ 457#define atomic_clear_mask(mask, addr) \ 458 asm volatile(LOCK_PREFIX "andl %0,%1" \ 459 : : "r" (~(mask)), "m" (*(addr)) : "memory") 460 461#define atomic_set_mask(mask, addr) \ 462 asm volatile(LOCK_PREFIX "orl %0,%1" \ 463 : : "r" ((unsigned)(mask)), "m" (*(addr)) \ 464 : "memory") 465 466/* Atomic operations are already serializing on x86 */ 467#define smp_mb__before_atomic_dec() barrier() 468#define smp_mb__after_atomic_dec() barrier() 469#define smp_mb__before_atomic_inc() barrier() 470#define smp_mb__after_atomic_inc() barrier() 471 472#include <asm-generic/atomic.h> 473#endif