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