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

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Mon Jul 27 2020 13:40:40