OGRE  2.0
Object-Oriented Graphics Rendering Engine
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
OgreAtomicScalar.h
Go to the documentation of this file.
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4  (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #ifndef __AtomicScalar_H__
29 #define __AtomicScalar_H__
30 
31 #include "OgrePrerequisites.h"
33 #include "OgreException.h"
35 
36 #if (((OGRE_COMPILER == OGRE_COMPILER_GNUC) && (OGRE_COMP_VER >= 412)) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)) && OGRE_THREAD_SUPPORT
37 
38 // Atomics are not yet supported for the unsigned long long int(ResourceHandle) type as of Clang 5.0. So only GCC for now.
39 #if ((OGRE_COMPILER == OGRE_COMPILER_GNUC) && (OGRE_COMP_VER >= 473))
40  #define BUILTIN_FETCH_ADD(var, add) __atomic_fetch_add (var, add, __ATOMIC_SEQ_CST);
41  #define BUILTIN_ADD_FETCH(var, add) __atomic_add_fetch (var, add, __ATOMIC_SEQ_CST);
42  #define BUILTIN_SUB_FETCH(var, sub) __atomic_sub_fetch (var, sub, __ATOMIC_SEQ_CST);
43 #else
44  #define BUILTIN_FETCH_ADD(var, add) __sync_fetch_and_add (var, add);
45  #define BUILTIN_ADD_FETCH(var, add) __sync_add_and_fetch (var, add);
46  #define BUILTIN_SUB_FETCH(var, sub) __sync_sub_and_fetch (var, sub);
47 #endif
48 
49 namespace Ogre {
50 
57  template<class T> class AtomicScalar
58  {
59 
60  public:
61 
62  AtomicScalar (const T &initial)
63  : mField(initial)
64  { }
65 
66  AtomicScalar (const AtomicScalar<T> &cousin)
67  : mField(cousin.mField)
68  { }
69 
70  AtomicScalar ()
71  { }
72 
73  void operator= (const AtomicScalar<T> &cousin)
74  {
75  mField = cousin.mField;
76  }
77 
78  T get (void) const
79  {
80  return mField;
81  }
82 
83  void set (const T &v)
84  {
85  mField = v;
86  }
87 
88  bool cas (const T &old, const T &nu)
89  {
90  return __sync_bool_compare_and_swap (&mField, old, nu);
91  }
92 
93  T operator++ (void)
94  {
95  return BUILTIN_ADD_FETCH (&mField, 1);
96  }
97 
98  T operator-- (void)
99  {
100  return BUILTIN_ADD_FETCH (&mField, -1);
101  }
102 
103  T operator++ (int)
104  {
105  return BUILTIN_FETCH_ADD (&mField, 1);
106  }
107 
108  T operator-- (int)
109  {
110  return BUILTIN_FETCH_ADD (&mField, -1);
111  }
112 
113  T operator+=(const T &add)
114  {
115  return BUILTIN_ADD_FETCH (&mField, add);
116  }
117 
118  T operator-=(const T &sub)
119  {
120  return BUILTIN_SUB_FETCH (&mField, sub);
121  }
122 
123  // Need special alignment for atomic functions on ARM CPU's
124 #if OGRE_CPU == OGRE_CPU_ARM
125 # if OGRE_COMPILER == OGRE_COMPILER_MSVC
126  __declspec(align(16)) volatile T mField;
127 # elif (OGRE_COMPILER == OGRE_COMPILER_GNUC) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)
128  volatile T mField __attribute__((__aligned__(16)));
129 # endif
130 #elif OGRE_CPU == OGRE_CPU_X86 && OGRE_PLATFORM == OGRE_PLATFORM_APPLE && ((OGRE_COMPILER == OGRE_COMPILER_CLANG) && (OGRE_COMP_VER < 500))
131 /* https://ogre3d.atlassian.net/browse/OGRE-324
132  * but see http://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time
133  * the version in OGRE_COMP_VER is exactly the version reported with 'gcc -v' (Apple LLVM version 5.0 would produce OGRE_COMP_VER==500)
134  * but if the system built clang from sources that same compiler would be LLVM version 3.3 with OGRE_COMP_VER==330
135  */
136  volatile T mField __attribute__((__aligned__(16)));
137 #else
138  volatile T mField;
139 #endif
140 
141  };
145 }
146 
147 
148  #elif OGRE_COMPILER == OGRE_COMPILER_MSVC && OGRE_COMP_VER >= 1400 && OGRE_THREAD_SUPPORT
149 
150 #ifndef WIN32_LEAN_AND_MEAN
151 # define WIN32_LEAN_AND_MEAN
152 #endif
153 #if !defined(NOMINMAX) && defined(_MSC_VER)
154 # define NOMINMAX // required to stop windows.h messing up std::min
155 #endif
156 #include <windows.h>
157 #include <intrin.h>
159 
160 // Save warnings state
161 # pragma warning (push)
162 # pragma warning (disable : 4244)
163 
164 
165 
166 namespace Ogre {
167 
168  // a hack so we can support windows xp.
169 #define NEED_TO_INIT_INTERLOCKEDCOMPAREEXCHANGE64WRAPPER
170  struct _OgreExport InterlockedCompareExchange64Wrapper
171  {
172  InterlockedCompareExchange64Wrapper();
173 
174  typedef
175  LONGLONG
176  (WINAPI *func_InterlockedCompareExchange64)(
177  __inout LONGLONG volatile *Destination,
178  __in LONGLONG Exchange,
179  __in LONGLONG Comperand) ;
180 
181  static func_InterlockedCompareExchange64 Ogre_InterlockedCompareExchange64;
182 
183  static FORCEINLINE
184  LONGLONG
185  Ogre_InterlockedIncrement64 (
186  __inout LONGLONG volatile *Addend
187  )
188  {
189  LONGLONG Old;
190 
191  do {
192  Old = *Addend;
193  } while (Ogre_InterlockedCompareExchange64(Addend,
194  Old + 1,
195  Old) != Old);
196 
197  return Old + 1;
198  }
199 
200  static FORCEINLINE
201  LONGLONG
202  Ogre_InterlockedDecrement64 (
203  __inout LONGLONG volatile *Addend
204  )
205  {
206  LONGLONG Old;
207 
208  do {
209  Old = *Addend;
210  } while (Ogre_InterlockedCompareExchange64(Addend,
211  Old - 1,
212  Old) != Old);
213 
214  return Old - 1;
215  }
216 
217  };
218 
225  template<class T> class AtomicScalar
226  {
227 
228  public:
229 
230  AtomicScalar (const T &initial)
231  : mField(initial)
232  { }
233 
234  AtomicScalar (const AtomicScalar<T> &cousin)
235  : mField(cousin.mField)
236  { }
237 
238  AtomicScalar ()
239  { }
240 
241  void operator= (const AtomicScalar<T> &cousin)
242  {
243  mField = cousin.mField;
244  }
245 
246  T get (void) const
247  {
248  return mField;
249  }
250 
251  void set (const T &v)
252  {
253  mField = v;
254  }
255 
256  bool cas (const T &old, const T &nu)
257  {
258  if (sizeof(T)==2) {
259  return _InterlockedCompareExchange16((SHORT*)&mField, static_cast<SHORT>(nu), static_cast<SHORT>(old)) == static_cast<SHORT>(old);
260  }
261  else if (sizeof(T)==4)
262  {
263  return _InterlockedCompareExchange((LONG*)&mField, static_cast<LONG>(nu), static_cast<LONG>(old)) == static_cast<LONG>(old);
264  }
265  else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
266  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64((LONGLONG*)&mField, static_cast<LONGLONG>(nu), static_cast<LONGLONG>(old)) == static_cast<LONGLONG>(old);
267  }
268  else {
270  if (mField != old) return false;
271  mField = nu;
272  return true;
273  }
274  }
275 
276  T operator++ (void)
277  {
278  if (sizeof(T)==2) {
279  return _InterlockedIncrement16((SHORT*)&mField);
280  } else if (sizeof(T)==4) {
281  return InterlockedIncrement((LONG*)&mField);
282  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
283  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedIncrement64((LONGLONG*)&mField);
284  } else {
286  return ++mField;
287  }
288  }
289 
290  T operator-- (void)
291  {
292  if (sizeof(T)==2) {
293  return _InterlockedDecrement16((SHORT*)&mField);
294  } else if (sizeof(T)==4) {
295  return InterlockedDecrement((LONG*)&mField);
296  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
297  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedDecrement64((LONGLONG*)&mField);
298  } else {
300  return --mField;
301  }
302  }
303 
304  T operator++ (int)
305  {
306  if (sizeof(T)==2) {
307  return _InterlockedIncrement16((SHORT*)&mField)-1;
308  } else if (sizeof(T)==4) {
309  return InterlockedIncrement((LONG*)&mField)-1;
310  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
311  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedIncrement64((LONGLONG*)&mField)-1;
312  } else {
314  return mField++;
315  }
316  }
317 
318  T operator-- (int)
319  {
320  if (sizeof(T)==2) {
321  return _InterlockedDecrement16((SHORT*)&mField)+1;
322  } else if (sizeof(T)==4) {
323  return InterlockedDecrement((LONG*)&mField)+1;
324  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
325  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedDecrement64((LONGLONG*)&mField)+1;
326  } else {
328  return mField--;
329  }
330  }
331 
332  T operator+=(const T &add)
333  {
334  if ((sizeof(T)==2) || (sizeof(T)==4) || (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL)) {
335  //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
336  //We will use the cas operation instead.
337  T newVal;
338  do {
339  //Create a value of the current field plus the added value
340  newVal = mField + add;
341  //Replace the current field value with the new value. Ensure that the value
342  //of the field hasn't changed in the mean time by comparing it to the new value
343  //minus the added value.
344  } while (!cas(newVal - add, newVal)); //repeat until successful
345  return newVal;
346  }
347  else
348  {
350  mField += add;
351  return mField;
352  }
353  }
354 
355  T operator-=(const T &sub)
356  {
357  if ((sizeof(T)==2) || (sizeof(T)==4) || (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL)) {
358  //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
359  //We will use the cas operation instead.
360  T newVal;
361  do {
362  //Create a value of the current field plus the added value
363  newVal = mField - sub;
364  //Replace the current field value with the new value. Ensure that the value
365  //of the field hasn't changed in the mean time by comparing it to the new value
366  //minus the added value.
367  } while (!cas(newVal + sub, newVal)); //repeat until successful
368  return newVal;
369  }
370  else
371  {
373  mField -= sub;
374  return mField;
375  }
376  }
377 
378  protected:
379 
381 
382  volatile T mField;
383 
384  };
388 }
389 
390 # pragma warning (pop)
391 
392 #else
393 
395 
396 namespace Ogre {
397 
404  template <class T> class AtomicScalar {
405 
406  public:
407 
408  AtomicScalar (const T &initial)
409  : mField(initial)
410  { }
411 
413  : mField(cousin.mField)
414  { }
415 
417  { }
418 
419  void operator= (const AtomicScalar<T> &cousin)
420  {
421  mField = cousin.mField;
422  }
423 
424  T get (void) const
425  {
426  // no lock required here
427  // since get will not interfere with set or cas
428  // we may get a stale value, but this is ok
429  return mField;
430  }
431 
432  void set (const T &v)
433  {
434  mField = v;
435  }
436 
437  bool cas (const T &old, const T &nu)
438  {
440  if (mField != old) return false;
441  mField = nu;
442  return true;
443  }
444 
445  T operator++ (void)
446  {
448  return ++mField;
449  }
450 
451  T operator-- (void)
452  {
454  return --mField;
455  }
456 
457  T operator++ (int)
458  {
460  return mField++;
461  }
462 
463  T operator-- (int)
464  {
466  return mField--;
467  }
468 
469  T operator+=(const T &add)
470  {
472  mField += add;
473  return mField;
474  }
475 
476  T operator-=(const T &sub)
477  {
479  mField -= sub;
480  return mField;
481  }
482 
483  protected:
484 
486 
487  volatile T mField;
488 
489  };
493 }
494 
495 #endif
496 
497 #endif
498 
long LONG
Definition: OgreBarrier.h:36
#define _OgreExport
Definition: OgrePlatform.h:255
T operator-=(const T &sub)
void set(const T &v)
AtomicScalar(const AtomicScalar< T > &cousin)
#define OGRE_LOCK_AUTO_MUTEX
bool cas(const T &old, const T &nu)
void operator=(const AtomicScalar< T > &cousin)
#define FORCEINLINE
Definition: OgrePlatform.h:104
T operator+=(const T &add)
AtomicScalar(const T &initial)