atomic_ix86.h

Go to the documentation of this file.
00001 /*!@file rutz/atomic_ix86.h Inline x86 assembly functions imported
00002          from Linux kernel headers circa version 2.4.18-41mdk. */
00003 
00004 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00005 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/atomic_ix86.h $
00006 // $Id: atomic_ix86.h 7063 2006-08-29 18:26:55Z rjpeters $
00007 
00008 #ifndef RUTZ_ATOMIC_IX86_H_UTC20050728203342_DEFINED
00009 #define RUTZ_ATOMIC_IX86_H_UTC20050728203342_DEFINED
00010 
00011 namespace rutz
00012 {
00013 
00014 /*
00015  * Atomic operations that C can't guarantee us.  Useful for
00016  * resource counting etc..
00017  */
00018 
00019 #define LOCK "lock ; "
00020 
00021 /*
00022  * Make sure gcc doesn't try to be clever and move things around
00023  * on us. We need to use _exactly_ the address the user gave us,
00024  * not some alias that contains the same information.
00025  */
00026 typedef struct { volatile int counter; } ix86_atomic_int_t;
00027 
00028 /**
00029  * ix86_atomic_read - read atomic variable
00030  * @v: pointer of type ix86_atomic_int_t
00031  *
00032  * Atomically reads the value of @v.  Note that the guaranteed
00033  * useful range of an ix86_atomic_int_t is only 24 bits.
00034  */
00035 #define ix86_atomic_read(v)          ((v)->counter)
00036 
00037 /**
00038  * ix86_atomic_set - set atomic variable
00039  * @v: pointer of type ix86_atomic_int_t
00040  * @i: required value
00041  *
00042  * Atomically sets the value of @v to @i.  Note that the guaranteed
00043  * useful range of an ix86_atomic_int_t is only 24 bits.
00044  */
00045 #define ix86_atomic_set(v,i)         (((v)->counter) = (i))
00046 
00047 /**
00048  * ix86_atomic_add - add integer to atomic variable
00049  * @i: integer value to add
00050  * @v: pointer of type ix86_atomic_int_t
00051  *
00052  * Atomically adds @i to @v.
00053  */
00054 static __inline__ void ix86_atomic_add(int i, ix86_atomic_int_t *v)
00055 {
00056         __asm__ __volatile__(
00057                 LOCK "addl %1,%0"
00058                 :"=m" (v->counter)
00059                 :"ir" (i), "m" (v->counter));
00060 }
00061 
00062 /**
00063  * ix86_atomic_sub - subtract the atomic variable
00064  * @i: integer value to subtract
00065  * @v: pointer of type ix86_atomic_int_t
00066  *
00067  * Atomically subtracts @i from @v.
00068  */
00069 static __inline__ void ix86_atomic_sub(int i, ix86_atomic_int_t *v)
00070 {
00071         __asm__ __volatile__(
00072                 LOCK "subl %1,%0"
00073                 :"=m" (v->counter)
00074                 :"ir" (i), "m" (v->counter));
00075 }
00076 
00077 /**
00078  * ix86_atomic_sub_and_test - subtract value from variable and test result
00079  * @i: integer value to subtract
00080  * @v: pointer of type ix86_atomic_int_t
00081  *
00082  * Atomically subtracts @i from @v and returns
00083  * true if the result is zero, or false for all
00084  * other cases.
00085  */
00086 static __inline__ int ix86_atomic_sub_and_test(int i, ix86_atomic_int_t *v)
00087 {
00088         unsigned char c;
00089 
00090         __asm__ __volatile__(
00091                 LOCK "subl %2,%0; sete %1"
00092                 :"=m" (v->counter), "=qm" (c)
00093                 :"ir" (i), "m" (v->counter) : "memory");
00094         return c;
00095 }
00096 
00097 /**
00098  * ix86_atomic_inc - increment atomic variable
00099  * @v: pointer of type ix86_atomic_int_t
00100  *
00101  * Atomically increments @v by 1.  Note that the guaranteed
00102  * useful range of an ix86_atomic_int_t is only 24 bits.
00103  */
00104 static __inline__ void ix86_atomic_inc(ix86_atomic_int_t *v)
00105 {
00106         __asm__ __volatile__(
00107                 LOCK "incl %0"
00108                 :"=m" (v->counter)
00109                 :"m" (v->counter));
00110 }
00111 
00112 /**
00113  * ix86_atomic_dec - decrement atomic variable
00114  * @v: pointer of type ix86_atomic_int_t
00115  *
00116  * Atomically decrements @v by 1.
00117  */
00118 static __inline__ void ix86_atomic_dec(ix86_atomic_int_t *v)
00119 {
00120         __asm__ __volatile__(
00121                 LOCK "decl %0"
00122                 :"=m" (v->counter)
00123                 :"m" (v->counter));
00124 }
00125 
00126 /**
00127  * ix86_atomic_dec_and_test - decrement and test
00128  * @v: pointer of type ix86_atomic_int_t
00129  *
00130  * Atomically decrements @v by 1 and
00131  * returns true if the result is 0, or false for all other
00132  * cases.  Note that the guaranteed
00133  * useful range of an ix86_atomic_int_t is only 24 bits.
00134  */
00135 static __inline__ int ix86_atomic_dec_and_test(ix86_atomic_int_t *v)
00136 {
00137         unsigned char c;
00138 
00139         __asm__ __volatile__(
00140                 LOCK "decl %0; sete %1"
00141                 :"=m" (v->counter), "=qm" (c)
00142                 :"m" (v->counter) : "memory");
00143         return c != 0;
00144 }
00145 
00146 /**
00147  * ix86_atomic_inc_and_test - increment and test
00148  * @v: pointer of type ix86_atomic_int_t
00149  *
00150  * Atomically increments @v by 1
00151  * and returns true if the result is zero, or false for all
00152  * other cases.
00153  */
00154 static __inline__ int ix86_atomic_inc_and_test(ix86_atomic_int_t *v)
00155 {
00156         unsigned char c;
00157 
00158         __asm__ __volatile__(
00159                 LOCK "incl %0; sete %1"
00160                 :"=m" (v->counter), "=qm" (c)
00161                 :"m" (v->counter) : "memory");
00162         return c != 0;
00163 }
00164 
00165 /**
00166  * ix86_atomic_add_return - add and return
00167  * @v: pointer of type ix86_atomic_int_t
00168  * @i: integer value to add
00169  *
00170  * Atomically adds @i to @v and returns @i + @v
00171  */
00172 static __inline__ int ix86_atomic_add_return(int i, ix86_atomic_int_t *v)
00173 {
00174         /* Modern 486+ processor */
00175         int __i = i;
00176         __asm__ __volatile__(
00177                 LOCK "xaddl %0, %1;"
00178                 :"=r"(i)
00179                 :"m"(v->counter), "0"(i));
00180         return i + __i;
00181 }
00182 
00183 static __inline__ int ix86_atomic_sub_return(int i, ix86_atomic_int_t *v)
00184 {
00185         return ix86_atomic_add_return(-i,v);
00186 }
00187 
00188 /// Atomic integer class for ix86 CPUs.
00189 class ix86_atomic_int
00190 {
00191 private:
00192   ix86_atomic_int_t x;
00193 
00194   ix86_atomic_int(const ix86_atomic_int&); // not implemented
00195   ix86_atomic_int& operator=(const ix86_atomic_int&); // not implemented
00196 
00197 public:
00198   //! Construct with an initial value of 0.
00199   ix86_atomic_int() { this->atomic_set(0); }
00200 
00201   //! Get the maximum representable value
00202   static int max_value() { return ((1 << 24) - 1); }
00203 
00204   //! Get the current value.
00205   int atomic_get() const
00206   { return ix86_atomic_read(&x); }
00207 
00208   //! Set value to the given value \a v.
00209   void atomic_set(int v)
00210   { ix86_atomic_set(&x, v); }
00211 
00212   //! Add \a v to the value.
00213   void atomic_add(int i)
00214   { ix86_atomic_add(i, &x); }
00215 
00216   //! Subtract \a v from the value.
00217   void atomic_sub(int i)
00218   { ix86_atomic_sub(i, &x); }
00219 
00220   //! Subtract \a v from the value; return true if the new value is zero.
00221   bool atomic_sub_test_zero(int i)
00222   { return bool(ix86_atomic_sub_and_test(i, &x)); }
00223 
00224   //! Increment the value by one.
00225   void atomic_incr()
00226   { ix86_atomic_inc(&x); }
00227 
00228   //! Decrement the value by one.
00229   void atomic_decr()
00230   { ix86_atomic_dec(&x); }
00231 
00232   //! Decrement the value by one; return true if the new value is zero.
00233   bool atomic_decr_test_zero()
00234   { return bool(ix86_atomic_dec_and_test(&x)); }
00235 
00236   //! Increment the value by one; return true if the new value is zero.
00237   bool atomic_incr_test_zero()
00238   { return bool(ix86_atomic_inc_and_test(&x)); }
00239 
00240   //! Add \a v to the value and return the new value.
00241   int atomic_add_return(int i)
00242   { return ix86_atomic_add_return(i, &x); }
00243 
00244   //! Subtract \a v from the value and return the new value.
00245   int atomic_sub_return(int i)
00246   { return ix86_atomic_sub_return(i, &x); }
00247 
00248   //! Increment the value by one and return the new value.
00249   int atomic_incr_return()
00250   { return ix86_atomic_add_return(1, &x); }
00251 
00252   //! Decrement the value by one and return the new value.
00253   int atomic_decr_return()
00254   { return ix86_atomic_add_return(-1, &x); }
00255 };
00256 
00257 } // end namespace rutz
00258 
00259 #endif // !RUTZ_ATOMIC_IX86_H_UTC20050728203342DEFINED
Generated on Sun May 8 08:42:09 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3