OGRE  1.9
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 <signal.h>
32 #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 #else
131  volatile T mField;
132 #endif
133 
134  };
138 }
139 
140 
141  #elif OGRE_COMPILER == OGRE_COMPILER_MSVC && OGRE_COMP_VER >= 1400 && OGRE_THREAD_SUPPORT
142 
143 #ifndef WIN32_LEAN_AND_MEAN
144 # define WIN32_LEAN_AND_MEAN
145 #endif
146 #if !defined(NOMINMAX) && defined(_MSC_VER)
147 # define NOMINMAX // required to stop windows.h messing up std::min
148 #endif
149 #include <windows.h>
150 #include <intrin.h>
152 
153 // Save warnings state
154 # pragma warning (push)
155 # pragma warning (disable : 4244)
156 
157 
158 
159 namespace Ogre {
160 
161  // a hack so we can support windows xp.
162 #define NEED_TO_INIT_INTERLOCKEDCOMPAREEXCHANGE64WRAPPER
163  struct _OgreExport InterlockedCompareExchange64Wrapper
164  {
165  InterlockedCompareExchange64Wrapper();
166 
167  typedef
168  LONGLONG
169  (WINAPI *func_InterlockedCompareExchange64)(
170  __inout LONGLONG volatile *Destination,
171  __in LONGLONG Exchange,
172  __in LONGLONG Comperand) ;
173 
174  static func_InterlockedCompareExchange64 Ogre_InterlockedCompareExchange64;
175 
176  static FORCEINLINE
177  LONGLONG
178  Ogre_InterlockedIncrement64 (
179  __inout LONGLONG volatile *Addend
180  )
181  {
182  LONGLONG Old;
183 
184  do {
185  Old = *Addend;
186  } while (Ogre_InterlockedCompareExchange64(Addend,
187  Old + 1,
188  Old) != Old);
189 
190  return Old + 1;
191  }
192 
193  static FORCEINLINE
194  LONGLONG
195  Ogre_InterlockedDecrement64 (
196  __inout LONGLONG volatile *Addend
197  )
198  {
199  LONGLONG Old;
200 
201  do {
202  Old = *Addend;
203  } while (Ogre_InterlockedCompareExchange64(Addend,
204  Old - 1,
205  Old) != Old);
206 
207  return Old - 1;
208  }
209 
210  };
211 
218  template<class T> class AtomicScalar
219  {
220 
221  public:
222 
223  AtomicScalar (const T &initial)
224  : mField(initial)
225  { }
226 
227  AtomicScalar (const AtomicScalar<T> &cousin)
228  : mField(cousin.mField)
229  { }
230 
231  AtomicScalar ()
232  { }
233 
234  void operator= (const AtomicScalar<T> &cousin)
235  {
236  mField = cousin.mField;
237  }
238 
239  T get (void) const
240  {
241  return mField;
242  }
243 
244  void set (const T &v)
245  {
246  mField = v;
247  }
248 
249  bool cas (const T &old, const T &nu)
250  {
251  if (sizeof(T)==2) {
252  return _InterlockedCompareExchange16((SHORT*)&mField, static_cast<SHORT>(nu), static_cast<SHORT>(old)) == static_cast<SHORT>(old);
253  }
254  else if (sizeof(T)==4)
255  {
256  return _InterlockedCompareExchange((LONG*)&mField, static_cast<LONG>(nu), static_cast<LONG>(old)) == static_cast<LONG>(old);
257  }
258  else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
259  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64((LONGLONG*)&mField, static_cast<LONGLONG>(nu), static_cast<LONGLONG>(old)) == static_cast<LONGLONG>(old);
260  }
261  else {
263  if (mField != old) return false;
264  mField = nu;
265  return true;
266  }
267  }
268 
269  T operator++ (void)
270  {
271  if (sizeof(T)==2) {
272  return _InterlockedIncrement16((SHORT*)&mField);
273  } else if (sizeof(T)==4) {
274  return InterlockedIncrement((LONG*)&mField);
275  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
276  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedIncrement64((LONGLONG*)&mField);
277  } else {
279  return ++mField;
280  }
281  }
282 
283  T operator-- (void)
284  {
285  if (sizeof(T)==2) {
286  return _InterlockedDecrement16((SHORT*)&mField);
287  } else if (sizeof(T)==4) {
288  return InterlockedDecrement((LONG*)&mField);
289  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
290  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedDecrement64((LONGLONG*)&mField);
291  } else {
293  return --mField;
294  }
295  }
296 
297  T operator++ (int)
298  {
299  if (sizeof(T)==2) {
300  return _InterlockedIncrement16((SHORT*)&mField)-1;
301  } else if (sizeof(T)==4) {
302  return InterlockedIncrement((LONG*)&mField)-1;
303  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
304  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedIncrement64((LONGLONG*)&mField)-1;
305  } else {
307  return mField++;
308  }
309  }
310 
311  T operator-- (int)
312  {
313  if (sizeof(T)==2) {
314  return _InterlockedDecrement16((SHORT*)&mField)+1;
315  } else if (sizeof(T)==4) {
316  return InterlockedDecrement((LONG*)&mField)+1;
317  } else if (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL) {
318  return InterlockedCompareExchange64Wrapper::Ogre_InterlockedDecrement64((LONGLONG*)&mField)+1;
319  } else {
321  return mField--;
322  }
323  }
324 
325  T operator+=(const T &add)
326  {
327  if ((sizeof(T)==2) || (sizeof(T)==4) || (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL)) {
328  //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
329  //We will use the cas operation instead.
330  T newVal;
331  do {
332  //Create a value of the current field plus the added value
333  newVal = mField + add;
334  //Replace the current field value with the new value. Ensure that the value
335  //of the field hasn't changed in the mean time by comparing it to the new value
336  //minus the added value.
337  } while (!cas(newVal - add, newVal)); //repeat until successful
338  return newVal;
339  }
340  else
341  {
343  mField += add;
344  return mField;
345  }
346  }
347 
348  T operator-=(const T &sub)
349  {
350  if ((sizeof(T)==2) || (sizeof(T)==4) || (sizeof(T)==8 && InterlockedCompareExchange64Wrapper::Ogre_InterlockedCompareExchange64 != NULL)) {
351  //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
352  //We will use the cas operation instead.
353  T newVal;
354  do {
355  //Create a value of the current field plus the added value
356  newVal = mField - sub;
357  //Replace the current field value with the new value. Ensure that the value
358  //of the field hasn't changed in the mean time by comparing it to the new value
359  //minus the added value.
360  } while (!cas(newVal + sub, newVal)); //repeat until successful
361  return newVal;
362  }
363  else
364  {
366  mField -= sub;
367  return mField;
368  }
369  }
370 
371  protected:
372 
374 
375  volatile T mField;
376 
377  };
381 }
382 
383 # pragma warning (pop)
384 
385 #else
386 
388 
389 namespace Ogre {
390 
397  template <class T> class AtomicScalar {
398 
399  public:
400 
401  AtomicScalar (const T &initial)
402  : mField(initial)
403  { }
404 
406  : mField(cousin.mField)
407  { }
408 
410  { }
411 
412  void operator= (const AtomicScalar<T> &cousin)
413  {
414  mField = cousin.mField;
415  }
416 
417  T get (void) const
418  {
419  // no lock required here
420  // since get will not interfere with set or cas
421  // we may get a stale value, but this is ok
422  return mField;
423  }
424 
425  void set (const T &v)
426  {
427  mField = v;
428  }
429 
430  bool cas (const T &old, const T &nu)
431  {
433  if (mField != old) return false;
434  mField = nu;
435  return true;
436  }
437 
438  T operator++ (void)
439  {
441  return ++mField;
442  }
443 
444  T operator-- (void)
445  {
447  return --mField;
448  }
449 
450  T operator++ (int)
451  {
453  return mField++;
454  }
455 
456  T operator-- (int)
457  {
459  return mField--;
460  }
461 
462  T operator+=(const T &add)
463  {
465  mField += add;
466  return mField;
467  }
468 
469  T operator-=(const T &sub)
470  {
472  mField -= sub;
473  return mField;
474  }
475 
476  protected:
477 
479 
480  volatile T mField;
481 
482  };
486 }
487 
488 #endif
489 
490 #endif
491 
#define _OgreExport
Definition: OgrePlatform.h:260
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:102
T operator+=(const T &add)
AtomicScalar(const T &initial)