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 <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 /* _ASM_X86_ATOMIC_32_H */
 260
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.