ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-i386 / atomic.h
1 #ifndef __ARCH_I386_ATOMIC__
2 #define __ARCH_I386_ATOMIC__
3
4 #include <linux/config.h>
5
6 /*
7  * Atomic operations that C can't guarantee us.  Useful for
8  * resource counting etc..
9  */
10
11 #ifdef CONFIG_SMP
12 #define LOCK "lock ; "
13 #else
14 #define LOCK ""
15 #endif
16
17 /*
18  * Make sure gcc doesn't try to be clever and move things around
19  * on us. We need to use _exactly_ the address the user gave us,
20  * not some alias that contains the same information.
21  */
22 typedef struct { volatile int counter; } atomic_t;
23
24 #define ATOMIC_INIT(i)  { (i) }
25
26 /**
27  * atomic_read - read atomic variable
28  * @v: pointer of type atomic_t
29  * 
30  * Atomically reads the value of @v.
31  */ 
32 #define atomic_read(v)          ((v)->counter)
33
34 /**
35  * atomic_set - set atomic variable
36  * @v: pointer of type atomic_t
37  * @i: required value
38  * 
39  * Atomically sets the value of @v to @i.
40  */ 
41 #define atomic_set(v,i)         (((v)->counter) = (i))
42
43 /**
44  * atomic_add - add integer to atomic variable
45  * @i: integer value to add
46  * @v: pointer of type atomic_t
47  * 
48  * Atomically adds @i to @v.
49  */
50 static __inline__ void atomic_add(int i, atomic_t *v)
51 {
52         __asm__ __volatile__(
53                 LOCK "addl %1,%0"
54                 :"=m" (v->counter)
55                 :"ir" (i), "m" (v->counter));
56 }
57
58 /**
59  * atomic_sub - subtract the atomic variable
60  * @i: integer value to subtract
61  * @v: pointer of type atomic_t
62  * 
63  * Atomically subtracts @i from @v.
64  */
65 static __inline__ void atomic_sub(int i, atomic_t *v)
66 {
67         __asm__ __volatile__(
68                 LOCK "subl %1,%0"
69                 :"=m" (v->counter)
70                 :"ir" (i), "m" (v->counter));
71 }
72
73 /**
74  * atomic_sub_and_test - subtract value from variable and test result
75  * @i: integer value to subtract
76  * @v: pointer of type atomic_t
77  * 
78  * Atomically subtracts @i from @v and returns
79  * true if the result is zero, or false for all
80  * other cases.
81  */
82 static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
83 {
84         unsigned char c;
85
86         __asm__ __volatile__(
87                 LOCK "subl %2,%0; sete %1"
88                 :"=m" (v->counter), "=qm" (c)
89                 :"ir" (i), "m" (v->counter) : "memory");
90         return c;
91 }
92
93 /**
94  * atomic_inc - increment atomic variable
95  * @v: pointer of type atomic_t
96  * 
97  * Atomically increments @v by 1.
98  */ 
99 static __inline__ void atomic_inc(atomic_t *v)
100 {
101         __asm__ __volatile__(
102                 LOCK "incl %0"
103                 :"=m" (v->counter)
104                 :"m" (v->counter));
105 }
106
107 /**
108  * atomic_dec - decrement atomic variable
109  * @v: pointer of type atomic_t
110  * 
111  * Atomically decrements @v by 1.
112  */ 
113 static __inline__ void atomic_dec(atomic_t *v)
114 {
115         __asm__ __volatile__(
116                 LOCK "decl %0"
117                 :"=m" (v->counter)
118                 :"m" (v->counter));
119 }
120
121 /**
122  * atomic_dec_and_test - decrement and test
123  * @v: pointer of type atomic_t
124  * 
125  * Atomically decrements @v by 1 and
126  * returns true if the result is 0, or false for all other
127  * cases.
128  */ 
129 static __inline__ int atomic_dec_and_test(atomic_t *v)
130 {
131         unsigned char c;
132
133         __asm__ __volatile__(
134                 LOCK "decl %0; sete %1"
135                 :"=m" (v->counter), "=qm" (c)
136                 :"m" (v->counter) : "memory");
137         return c != 0;
138 }
139
140 /**
141  * atomic_inc_and_test - increment and test 
142  * @v: pointer of type atomic_t
143  * 
144  * Atomically increments @v by 1
145  * and returns true if the result is zero, or false for all
146  * other cases.
147  */ 
148 static __inline__ int atomic_inc_and_test(atomic_t *v)
149 {
150         unsigned char c;
151
152         __asm__ __volatile__(
153                 LOCK "incl %0; sete %1"
154                 :"=m" (v->counter), "=qm" (c)
155                 :"m" (v->counter) : "memory");
156         return c != 0;
157 }
158
159 /**
160  * atomic_add_negative - add and test if negative
161  * @v: pointer of type atomic_t
162  * @i: integer value to add
163  * 
164  * Atomically adds @i to @v and returns true
165  * if the result is negative, or false when
166  * result is greater than or equal to zero.
167  */ 
168 static __inline__ int atomic_add_negative(int i, atomic_t *v)
169 {
170         unsigned char c;
171
172         __asm__ __volatile__(
173                 LOCK "addl %2,%0; sets %1"
174                 :"=m" (v->counter), "=qm" (c)
175                 :"ir" (i), "m" (v->counter) : "memory");
176         return c;
177 }
178
179 /* These are x86-specific, used by some header files */
180 #define atomic_clear_mask(mask, addr) \
181 __asm__ __volatile__(LOCK "andl %0,%1" \
182 : : "r" (~(mask)),"m" (*addr) : "memory")
183
184 #define atomic_set_mask(mask, addr) \
185 __asm__ __volatile__(LOCK "orl %0,%1" \
186 : : "r" (mask),"m" (*(addr)) : "memory")
187
188 /* Atomic operations are already serializing on x86 */
189 #define smp_mb__before_atomic_dec()     barrier()
190 #define smp_mb__after_atomic_dec()      barrier()
191 #define smp_mb__before_atomic_inc()     barrier()
192 #define smp_mb__after_atomic_inc()      barrier()
193
194 #endif