OgreAtomicScalar.h
Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright (c) 2000-2013 Torus Knot Software Ltd
00008 
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015 
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018 
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025 THE SOFTWARE.
00026 -----------------------------------------------------------------------------
00027 */
00028 #ifndef __AtomicScalar_H__
00029 #define __AtomicScalar_H__
00030 
00031 #include <signal.h>
00032 #include "OgrePrerequisites.h"
00033 #include "OgreException.h"
00034 #include "OgrePlatformInformation.h"
00035 
00036 #if (((OGRE_COMPILER == OGRE_COMPILER_GNUC) && (OGRE_COMP_VER >= 412)) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)) && OGRE_THREAD_SUPPORT
00037 
00038 // Atomics are not yet supported for the unsigned long long int(ResourceHandle) type as of Clang 5.0. So only GCC for now.
00039 #if ((OGRE_COMPILER == OGRE_COMPILER_GNUC) && (OGRE_COMP_VER >= 473))
00040     #define BUILTIN_FETCH_ADD(var, add) __atomic_fetch_add (var, add, __ATOMIC_SEQ_CST);
00041     #define BUILTIN_ADD_FETCH(var, add) __atomic_add_fetch (var, add, __ATOMIC_SEQ_CST);
00042     #define BUILTIN_SUB_FETCH(var, sub) __atomic_sub_fetch (var, sub, __ATOMIC_SEQ_CST);
00043 #else
00044     #define BUILTIN_FETCH_ADD(var, add) __sync_fetch_and_add (var, add);
00045     #define BUILTIN_ADD_FETCH(var, add) __sync_add_and_fetch (var, add);
00046     #define BUILTIN_SUB_FETCH(var, sub) __sync_sub_and_fetch (var, sub);
00047 #endif
00048 
00049 namespace Ogre {
00050 
00057     template<class T> class AtomicScalar
00058     {
00059 
00060         public:
00061 
00062         AtomicScalar (const T &initial)
00063             : mField(initial)
00064         {   }
00065 
00066         AtomicScalar (const AtomicScalar<T> &cousin)
00067             : mField(cousin.mField)
00068         {   }
00069 
00070         AtomicScalar () 
00071         {   }
00072 
00073         void operator= (const AtomicScalar<T> &cousin)
00074         {
00075             mField = cousin.mField;
00076         }
00077 
00078         T get (void) const
00079         {
00080             return mField;
00081         }
00082 
00083         void set (const T &v)
00084         {
00085             mField = v; 
00086         }   
00087 
00088         bool cas (const T &old, const T &nu)
00089         {
00090             return __sync_bool_compare_and_swap (&mField, old, nu);
00091         }
00092             
00093         T operator++ (void)
00094         {
00095             return BUILTIN_ADD_FETCH (&mField, 1);
00096         }
00097             
00098         T operator-- (void)
00099         {
00100             return BUILTIN_ADD_FETCH (&mField, -1);
00101         }
00102 
00103         T operator++ (int)
00104         {
00105             return BUILTIN_FETCH_ADD (&mField, 1);
00106         }
00107             
00108         T operator-- (int)
00109         {
00110             return BUILTIN_FETCH_ADD (&mField, -1);
00111         }
00112 
00113         T operator+=(const T &add)
00114         {
00115             return BUILTIN_ADD_FETCH (&mField, add);
00116         }
00117 
00118         T operator-=(const T &sub)
00119         {
00120             return BUILTIN_SUB_FETCH (&mField, sub);
00121         }
00122 
00123         // Need special alignment for atomic functions on ARM CPU's
00124 #if OGRE_CPU == OGRE_CPU_ARM
00125 #   if OGRE_COMPILER == OGRE_COMPILER_MSVC
00126         __declspec(align(16)) volatile T mField;
00127 #   elif (OGRE_COMPILER == OGRE_COMPILER_GNUC) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)
00128         volatile T mField __attribute__((__aligned__(16)));
00129 #   endif
00130 #else
00131         volatile T mField;
00132 #endif
00133 
00134     };
00138 }
00139 
00140 
00141  #elif OGRE_COMPILER == OGRE_COMPILER_MSVC && OGRE_COMP_VER >= 1400 && OGRE_THREAD_SUPPORT
00142 
00143 #ifndef WIN32_LEAN_AND_MEAN
00144 #  define WIN32_LEAN_AND_MEAN
00145 #endif
00146 #if !defined(NOMINMAX) && defined(_MSC_VER)
00147 #   define NOMINMAX // required to stop windows.h messing up std::min
00148 #endif
00149 #include <windows.h>
00150 #include <intrin.h>
00151 #include "Threading/OgreThreadHeaders.h"
00152 
00153 // Save warnings state
00154 #   pragma warning (push)
00155 #   pragma warning (disable : 4244)
00156 
00157 
00158 
00159 namespace Ogre {
00160 
00161     // a hack so we can support windows xp.
00162 #define NEED_TO_INIT_INTERLOCKEDCOMPAREEXCHANGE64WRAPPER
00163     struct _OgreExport InterlockedCompareExchange64Wrapper
00164     {
00165         InterlockedCompareExchange64Wrapper();
00166 
00167         typedef 
00168             LONGLONG
00169             (WINAPI *func_InterlockedCompareExchange64)( 
00170             __inout LONGLONG volatile *Destination,
00171             __in    LONGLONG Exchange,
00172             __in    LONGLONG Comperand) ;
00173 
00174         static func_InterlockedCompareExchange64 Ogre_InterlockedCompareExchange64;
00175 
00176         static FORCEINLINE
00177             LONGLONG
00178             Ogre_InterlockedIncrement64 (
00179             __inout LONGLONG volatile *Addend
00180             )
00181         {
00182             LONGLONG Old;
00183 
00184             do {
00185                 Old = *Addend;
00186             } while (Ogre_InterlockedCompareExchange64(Addend,
00187                 Old + 1,
00188                 Old) != Old);
00189 
00190             return Old + 1;
00191         }
00192 
00193         static FORCEINLINE
00194             LONGLONG
00195             Ogre_InterlockedDecrement64 (
00196             __inout LONGLONG volatile *Addend
00197             )
00198         {
00199             LONGLONG Old;
00200 
00201             do {
00202                 Old = *Addend;
00203             } while (Ogre_InterlockedCompareExchange64(Addend,
00204                 Old - 1,
00205                 Old) != Old);
00206 
00207             return Old - 1;
00208         }
00209 
00210     };
00211 
00218     template<class T> class AtomicScalar
00219     {
00220 
00221         public:
00222 
00223         AtomicScalar (const T &initial)
00224             : mField(initial)
00225         {   }
00226 
00227         AtomicScalar (const AtomicScalar<T> &cousin)
00228             : mField(cousin.mField)
00229         {   }
00230 
00231         AtomicScalar () 
00232         {   }
00233 
00234         void operator= (const AtomicScalar<T> &cousin)
00235         {
00236             mField = cousin.mField;
00237         }
00238 
00239         T get (void) const
00240         {
00241             return mField;
00242         }
00243 
00244         void set (const T &v)
00245         {
00246             mField = v;
00247         }   
00248 
00249         bool cas (const T &old, const T &nu)
00250         {
00251             if (sizeof(T)==2) {
00252                 return _InterlockedCompareExchange16((SHORT*)&mField, static_cast<SHORT>(nu), static_cast<SHORT>(old)) == static_cast<SHORT>(old);
00253             } 
00254             else if (sizeof(T)==4) 
00255             {
00256                 return _InterlockedCompareExchange((LONG*)&mField, static_cast<LONG>(nu), static_cast<LONG>(old)) == static_cast<LONG>(old);
00257             } 
00258             else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
00259                 return InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64((LONGLONG*)&mField, static_cast<LONGLONG>(nu), static_cast<LONGLONG>(old)) == static_cast<LONGLONG>(old);
00260             } 
00261             else {
00262                 OGRE_LOCK_AUTO_MUTEX;
00263                 if (mField != old) return false;
00264                 mField = nu;
00265                 return true;
00266             }
00267         }
00268             
00269         T operator++ (void)
00270         {
00271             if (sizeof(T)==2) {
00272                 return _InterlockedIncrement16((SHORT*)&mField);
00273             } else if (sizeof(T)==4) {
00274                 return InterlockedIncrement((LONG*)&mField);
00275             } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
00276                 return InterlockedCompareExchange64Wrapper::Ogre_InterlockedIncrement64((LONGLONG*)&mField);
00277             } else {
00278                 OGRE_LOCK_AUTO_MUTEX;
00279                 return ++mField;
00280             }
00281         }
00282             
00283         T operator-- (void)
00284         {
00285             if (sizeof(T)==2) {
00286                 return _InterlockedDecrement16((SHORT*)&mField);
00287             } else if (sizeof(T)==4) {
00288                 return InterlockedDecrement((LONG*)&mField);
00289             } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
00290                 return InterlockedCompareExchange64Wrapper::Ogre_InterlockedDecrement64((LONGLONG*)&mField);
00291             } else {
00292                 OGRE_LOCK_AUTO_MUTEX;
00293                 return --mField;
00294             }
00295         }
00296 
00297         T operator++ (int)
00298         {
00299             if (sizeof(T)==2) {
00300                 return _InterlockedIncrement16((SHORT*)&mField)-1;
00301             } else if (sizeof(T)==4) {
00302                 return InterlockedIncrement((LONG*)&mField)-1;
00303             } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
00304                 return InterlockedCompareExchange64Wrapper::Ogre_InterlockedIncrement64((LONGLONG*)&mField)-1;
00305             } else {
00306                 OGRE_LOCK_AUTO_MUTEX;
00307                 return mField++;
00308             }
00309         }
00310             
00311         T operator-- (int)
00312         {
00313             if (sizeof(T)==2) {
00314                 return _InterlockedDecrement16((SHORT*)&mField)+1;
00315             } else if (sizeof(T)==4) {
00316                 return InterlockedDecrement((LONG*)&mField)+1;
00317             } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
00318                 return InterlockedCompareExchange64Wrapper::Ogre_InterlockedDecrement64((LONGLONG*)&mField)+1;
00319             } else {
00320                 OGRE_LOCK_AUTO_MUTEX;
00321                 return mField--;
00322             }
00323         }
00324 
00325         T operator+=(const T &add)
00326         {
00327             if ((sizeof(T)==2) || (sizeof(T)==4) || (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL)) {
00328                 //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
00329                 //We will use the cas operation instead. 
00330                 T newVal;
00331                 do {
00332                     //Create a value of the current field plus the added value
00333                     newVal = mField + add;
00334                     //Replace the current field value with the new value. Ensure that the value 
00335                     //of the field hasn't changed in the mean time by comparing it to the new value
00336                     //minus the added value. 
00337                 } while (!cas(newVal - add, newVal)); //repeat until successful
00338                 return newVal;
00339             }
00340             else
00341             {
00342                 OGRE_LOCK_AUTO_MUTEX;
00343                 mField += add;
00344                 return mField;
00345             }
00346         }
00347 
00348         T operator-=(const T &sub)
00349         {
00350             if ((sizeof(T)==2) || (sizeof(T)==4) || (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL)) {
00351                 //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
00352                 //We will use the cas operation instead. 
00353                 T newVal;
00354                 do {
00355                     //Create a value of the current field plus the added value
00356                     newVal = mField - sub;
00357                     //Replace the current field value with the new value. Ensure that the value 
00358                     //of the field hasn't changed in the mean time by comparing it to the new value
00359                     //minus the added value. 
00360                 } while (!cas(newVal + sub, newVal)); //repeat until successful
00361                 return newVal;
00362             }
00363             else
00364             {
00365                 OGRE_LOCK_AUTO_MUTEX;
00366                 mField -= sub;
00367                 return mField;
00368             }
00369         }
00370 
00371         protected:
00372 
00373         OGRE_AUTO_MUTEX;
00374 
00375         volatile T mField;
00376 
00377     };
00381 }
00382 
00383 #   pragma warning (pop)
00384 
00385 #else
00386 
00387 #include "Threading/OgreThreadHeaders.h"
00388 
00389 namespace Ogre {
00390 
00397     template <class T> class AtomicScalar {
00398 
00399         public:
00400 
00401         AtomicScalar (const T &initial)
00402             : mField(initial)
00403         {   }
00404 
00405         AtomicScalar (const AtomicScalar<T> &cousin)
00406             : mField(cousin.mField)
00407         {   }
00408 
00409         AtomicScalar ()
00410         {   }
00411 
00412         void operator= (const AtomicScalar<T> &cousin)
00413         {
00414             mField = cousin.mField;
00415         }
00416 
00417         T get (void) const
00418         {
00419             // no lock required here
00420             // since get will not interfere with set or cas
00421             // we may get a stale value, but this is ok
00422             return mField;
00423         }
00424 
00425         void set (const T &v)
00426         {
00427             mField = v;
00428         }
00429 
00430         bool cas (const T &old, const T &nu)
00431         {
00432             OGRE_LOCK_AUTO_MUTEX;
00433             if (mField != old) return false;
00434             mField = nu;
00435             return true;
00436         }
00437 
00438         T operator++ (void)
00439         {
00440             OGRE_LOCK_AUTO_MUTEX;
00441             return ++mField;
00442         }
00443 
00444         T operator-- (void)
00445         {
00446             OGRE_LOCK_AUTO_MUTEX;
00447             return --mField;
00448         }
00449 
00450         T operator++ (int)
00451         {
00452             OGRE_LOCK_AUTO_MUTEX;
00453             return mField++;
00454         }
00455 
00456         T operator-- (int)
00457         {
00458             OGRE_LOCK_AUTO_MUTEX;
00459             return mField--;
00460         }
00461 
00462         T operator+=(const T &add)
00463         {
00464             OGRE_LOCK_AUTO_MUTEX;
00465             mField += add;
00466             return mField;
00467         }
00468 
00469         T operator-=(const T &sub)
00470         {
00471             OGRE_LOCK_AUTO_MUTEX;
00472             mField -= sub;
00473             return mField;
00474         }
00475 
00476         protected:
00477 
00478         OGRE_AUTO_MUTEX;
00479 
00480         volatile T mField;
00481 
00482     };
00486 }
00487 
00488 #endif
00489 
00490 #endif
00491 

Copyright © 2012 Torus Knot Software Ltd
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Mon Jul 27 2020 13:40:40