linux/arch/x86/include/asm/atomic_32.h
<<
>>
Prefs
   1#ifndef _ASM_X86_ATOMIC_32_H
   2#define _ASM_X86_ATOMIC_32_H
   3
   4#include <linux/compiler.h>
   5#include <linux/types.h>
   6#include <asm/processor.h>
   7#include <asm/cmpxchg.h>
   8
   9/*
  10 * Atomic operations that C can't guarantee us.  Useful for
  11 * resource counting etc..
  12 */
  13
  14#define ATOMIC_INIT(i)  { (i) }
  15
  16/**
  17 * atomic_read - read atomic variable
  18 * @v: pointer of type atomic_t
  19 *
  20 * Atomically reads the value of @v.
  21 */
  22static inline int atomic_read(const atomic_t *v)
  23{
  24        return v->counter;
  25}
  26
  27/**
  28 * atomic_set - set atomic variable
  29 * @v: pointer of type atomic_t
  30 * @i: required value
  31 *
  32 * Atomically sets the value of @v to @i.
  33 */
  34static inline void atomic_set(atomic_t *v, int i)
  35{
  36        v->counter = i;
  37}
  38
  39/**
  40 * atomic_add - add integer to atomic variable
  41 * @i: integer value to add
  42 * @v: pointer of type atomic_t
  43 *
  44 * Atomically adds @i to @v.
  45 */
  46static inline void atomic_add(int i, atomic_t *v)
  47{
  48        asm volatile(LOCK_PREFIX "addl %1,%0"
  49                     : "+m" (v->counter)
  50                     : "ir" (i));
  51}
  52
  53/**
  54 * atomic_sub - subtract integer from atomic variable
  55 * @i: integer value to subtract
  56 * @v: pointer of type atomic_t
  57 *
  58 * Atomically subtracts @i from @v.
  59 */
  60static inline void atomic_sub(int i, atomic_t *v)
  61{
  62        asm volatile(LOCK_PREFIX "subl %1,%0"
  63                     : "+m" (v->counter)
  64                     : "ir" (i));
  65}
  66
  67/**
  68 * atomic_sub_and_test - subtract value from variable and test result
  69 * @i: integer value to subtract
  70 * @v: pointer of type atomic_t
  71 *
  72 * Atomically subtracts @i from @v and returns
  73 * true if the result is zero, or false for all
  74 * other cases.
  75 */
  76static inline int atomic_sub_and_test(int i, atomic_t *v)
  77{
  78        unsigned char c;
  79
  80        asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
  81                     : "+m" (v->counter), "=qm" (c)
  82                     : "ir" (i) : "memory");
  83        return c;
  84}
  85
  86/**
  87 * atomic_inc - increment atomic variable
  88 * @v: pointer of type atomic_t
  89 *
  90 * Atomically increments @v by 1.
  91 */
  92static inline void atomic_inc(atomic_t *v)
  93{
  94        asm volatile(LOCK_PREFIX "incl %0"
  95                     : "+m" (v->counter));
  96}
  97
  98/**
  99 * atomic_dec - decrement atomic variable
 100 * @v: pointer of type atomic_t
 101 *
 102 * Atomically decrements @v by 1.
 103 */
 104static inline void atomic_dec(atomic_t *v)
 105{
 106        asm volatile(LOCK_PREFIX "decl %0"
 107                     : "+m" (v->counter));
 108}
 109
 110/**
 111 * atomic_dec_and_test - decrement and test
 112 * @v: pointer of type atomic_t
 113 *
 114 * Atomically decrements @v by 1 and
 115 * returns true if the result is 0, or false for all other
 116 * cases.
 117 */
 118static inline int atomic_dec_and_test(atomic_t *v)
 119{
 120        unsigned char c;
 121
 122        asm volatile(LOCK_PREFIX "decl %0; sete %1"
 123                     : "+m" (v->counter), "=qm" (c)
 124                     : : "memory");
 125        return c != 0;
 126}
 127
 128/**
 129 * atomic_inc_and_test - increment and test
 130 * @v: pointer of type atomic_t
 131 *
 132 * Atomically increments @v by 1
 133 * and returns true if the result is zero, or false for all
 134 * other cases.
 135 */
 136static inline int atomic_inc_and_test(atomic_t *v)
 137{
 138        unsigned char c;
 139
 140        asm volatile(LOCK_PREFIX "incl %0; sete %1"
 141                     : "+m" (v->counter), "=qm" (c)
 142                     : : "memory");
 143        return c != 0;
 144}
 145
 146/**
 147 * atomic_add_negative - add and test if negative
 148 * @v: pointer of type atomic_t
 149 * @i: integer value to add
 150 *
 151 * Atomically adds @i to @v and returns true
 152 * if the result is negative, or false when
 153 * result is greater than or equal to zero.
 154 */
 155static inline int atomic_add_negative(int i, atomic_t *v)
 156{
 157        unsigned char c;
 158
 159        asm volatile(LOCK_PREFIX "addl %2,%0; sets %1"
 160                     : "+m" (v->counter), "=qm" (c)
 161                     : "ir" (i) : "memory");
 162        return c;
 163}
 164
 165/**
 166 * atomic_add_return - add integer and return
 167 * @v: pointer of type atomic_t
 168 * @i: integer value to add
 169 *
 170 * Atomically adds @i to @v and returns @i + @v
 171 */
 172static inline int atomic_add_return(int i, atomic_t *v)
 173{
 174        int __i;
 175#ifdef CONFIG_M386
 176        unsigned long flags;
 177        if (unlikely(boot_cpu_data.x86 <= 3))
 178                goto no_xadd;
 179#endif
 180        /* Modern 486+ processor */
 181        __i = i;
 182        asm volatile(LOCK_PREFIX "xaddl %0, %1"
 183                     : "+r" (i), "+m" (v->counter)
 184                     : : "memory");
 185        return i + __i;
 186
 187#ifdef CONFIG_M386
 188no_xadd: /* Legacy 386 processor */
 189        local_irq_save(flags);
 190        __i = atomic_read(v);
 191        atomic_set(v, i + __i);
 192        local_irq_restore(flags);
 193        return i + __i;
 194#endif
 195}
 196
 197/**
 198 * atomic_sub_return - subtract integer and return
 199 * @v: pointer of type atomic_t
 200 * @i: integer value to subtract
 201 *
 202 * Atomically subtracts @i from @v and returns @v - @i
 203 */
 204static inline int atomic_sub_return(int i, atomic_t *v)
 205{
 206        return atomic_add_return(-i, v);
 207}
 208
 209static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 210{
 211        return cmpxchg(&v->counter, old, new);
 212}
 213
 214static inline int atomic_xchg(atomic_t *v, int new)
 215{
 216        return xchg(&v->counter, new);
 217}
 218
 219/**
 220 * atomic_add_unless - add unless the number is already a given value
 221 * @v: pointer of type atomic_t
 222 * @a: the amount to add to v...
 223 * @u: ...unless v is equal to u.
 224 *
 225 * Atomically adds @a to @v, so long as @v was not already @u.
 226 * Returns non-zero if @v was not @u, and zero otherwise.
 227 */
 228static inline int atomic_add_unless(atomic_t *v, int a, int u)
 229{
 230        int c, old;
 231        c = atomic_read(v);
 232        for (;;) {
 233                if (unlikely(c == (u)))
 234                        break;
 235                old = atomic_cmpxchg((v), c, c + (a));
 236                if (likely(old == c))
 237                        break;
 238                c = old;
 239        }
 240        return c != (u);
 241}
 242
 243#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 244
 245#define atomic_inc_return(v)  (atomic_add_return(1, v))
 246#define atomic_dec_return(v)  (atomic_sub_return(1, v))
 247
 248/* These are x86-specific, used by some header files */
 249#define atomic_clear_mask(mask, addr)                           \
 250        asm volatile(LOCK_PREFIX "andl %0,%1"                   \
 251                     : : "r" (~(mask)), "m" (*(addr)) : "memory")
 252
 253#define atomic_set_mask(mask, addr)                             \
 254        asm volatile(LOCK_PREFIX "orl %0,%1"                            \
 255                     : : "r" (mask), "m" (*(addr)) : "memory")
 256
 257/* Atomic operations are already serializing on x86 */
 258#define smp_mb__before_atomic_dec()     barrier()
 259#define smp_mb__after_atomic_dec()      barrier()
 260#define smp_mb__before_atomic_inc()     barrier()
 261#define smp_mb__after_atomic_inc()      barrier()
 262
 263/* An 64bit atomic type */
 264
 265typedef struct {
 266        u64 __aligned(8) counter;
 267} atomic64_t;
 268
 269#define ATOMIC64_INIT(val)      { (val) }
 270
 271extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val);
 272
 273/**
 274 * atomic64_xchg - xchg atomic64 variable
 275 * @ptr:      pointer to type atomic64_t
 276 * @new_val:  value to assign
 277 *
 278 * Atomically xchgs the value of @ptr to @new_val and returns
 279 * the old value.
 280 */
 281extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val);
 282
 283/**
 284 * atomic64_set - set atomic64 variable
 285 * @ptr:      pointer to type atomic64_t
 286 * @new_val:  value to assign
 287 *
 288 * Atomically sets the value of @ptr to @new_val.
 289 */
 290extern void atomic64_set(atomic64_t *ptr, u64 new_val);
 291
 292/**
 293 * atomic64_read - read atomic64 variable
 294 * @ptr:      pointer to type atomic64_t
 295 *
 296 * Atomically reads the value of @ptr and returns it.
 297 */
 298static inline u64 atomic64_read(atomic64_t *ptr)
 299{
 300        u64 res;
 301
 302        /*
 303         * Note, we inline this atomic64_t primitive because
 304         * it only clobbers EAX/EDX and leaves the others
 305         * untouched. We also (somewhat subtly) rely on the
 306         * fact that cmpxchg8b returns the current 64-bit value
 307         * of the memory location we are touching:
 308         */
 309        asm volatile(
 310                "mov %%ebx, %%eax\n\t"
 311                "mov %%ecx, %%edx\n\t"
 312                LOCK_PREFIX "cmpxchg8b %1\n"
 313                        : "=&A" (res)
 314                        : "m" (*ptr)
 315                );
 316
 317        return res;
 318}
 319
 320extern u64 atomic64_read(atomic64_t *ptr);
 321
 322/**
 323 * atomic64_add_return - add and return
 324 * @delta: integer value to add
 325 * @ptr:   pointer to type atomic64_t
 326 *
 327 * Atomically adds @delta to @ptr and returns @delta + *@ptr
 328 */
 329extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr);
 330
 331/*
 332 * Other variants with different arithmetic operators:
 333 */
 334extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr);
 335extern u64 atomic64_inc_return(atomic64_t *ptr);
 336extern u64 atomic64_dec_return(atomic64_t *ptr);
 337
 338/**
 339 * atomic64_add - add integer to atomic64 variable
 340 * @delta: integer value to add
 341 * @ptr:   pointer to type atomic64_t
 342 *
 343 * Atomically adds @delta to @ptr.
 344 */
 345extern void atomic64_add(u64 delta, atomic64_t *ptr);
 346
 347/**
 348 * atomic64_sub - subtract the atomic64 variable
 349 * @delta: integer value to subtract
 350 * @ptr:   pointer to type atomic64_t
 351 *
 352 * Atomically subtracts @delta from @ptr.
 353 */
 354extern void atomic64_sub(u64 delta, atomic64_t *ptr);
 355
 356/**
 357 * atomic64_sub_and_test - subtract value from variable and test result
 358 * @delta: integer value to subtract
 359 * @ptr:   pointer to type atomic64_t
 360 *
 361 * Atomically subtracts @delta from @ptr and returns
 362 * true if the result is zero, or false for all
 363 * other cases.
 364 */
 365extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr);
 366
 367/**
 368 * atomic64_inc - increment atomic64 variable
 369 * @ptr: pointer to type atomic64_t
 370 *
 371 * Atomically increments @ptr by 1.
 372 */
 373extern void atomic64_inc(atomic64_t *ptr);
 374
 375/**
 376 * atomic64_dec - decrement atomic64 variable
 377 * @ptr: pointer to type atomic64_t
 378 *
 379 * Atomically decrements @ptr by 1.
 380 */
 381extern void atomic64_dec(atomic64_t *ptr);
 382
 383/**
 384 * atomic64_dec_and_test - decrement and test
 385 * @ptr: pointer to type atomic64_t
 386 *
 387 * Atomically decrements @ptr by 1 and
 388 * returns true if the result is 0, or false for all other
 389 * cases.
 390 */
 391extern int atomic64_dec_and_test(atomic64_t *ptr);
 392
 393/**
 394 * atomic64_inc_and_test - increment and test
 395 * @ptr: pointer to type atomic64_t
 396 *
 397 * Atomically increments @ptr by 1
 398 * and returns true if the result is zero, or false for all
 399 * other cases.
 400 */
 401extern int atomic64_inc_and_test(atomic64_t *ptr);
 402
 403/**
 404 * atomic64_add_negative - add and test if negative
 405 * @delta: integer value to add
 406 * @ptr:   pointer to type atomic64_t
 407 *
 408 * Atomically adds @delta to @ptr and returns true
 409 * if the result is negative, or false when
 410 * result is greater than or equal to zero.
 411 */
 412extern int atomic64_add_negative(u64 delta, atomic64_t *ptr);
 413
 414#include <asm-generic/atomic-long.h>
 415#endif /* _ASM_X86_ATOMIC_32_H */
 416
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.