00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef ARCHON_UTILITIES_ATOMIC_H
00021 #define ARCHON_UTILITIES_ATOMIC_H
00022
00023 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
00024 #else // The default fall-back implementation (bad performance)
00025 #include <archon/util/mutex.H>
00026 #endif
00027
00028 namespace Archon
00029 {
00030 namespace Utilities
00031 {
00032 using namespace std;
00033
00054 struct Atomic
00055 {
00056 Atomic() {}
00057 explicit Atomic(int w) { set(w); }
00058
00062 operator int() const { return get(); }
00063
00067 Atomic &operator=(int w) { set(w); return *this; }
00068
00072 Atomic &operator++() { inc(); return *this; }
00073
00077 int operator++(int) { return fetchAndAdd(1); }
00078
00082 Atomic &operator--() { dec(); return *this; }
00083
00087 int operator--(int) { return fetchAndAdd(-1); }
00088
00092 Atomic &operator+=(int w) { add(w); return *this; }
00093
00097 Atomic &operator-=(int w) { add(-w); return *this; }
00098
00104 int get() const;
00105
00111 void set(int w);
00112
00116 void inc();
00117
00121 void dec();
00122
00128 void add(int w);
00129
00135 void sub(int w);
00136
00144 bool decAndZeroTest();
00145
00154 int fetchAndAdd(int w);
00155
00166 bool testAndSet(int t, int w);
00167
00168 private:
00169
00170 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
00171 volatile int v;
00172 #else // The default fall-back implementation (bad performance)
00173 Mutex m;
00174 int v;
00175 #endif
00176
00177 Atomic(const Atomic &);
00178 };
00179
00180 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 inline int Atomic::get() const
00198 {
00199 return v;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209 inline void Atomic::set(int w)
00210 {
00211 v = w;
00212 }
00213
00214 inline void Atomic::inc()
00215 {
00216 asm volatile("lock; incl %0" : "=m"(v) : "m"(v));
00217 }
00218
00219 inline void Atomic::dec()
00220 {
00221 asm volatile("lock; decl %0" : "=m"(v) : "m"(v));
00222 }
00223
00224 inline void Atomic::add(int w)
00225 {
00226 asm volatile("lock; addl %1, %0" : "=m"(v) : "ir"(w), "m"(v));
00227 }
00228
00229 inline void Atomic::sub(int w)
00230 {
00231 asm volatile("lock; subl %1, %0" : "=m"(v) : "ir"(w), "m"(v));
00232 }
00233
00234 inline bool Atomic::decAndZeroTest()
00235 {
00236 unsigned char r;
00237 asm volatile("lock; decl %0; sete %1" : "=m"(v), "=qm"(r) : "m"(v));
00238 return r != 0;
00239 }
00240
00241 inline int Atomic::fetchAndAdd(int w)
00242 {
00243 int r;
00244 asm volatile("lock; xaddl %0, %1" : "=r"(r), "=m"(v) : "0"(w), "m"(v));
00245 return r;
00246 }
00247
00248 inline bool Atomic::testAndSet(int t, int w)
00249 {
00250 int r;
00251 asm volatile("lock; cmpxchgl %2, %1" : "=a"(r), "=m"(v) : "r"(w), "m"(v), "0"(t));
00252 return r == t;
00253 }
00254
00255 #else // The default fall-back implementation (bad performance)
00256
00257 inline int Atomic::get() const
00258 {
00259 Mutex::Lock l(m);
00260 return v;
00261 }
00262
00263 inline void Atomic::set(int w)
00264 {
00265 Mutex::Lock l(m);
00266 v = w;
00267 }
00268
00269 inline void Atomic::inc()
00270 {
00271 Mutex::Lock l(m);
00272 ++v;
00273 }
00274
00275 inline void Atomic::dec()
00276 {
00277 Mutex::Lock l(m);
00278 --v;
00279 }
00280
00281 inline void Atomic::add(int w)
00282 {
00283 Mutex::Lock l(m);
00284 v += w;
00285 }
00286
00287 inline void Atomic::sub(int w)
00288 {
00289 Mutex::Lock l(m);
00290 v -= w;
00291 }
00292
00293 inline bool Atomic::decAndZeroTest()
00294 {
00295 Mutex::Lock l(m);
00296 return --u == 0:
00297 }
00298
00299 inline int Atomic::fetchAndAdd(int w)
00300 {
00301 Mutex::Lock l(m);
00302 int u = v;
00303 v += w;
00304 return u;
00305 }
00306
00307 inline bool Atomic::testAndSet(int t, int w)
00308 {
00309 Mutex::Lock l(m);
00310 if(v!=t) return false;
00311 v = w;
00312 return true;
00313 }
00314
00315 #endif
00316
00317 }
00318 }
00319
00320 #endif // ARCHON_UTILITIES_ATOMIC_H