atomic.h

Go to the documentation of this file.
00001 
00022 #ifndef ATOMIC_H
00023 #define ATOMIC_H
00024 
00025 /*
00026  * Atomic operations that C can't guarantee us.  Useful for
00027  * resource counting etc..
00028  */
00029 
00030 #define LOCK "lock ; "
00031 
00032 /*
00033  * Make sure gcc doesn't try to be clever and move things around
00034  * on us. We need to use _exactly_ the address the user gave us,
00035  * not some alias that contains the same information.
00036  */
00037 typedef struct { volatile int counter; } atomic_t;
00038 
00039 #define ATOMIC_INIT(i)  { (i) }
00040 
00047 #define atomic_read(v)          ((v)->counter)
00048 
00056 #define atomic_set(v,i)         (((v)->counter) = (i))
00057 
00065 static __inline__ void atomic_add(int i, atomic_t *v)
00066 {
00067         __asm__ __volatile__(
00068                 LOCK "addl %1,%0"
00069                 :"=m" (v->counter)
00070                 :"ir" (i), "m" (v->counter));
00071 }
00072 
00080 static __inline__ void atomic_sub(int i, atomic_t *v)
00081 {
00082         __asm__ __volatile__(
00083                 LOCK "subl %1,%0"
00084                 :"=m" (v->counter)
00085                 :"ir" (i), "m" (v->counter));
00086 }
00087 
00088 
00096 static __inline__ int atomic_add_return(int i, atomic_t *v)
00097 {
00098   int __i;
00099   /* Modern 486+ processor */
00100   __i = i;
00101   __asm__ __volatile__(
00102                 LOCK "xaddl %0, %1"
00103                 :"+r" (i), "+m" (v->counter)
00104                 : : "memory");
00105   return i + __i;
00106 }
00107 
00108 static __inline__ int atomic_sub_return(int i, atomic_t *v)
00109 {
00110   return atomic_add_return(-i,v);
00111 }
00112 
00113 
00123 static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
00124 {
00125         unsigned char c;
00126 
00127         __asm__ __volatile__(
00128                 LOCK "subl %2,%0; sete %1"
00129                 :"=m" (v->counter), "=qm" (c)
00130                 :"ir" (i), "m" (v->counter) : "memory");
00131         return c;
00132 }
00133 
00140 static __inline__ void atomic_inc(atomic_t *v)
00141 {
00142         __asm__ __volatile__(
00143                 LOCK "incl %0"
00144                 :"=m" (v->counter)
00145                 :"m" (v->counter));
00146 }
00147 
00154 static __inline__ void atomic_dec(atomic_t *v)
00155 {
00156         __asm__ __volatile__(
00157                 LOCK "decl %0"
00158                 :"=m" (v->counter)
00159                 :"m" (v->counter));
00160 }
00161 
00170 static __inline__ int atomic_dec_and_test(atomic_t *v)
00171 {
00172         unsigned char c;
00173 
00174         __asm__ __volatile__(
00175                 LOCK "decl %0; sete %1"
00176                 :"=m" (v->counter), "=qm" (c)
00177                 :"m" (v->counter) : "memory");
00178         return c != 0;
00179 }
00180 
00189 static __inline__ int atomic_inc_and_test(atomic_t *v)
00190 {
00191         unsigned char c;
00192 
00193         __asm__ __volatile__(
00194                 LOCK "incl %0; sete %1"
00195                 :"=m" (v->counter), "=qm" (c)
00196                 :"m" (v->counter) : "memory");
00197         return c != 0;
00198 }
00199 
00209 static __inline__ int atomic_add_negative(int i, atomic_t *v)
00210 {
00211         unsigned char c;
00212 
00213         __asm__ __volatile__(
00214                 LOCK "addl %2,%0; sets %1"
00215                 :"=m" (v->counter), "=qm" (c)
00216                 :"ir" (i), "m" (v->counter) : "memory");
00217         return c;
00218 }
00219 
00220 /* These are x86-specific, used by some header files */
00221 #define atomic_clear_mask(mask, addr) \
00222 __asm__ __volatile__(LOCK "andl %0,%1" \
00223 : : "r" (~(mask)),"m" (*addr) : "memory")
00224 
00225 #define atomic_set_mask(mask, addr) \
00226 __asm__ __volatile__(LOCK "orl %0,%1" \
00227 : : "r" (mask),"m" (*(addr)) : "memory")
00228 
00229 #define atomic_inc_return(v)  (atomic_add_return(1,v))
00230 #define atomic_dec_return(v)  (atomic_sub_return(1,v))
00231 
00232 #endif // ATOMIC_H