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-2013 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"
34 
35 #if (((OGRE_COMPILER == OGRE_COMPILER_GNUC) && (OGRE_COMP_VER >= 412)) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)) && OGRE_THREAD_SUPPORT
36 
37 #if ((OGRE_COMPILER == OGRE_COMPILER_GNUC) && (OGRE_COMP_VER >= 473)) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)
38  #define BUILTIN_FETCH_ADD(var, add) __atomic_fetch_add (var, add, __ATOMIC_SEQ_CST);
39  #define BUILTIN_ADD_FETCH(var, add) __atomic_add_fetch (var, add, __ATOMIC_SEQ_CST);
40  #define BUILTIN_SUB_FETCH(var, sub) __atomic_sub_fetch (var, sub, __ATOMIC_SEQ_CST);
41 #else
42  #define BUILTIN_FETCH_ADD(var, add) __sync_fetch_and_add (var, add);
43  #define BUILTIN_ADD_FETCH(var, add) __sync_add_and_fetch (var, add);
44  #define BUILTIN_SUB_FETCH(var, sub) __sync_sub_and_fetch (var, sub);
45 #endif
46 
47 namespace Ogre {
48 
55  template<class T> class AtomicScalar
56  {
57 
58  public:
59 
60  AtomicScalar (const T &initial)
61  : mField(initial)
62  { }
63 
64  AtomicScalar (const AtomicScalar<T> &cousin)
65  : mField(cousin.mField)
66  { }
67 
68  AtomicScalar ()
69  { }
70 
71  void operator= (const AtomicScalar<T> &cousin)
72  {
73  mField = cousin.mField;
74  }
75 
76  T get (void) const
77  {
78  return mField;
79  }
80 
81  void set (const T &v)
82  {
83  mField = v;
84  }
85 
86  bool cas (const T &old, const T &nu)
87  {
88  return __sync_bool_compare_and_swap (&mField, old, nu);
89  }
90 
91  T operator++ (void)
92  {
93  return BUILTIN_ADD_FETCH (&mField, 1);
94  }
95 
96  T operator-- (void)
97  {
98  return BUILTIN_ADD_FETCH (&mField, -1);
99  }
100 
101  T operator++ (int)
102  {
103  return BUILTIN_FETCH_ADD (&mField, 1);
104  }
105 
106  T operator-- (int)
107  {
108  return BUILTIN_FETCH_ADD (&mField, -1);
109  }
110 
111  T operator+=(const T &add)
112  {
113  return BUILTIN_ADD_FETCH (&mField, add);
114  }
115 
116  T operator-=(const T &sub)
117  {
118  return BUILTIN_SUB_FETCH (&mField, sub);
119  }
120 
121  // Need special alignment for atomic functions on ARM CPU's
122 #if OGRE_CPU == OGRE_CPU_ARM
123 # if OGRE_COMPILER == OGRE_COMPILER_MSVC
124  __declspec(align(16)) volatile T mField;
125 # elif (OGRE_COMPILER == OGRE_COMPILER_GNUC) || (OGRE_COMPILER == OGRE_COMPILER_CLANG)
126  volatile T mField __attribute__((__aligned__(16)));
127 # endif
128 #else
129  volatile T mField;
130 #endif
131 
132  };
136 }
137 
138  #elif OGRE_COMPILER == OGRE_COMPILER_MSVC && OGRE_COMP_VER >= 1400 && OGRE_THREAD_SUPPORT
139 
140 #ifndef WIN32_LEAN_AND_MEAN
141 # define WIN32_LEAN_AND_MEAN
142 #endif
143 #if !defined(NOMINMAX) && defined(_MSC_VER)
144 # define NOMINMAX // required to stop windows.h messing up std::min
145 #endif
146 #include <windows.h>
147 #include <intrin.h>
148 
149 // Save warnings state
150 # pragma warning (push)
151 # pragma warning (disable : 4244)
152 
153 namespace Ogre {
154 
161  template<class T> class AtomicScalar
162  {
163 
164  public:
165 
166  AtomicScalar (const T &initial)
167  : mField(initial)
168  { }
169 
170  AtomicScalar (const AtomicScalar<T> &cousin)
171  : mField(cousin.mField)
172  { }
173 
174  AtomicScalar ()
175  { }
176 
177  void operator= (const AtomicScalar<T> &cousin)
178  {
179  mField = cousin.mField;
180  }
181 
182  T get (void) const
183  {
184  return mField;
185  }
186 
187  void set (const T &v)
188  {
189  mField = v;
190  }
191 
192  bool cas (const T &old, const T &nu)
193  {
194  if (sizeof(T)==2) {
195  return _InterlockedCompareExchange16((SHORT*)&mField, static_cast<SHORT>(nu), static_cast<SHORT>(old)) == static_cast<SHORT>(old);
196  }
197  else if (sizeof(T)==4)
198  {
199  return _InterlockedCompareExchange((LONG*)&mField, static_cast<LONG>(nu), static_cast<LONG>(old)) == static_cast<LONG>(old);
200  }
201  else if (sizeof(T)==8) {
202  return _InterlockedCompareExchange64((LONGLONG*)&mField, static_cast<LONGLONG>(nu), static_cast<LONGLONG>(old)) == static_cast<LONGLONG>(old);
203  }
204  else {
205  OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,"Only 16, 32, and 64 bit scalars supported in win32.","AtomicScalar::cas");
206  }
207  }
208 
209  T operator++ (void)
210  {
211  if (sizeof(T)==2) {
212  return _InterlockedIncrement16((SHORT*)&mField);
213  } else if (sizeof(T)==4) {
214  return InterlockedIncrement((LONG*)&mField);
215  } else if (sizeof(T)==8) {
216  return InterlockedIncrement64((LONGLONG*)&mField);
217  } else {
218  OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,"Only 16, 32, and 64 bit scalars supported in win32.","AtomicScalar::operator++(prefix)");
219  }
220  }
221 
222  T operator-- (void)
223  {
224  if (sizeof(T)==2) {
225  return _InterlockedDecrement16((SHORT*)&mField);
226  } else if (sizeof(T)==4) {
227  return InterlockedDecrement((LONG*)&mField);
228  } else if (sizeof(T)==8) {
229  return InterlockedDecrement64((LONGLONG*)&mField);
230  } else {
231  OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,"Only 16, 32, and 64 bit scalars supported in win32.","AtomicScalar::operator--(prefix)");
232  }
233  }
234 
235  T operator++ (int)
236  {
237  if (sizeof(T)==2) {
238  return _InterlockedIncrement16((SHORT*)&mField)-1;
239  } else if (sizeof(T)==4) {
240  return InterlockedIncrement((LONG*)&mField)-1;
241  } else if (sizeof(T)==8) {
242  return InterlockedIncrement64((LONGLONG*)&mField)-1;
243  } else {
244  OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,"Only 16, 32, and 64 bit scalars supported in win32.","AtomicScalar::operator++(postfix)");
245  }
246  }
247 
248  T operator-- (int)
249  {
250  if (sizeof(T)==2) {
251  return _InterlockedDecrement16((SHORT*)&mField)+1;
252  } else if (sizeof(T)==4) {
253  return InterlockedDecrement((LONG*)&mField)+1;
254  } else if (sizeof(T)==8) {
255  return InterlockedDecrement64((LONGLONG*)&mField)+1;
256  } else {
257  OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,"Only 16, 32, and 64 bit scalars supported in win32.","AtomicScalar::operator--(postfix)");
258  }
259  }
260 
261  T operator+=(const T &add)
262  {
263  //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
264  //We will use the cas operation instead.
265  T newVal;
266  do {
267  //Create a value of the current field plus the added value
268  newVal = mField + add;
269  //Replace the current field value with the new value. Ensure that the value
270  //of the field hasn't changed in the mean time by comparing it to the new value
271  //minus the added value.
272  } while (!cas(newVal - add, newVal)); //repeat until successful
273  return newVal;
274  }
275 
276  T operator-=(const T &sub)
277  {
278  //The function InterlockedExchangeAdd is not available for 64 and 16 bit version
279  //We will use the cas operation instead.
280  T newVal;
281  do {
282  //Create a value of the current field plus the added value
283  newVal = mField - sub;
284  //Replace the current field value with the new value. Ensure that the value
285  //of the field hasn't changed in the mean time by comparing it to the new value
286  //minus the added value.
287  } while (!cas(newVal + sub, newVal)); //repeat until successful
288  return newVal;
289  }
290 
291  volatile T mField;
292 
293  };
297 }
298 
299 # pragma warning (pop)
300 
301 #else
302 
304 
305 namespace Ogre {
306 
313  template <class T> class AtomicScalar {
314 
315  public:
316 
317  AtomicScalar (const T &initial)
318  : mField(initial)
319  { }
320 
322  : mField(cousin.mField)
323  { }
324 
326  { }
327 
328  void operator= (const AtomicScalar<T> &cousin)
329  {
331  mField = cousin.mField;
332  }
333 
334  T get (void) const
335  {
336  // no lock required here
337  // since get will not interfere with set or cas
338  // we may get a stale value, but this is ok
339  return mField;
340  }
341 
342  void set (const T &v)
343  {
345  mField = v;
346  }
347 
348  bool cas (const T &old, const T &nu)
349  {
351  if (mField != old) return false;
352  mField = nu;
353  return true;
354  }
355 
356  T operator++ (void)
357  {
359  return ++mField;
360  }
361 
362  T operator-- (void)
363  {
365  return --mField;
366  }
367 
368  T operator++ (int)
369  {
371  return mField++;
372  }
373 
374  T operator-- (int)
375  {
377  return mField--;
378  }
379 
380  T operator+=(const T &add)
381  {
383  mField += add;
384  return mField;
385  }
386 
387  T operator-=(const T &sub)
388  {
390  mField -= sub;
391  return mField;
392  }
393 
394  protected:
395 
397 
398  volatile T mField;
399 
400  };
404 }
405 
406 #endif
407 
408 #endif
409 

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 Wed Oct 16 2013 14:35:41