File: /usr/src/linux/include/asm/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.  Note that the guaranteed
31      * useful range of an atomic_t is only 24 bits.
32      */ 
33     #define atomic_read(v)		((v)->counter)
34     
35     /**
36      * atomic_set - set atomic variable
37      * @v: pointer of type atomic_t
38      * @i: required value
39      * 
40      * Atomically sets the value of @v to @i.  Note that the guaranteed
41      * useful range of an atomic_t is only 24 bits.
42      */ 
43     #define atomic_set(v,i)		(((v)->counter) = (i))
44     
45     /**
46      * atomic_add - add integer to atomic variable
47      * @i: integer value to add
48      * @v: pointer of type atomic_t
49      * 
50      * Atomically adds @i to @v.  Note that the guaranteed useful range
51      * of an atomic_t is only 24 bits.
52      */
53     static __inline__ void atomic_add(int i, atomic_t *v)
54     {
55     	__asm__ __volatile__(
56     		LOCK "addl %1,%0"
57     		:"=m" (v->counter)
58     		:"ir" (i), "m" (v->counter));
59     }
60     
61     /**
62      * atomic_sub - subtract the atomic variable
63      * @i: integer value to subtract
64      * @v: pointer of type atomic_t
65      * 
66      * Atomically subtracts @i from @v.  Note that the guaranteed
67      * useful range of an atomic_t is only 24 bits.
68      */
69     static __inline__ void atomic_sub(int i, atomic_t *v)
70     {
71     	__asm__ __volatile__(
72     		LOCK "subl %1,%0"
73     		:"=m" (v->counter)
74     		:"ir" (i), "m" (v->counter));
75     }
76     
77     /**
78      * atomic_sub_and_test - subtract value from variable and test result
79      * @i: integer value to subtract
80      * @v: pointer of type atomic_t
81      * 
82      * Atomically subtracts @i from @v and returns
83      * true if the result is zero, or false for all
84      * other cases.  Note that the guaranteed
85      * useful range of an atomic_t is only 24 bits.
86      */
87     static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
88     {
89     	unsigned char c;
90     
91     	__asm__ __volatile__(
92     		LOCK "subl %2,%0; sete %1"
93     		:"=m" (v->counter), "=qm" (c)
94     		:"ir" (i), "m" (v->counter) : "memory");
95     	return c;
96     }
97     
98     /**
99      * atomic_inc - increment atomic variable
100      * @v: pointer of type atomic_t
101      * 
102      * Atomically increments @v by 1.  Note that the guaranteed
103      * useful range of an atomic_t is only 24 bits.
104      */ 
105     static __inline__ void atomic_inc(atomic_t *v)
106     {
107     	__asm__ __volatile__(
108     		LOCK "incl %0"
109     		:"=m" (v->counter)
110     		:"m" (v->counter));
111     }
112     
113     /**
114      * atomic_dec - decrement atomic variable
115      * @v: pointer of type atomic_t
116      * 
117      * Atomically decrements @v by 1.  Note that the guaranteed
118      * useful range of an atomic_t is only 24 bits.
119      */ 
120     static __inline__ void atomic_dec(atomic_t *v)
121     {
122     	__asm__ __volatile__(
123     		LOCK "decl %0"
124     		:"=m" (v->counter)
125     		:"m" (v->counter));
126     }
127     
128     /**
129      * atomic_dec_and_test - decrement and test
130      * @v: pointer of type atomic_t
131      * 
132      * Atomically decrements @v by 1 and
133      * returns true if the result is 0, or false for all other
134      * cases.  Note that the guaranteed
135      * useful range of an atomic_t is only 24 bits.
136      */ 
137     static __inline__ int atomic_dec_and_test(atomic_t *v)
138     {
139     	unsigned char c;
140     
141     	__asm__ __volatile__(
142     		LOCK "decl %0; sete %1"
143     		:"=m" (v->counter), "=qm" (c)
144     		:"m" (v->counter) : "memory");
145     	return c != 0;
146     }
147     
148     /**
149      * atomic_inc_and_test - increment and test 
150      * @v: pointer of type atomic_t
151      * 
152      * Atomically increments @v by 1
153      * and returns true if the result is zero, or false for all
154      * other cases.  Note that the guaranteed
155      * useful range of an atomic_t is only 24 bits.
156      */ 
157     static __inline__ int atomic_inc_and_test(atomic_t *v)
158     {
159     	unsigned char c;
160     
161     	__asm__ __volatile__(
162     		LOCK "incl %0; sete %1"
163     		:"=m" (v->counter), "=qm" (c)
164     		:"m" (v->counter) : "memory");
165     	return c != 0;
166     }
167     
168     /**
169      * atomic_add_negative - add and test if negative
170      * @v: pointer of type atomic_t
171      * @i: integer value to add
172      * 
173      * Atomically adds @i to @v and returns true
174      * if the result is negative, or false when
175      * result is greater than or equal to zero.  Note that the guaranteed
176      * useful range of an atomic_t is only 24 bits.
177      */ 
178     static __inline__ int atomic_add_negative(int i, atomic_t *v)
179     {
180     	unsigned char c;
181     
182     	__asm__ __volatile__(
183     		LOCK "addl %2,%0; sets %1"
184     		:"=m" (v->counter), "=qm" (c)
185     		:"ir" (i), "m" (v->counter) : "memory");
186     	return c;
187     }
188     
189     /* These are x86-specific, used by some header files */
190     #define atomic_clear_mask(mask, addr) \
191     __asm__ __volatile__(LOCK "andl %0,%1" \
192     : : "r" (~(mask)),"m" (*addr) : "memory")
193     
194     #define atomic_set_mask(mask, addr) \
195     __asm__ __volatile__(LOCK "orl %0,%1" \
196     : : "r" (mask),"m" (*addr) : "memory")
197     
198     /* Atomic operations are already serializing on x86 */
199     #define smp_mb__before_atomic_dec()	barrier()
200     #define smp_mb__after_atomic_dec()	barrier()
201     #define smp_mb__before_atomic_inc()	barrier()
202     #define smp_mb__after_atomic_inc()	barrier()
203     
204     #endif
205