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