OgreAtomicScalar.h
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2013 Torus Knot Software Ltd
8
9Permission is hereby granted, free of charge, to any person obtaining a copy
10of this software and associated documentation files (the "Software"), to deal
11in the Software without restriction, including without limitation the rights
12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13copies of the Software, and to permit persons to whom the Software is
14furnished to do so, subject to the following conditions:
15
16The above copyright notice and this permission notice shall be included in
17all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25THE 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
49namespace 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
159namespace 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
389namespace Ogre {
390
397 template <class T> class AtomicScalar {
398
399 public:
400
402 : mField(initial)
403 { }
404
407 { }
408
410 { }
411
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
439 {
441 return ++mField;
442 }
443
445 {
447 return --mField;
448 }
449
451 {
453 return mField++;
454 }
455
457 {
459 return mField--;
460 }
461
462 T operator+=(const T &add)
463 {
465 mField += add;
466 return mField;
467 }
468
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
#define FORCEINLINE
#define OGRE_LOCK_AUTO_MUTEX
void set(const T &v)
T operator+=(const T &add)
AtomicScalar(const AtomicScalar< T > &cousin)
bool cas(const T &old, const T &nu)
AtomicScalar(const T &initial)
void operator=(const AtomicScalar< T > &cousin)
T operator-=(const T &sub)
Reference-counted shared pointer, used for objects where implicit destruction is required.

Copyright © 2012 Torus Knot Software Ltd
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.