Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members

FXAtomic.h

Go to the documentation of this file.
00001 /********************************************************************************
00002 *                                                                               *
00003 *                         A t o m i c   I n t e g e r                           *
00004 *                                                                               *
00005 *********************************************************************************
00006 * Copyright (C) 2006,2010 by Jeroen van der Zijp.   All Rights Reserved.        *
00007 *********************************************************************************
00008 * This library is free software; you can redistribute it and/or modify          *
00009 * it under the terms of the GNU Lesser General Public License as published by   *
00010 * the Free Software Foundation; either version 3 of the License, or             *
00011 * (at your option) any later version.                                           *
00012 *                                                                               *
00013 * This library is distributed in the hope that it will be useful,               *
00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
00016 * GNU Lesser General Public License for more details.                           *
00017 *                                                                               *
00018 * You should have received a copy of the GNU Lesser General Public License      *
00019 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
00020 ********************************************************************************/
00021 #ifndef FXATOMIC_H
00022 #define FXATOMIC_H
00023 
00024 
00025 namespace FX {
00026 
00027 
00028 /**
00029 * An atomically modifyable integer.
00030 */
00031 class FXAtomicInt {
00032 private:
00033   volatile FXint val;
00034 public:
00035 
00036   /// Constructs an atomic integer with a given initial value.
00037   FXAtomicInt(FXint v=0):val(v){}
00038 
00039 
00040   /// Assign from value
00041   FXAtomicInt& operator=(FXint v){ val=v; return *this; }
00042 
00043 
00044   /// Returns current value of the integer
00045   operator FXint() const { return val; }
00046 
00047 
00048   /// Returns current value of the integer
00049   inline FXint get() const { return val; }
00050 
00051 
00052   /// Set variable to v; return old value
00053   inline FXint set(FXint v){
00054 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00055     FXint ret=v;
00056     __asm__ __volatile__("lock\n\t"
00057                          "xchgl %0,%1\n\t" : "=r" (ret) : "m" (val), "0" (ret) : "memory");
00058     return ret;
00059 #elif defined(WIN32)
00060     return InterlockedExchange((LONG*)&val,v);
00061 #else
00062     FXint ret=val;
00063     val=v;
00064     return ret;
00065 #endif
00066     }
00067 
00068 
00069   /// If variable is equal to expect, set it to v; returns old value
00070   inline FXint cas(FXint expect,FXint v){
00071 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00072     FXint ret;
00073     __asm__ __volatile__("lock\n\t"
00074                          "cmpxchgl %1,%2\n\t" : "=a" (ret) : "r" (v), "m" (val), "0" (expect) : "memory");
00075     return ret;
00076 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00077     return __sync_val_compare_and_swap(&val,expect,v);
00078 #elif defined(WIN32)
00079     return InterlockedCompareExchange((LONG*)&val,v,expect);
00080 #else
00081     FXint ret=val;
00082     if(val==expect) val=v;
00083     return ret;
00084 #endif
00085     }
00086 
00087 
00088   /// Atomically add v to the variable
00089   inline FXAtomicInt& operator+=(FXint v){
00090 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00091     __asm__ __volatile__ ("lock\n\t"
00092                           "addl %1,%0\n\t" : "=m" (val) : "ir" (v), "m" (val) : "memory");
00093 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00094     __sync_add_and_fetch(&val,v);
00095 #elif defined(WIN32)
00096     InterlockedAdd((LONG*)&val,v);
00097 #else
00098     val+=v;
00099 #endif
00100     return *this;
00101     }
00102 
00103 
00104   /// Atomically substract v from the variable
00105   inline FXAtomicInt& operator-=(FXint v){
00106 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00107     __asm__ __volatile__ ("lock\n\t"
00108                           "subl %1,%0\n\t" : "=m" (val) : "ir" (v), "m" (val) : "memory");
00109 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00110     __sync_add_and_fetch(&val,-v);
00111 #elif defined(WIN32)
00112     InterlockedAdd((LONG*)&val,-v);
00113 #else
00114     val-=v;
00115 #endif
00116     return *this;
00117     }
00118 
00119 
00120   /// Atomically bitwise-or v to the variable
00121   inline FXAtomicInt& operator|=(FXint v){
00122 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00123     __asm__ __volatile__ ("lock\n\t"
00124                           "orl %1,%0\n\t" : "=m" (val) : "ir" (v), "m" (val) : "memory");
00125 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00126     __sync_or_and_fetch(&val,v);
00127 #elif defined(WIN32)
00128     InterlockedOr((LONG*)&val,v);
00129 #else
00130     val|=v;
00131 #endif
00132     return *this;
00133     }
00134 
00135 
00136   /// Atomically bitwise-and v to the variable
00137   inline FXAtomicInt& operator&=(FXint v){
00138 #if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00139     __sync_and_and_fetch(&val,v);
00140 #elif (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00141     __asm__ __volatile__ ("lock\n\t"
00142                           "andl %1,%0\n\t" : "=m" (val) : "ir" (v), "m" (val) : "memory");
00143 #elif defined(WIN32)
00144     InterlockedAnd((LONG*)&val,v);
00145 #else
00146     val&=v;
00147 #endif
00148     return *this;
00149     }
00150 
00151 
00152   /// Atomically bitwise-xor v to the variable
00153   inline FXAtomicInt& operator^=(FXint v){
00154 #if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00155     __sync_xor_and_fetch(&val,v);
00156 #elif (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00157     __asm__ __volatile__ ("lock\n\t"
00158                           "xorl %1,%0\n\t" : "=m" (val) : "ir" (v), "m" (val) : "memory");
00159 #elif defined(WIN32)
00160     InterlockedXor((LONG*)&val,v);
00161 #else
00162     val^=v;
00163 #endif
00164     return *this;
00165     }
00166 
00167 
00168   /// Atomically increment the integer, prefix version
00169   inline FXint operator++(){
00170 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00171     FXint ret=1;
00172     __asm__ __volatile__ ("lock\n\t"
00173                           "xaddl %0,%1\n\t" : "=r"(ret), "=m"(val) : "0"(ret), "m"(val) : "memory");
00174     return ret+1;
00175 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00176     return __sync_add_and_fetch(&val,1);
00177 #elif defined(WIN32)
00178     return InterlockedAdd((LONG*)&val,1);
00179 #else
00180     return ++val;
00181 #endif
00182     }
00183 
00184 
00185   /// Atomically decrement the integer, prefix version
00186   inline FXint operator--(){
00187 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00188     FXint ret=-1;
00189     __asm__ __volatile__ ("lock\n\t"
00190                           "xaddl %0,%1\n\t" : "=r"(ret), "=m"(val) : "0"(ret), "m"(val) : "memory");
00191     return ret-1;
00192 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00193     return __sync_add_and_fetch(&val,-1);
00194 #elif defined(WIN32)
00195     return InterlockedAdd((LONG*)&val,-1);
00196 #else
00197     return --val;
00198 #endif
00199     }
00200 
00201 
00202   /// Atomically increment value, postfix version
00203   inline int operator++(FXint){
00204 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00205     FXint ret=1;
00206     __asm__ __volatile__ ("lock\n\t"
00207                           "xaddl %0,%1\n\t" : "=r"(ret), "=m"(val) : "0"(ret), "m"(val) : "memory");
00208     return ret;
00209 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00210     return __sync_fetch_and_add(&val,1);
00211 #elif defined(WIN32)
00212     return InterlockedExchangeAdd((LONG*)&val,1);
00213 #else
00214     return val++;
00215 #endif
00216     }
00217 
00218 
00219   /// Atomically decrement value, postfix version
00220   inline FXint operator--(FXint){
00221 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined(__x86_64__))
00222     FXint ret=-1;
00223     __asm__ __volatile__ ("lock\n\t"
00224                           "xaddl %0,%1\n\t" : "=r"(ret), "=m"(val) : "0"(ret), "m"(val) : "memory");
00225     return ret;
00226 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00227     return __sync_fetch_and_add(&val,-1);
00228 #elif defined(WIN32)
00229     return InterlockedExchangeAdd((LONG*)&val,-1);
00230 #else
00231     return val--;
00232 #endif
00233     }
00234   };
00235 
00236 
00237 
00238 
00239 /**
00240 * An atomically modifyable pointer.
00241 */
00242 template<class EType>
00243 class FXAtomicPtr {
00244 private:
00245   EType *volatile ptr;
00246 public:
00247 
00248   /// Constructs an atomic pointer with a given initial value.
00249   FXAtomicPtr(EType* p=NULL):ptr(p){ }
00250 
00251   /// Assign from pointer
00252   FXAtomicPtr& operator=(EType *p){ ptr=p; return *this; }
00253 
00254   /// Returns current value of the pointer
00255   operator EType*() const { return ptr; }
00256 
00257   /// Dereference operator
00258   EType& operator*() const { return *ptr; }
00259 
00260   /// Follow pointer operator
00261   EType *operator->() const { return ptr; }
00262 
00263 
00264   /// Returns current value of the pointer
00265   inline EType* get() const { return ptr; }
00266 
00267 
00268   /// Set pointer to p; return old value
00269   inline EType* set(EType* p){
00270 #if (defined(__GNUC__) || defined(__ICC)) && defined(__i386__)
00271     EType* ret=p;
00272     __asm__ __volatile__("lock\n\t"
00273                          "xchgl %0,%1\n\t" : "=r" (ret) : "m" (ptr), "0" (ret) : "memory");
00274     return ret;
00275 #elif (defined(__GNUC__) || defined(__ICC)) && defined(__x86_64__)
00276     EType* ret=p;
00277     __asm__ __volatile__("lock\n\t"
00278                          "xchgq %0,%1\n\t" : "=r" (ret) : "m" (ptr), "0" (ret) : "memory");
00279     return ret;
00280 #elif defined(WIN32)
00281    return (EType*)InterlockedExchangePointer((void *volatile)&ptr,p);
00282 #else
00283     EType* ret=ptr;
00284     ptr=p;
00285     return ret;
00286 #endif
00287     }
00288 
00289 
00290   /// If pointer is equal to expect, set it to p; returns old value
00291   inline EType* cas(EType* expect,EType* p){
00292 #if (defined(__GNUC__) || defined(__ICC)) && defined(__i386__)
00293     EType* ret;
00294     __asm__ __volatile__("lock\n\t"
00295                          "cmpxchgl %1,%2\n\t" : "=a" (ret) : "r" (p), "m" (ptr), "0" (expect) : "memory");
00296     return ret;
00297 #elif (defined(__GNUC__) || defined(__ICC)) && defined(__x86_64__)
00298     EType* ret;
00299     __asm__ __volatile__("lock\n\t"
00300                          "cmpxchgq %1,%2\n\t" : "=a" (ret) : "r" (p), "m" (ptr), "0" (expect) : "memory");
00301     return ret;
00302 #elif defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
00303     return __sync_val_compare_and_swap(&ptr,expect,p);
00304 #elif defined(WIN32)
00305     return (EType*)InterlockedCompareExchangePointer((void *volatile)&ptr,p,expect);
00306 #else
00307     EType* ret=ptr;
00308     if(ptr==expect) ptr=p;
00309     return ret;
00310 #endif
00311     }
00312   };
00313 
00314 
00315 }
00316 
00317 #endif

Copyright © 1997-2010 Jeroen van der Zijp