Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
OVR_Atomic.h
Go to the documentation of this file.
1 /************************************************************************************
2 
3 PublicHeader: OVR.h
4 Filename : OVR_Atomic.h
5 Content : Contains atomic operations and inline fastest locking
6  functionality. Will contain #ifdefs for OS efficiency.
7  Have non-thread-safe implementaion if not available.
8 Created : September 19, 2012
9 Notes :
10 
11 Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
12 
13 Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
14 you may not use the Oculus VR Rift SDK except in compliance with the License,
15 which is provided at the time of installation or download, or which
16 otherwise accompanies this software in either electronic or hard copy form.
17 
18 You may obtain a copy of the License at
19 
20 http://www.oculusvr.com/licenses/LICENSE-3.1
21 
22 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
23 distributed under the License is distributed on an "AS IS" BASIS,
24 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 See the License for the specific language governing permissions and
26 limitations under the License.
27 
28 ************************************************************************************/
29 #ifndef OVR_Atomic_h
30 #define OVR_Atomic_h
31 
32 #include "OVR_Types.h"
33 
34 // Include System thread functionality.
35 #if defined(OVR_OS_WIN32)
36 #include <windows.h>
37 #else
38 #include <pthread.h>
39 #endif
40 
41 
42 namespace OVR {
43 
44 
45 // ****** Declared classes
46 
47 // If there is NO thread support we implement AtomicOps and
48 // Lock objects as no-ops. The other classes are not defined.
49 template<class C> class AtomicOps;
50 template<class T> class AtomicInt;
51 template<class T> class AtomicPtr;
52 
53 class Lock;
54 
55 
56 //-----------------------------------------------------------------------------------
57 // ***** AtomicOps
58 
59 // Atomic operations are provided by the AtomicOps templates class,
60 // implemented through system-specific AtomicOpsRaw specializations.
61 // It provides several fundamental operations such as Exchange, ExchangeAdd
62 // CompareAndSet, and Store_Release. Each function includes several memory
63 // synchronization versions, important for multiprocessing CPUs with weak
64 // memory consistency. The following memory fencing strategies are supported:
65 //
66 // - NoSync. No memory synchronization is done for atomic op.
67 // - Release. All other memory writes are completed before atomic op
68 // writes its results.
69 // - Acquire. Further memory reads are forced to wait until atomic op
70 // executes, guaranteeing that the right values will be seen.
71 // - Sync. A combination of Release and Acquire.
72 
73 
74 // *** AtomicOpsRaw
75 
76 // AtomicOpsRaw is a specialized template that provides atomic operations
77 // used by AtomicOps. This class has two fundamental qualities: (1) it
78 // defines a type T of correct size, and (2) provides operations that work
79 // atomically, such as Exchange_Sync and CompareAndSet_Release.
80 
81 // AtomicOpsRawBase class contains shared constants/classes for AtomicOpsRaw.
82 // The primary thing is does is define sync class objects, whose destructor and
83 // constructor provide places to insert appropriate synchronization calls, on
84 // systems where such calls are necessary. So far, the breakdown is as follows:
85 //
86 // - X86 systems don't need custom syncs, since their exchange/atomic
87 // instructions are implicitly synchronized.
88 // - PowerPC requires lwsync/isync instructions that can use this mechanism.
89 // - If some other systems require a mechanism where syncing type is associated
90 // with a particular instruction, the default implementation (which implements
91 // all Sync, Acquire, and Release modes in terms of NoSync and fence) may not
92 // work. Ii that case it will need to be #ifdef-ed conditionally.
93 
95 {
96 #if !defined(OVR_ENABLE_THREADS) || defined(OVR_CPU_X86) || defined(OVR_OS_WIN32) || defined(OVR_OS_IPHONE)
97  // Need to have empty constructor to avoid class 'unused' variable warning.
98  struct FullSync { inline FullSync() { } };
99  struct AcquireSync { inline AcquireSync() { } };
100  struct ReleaseSync { inline ReleaseSync() { } };
101 
102 #elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
103  struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("isync\n"); } };
104  struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("isync\n"); } };
105  struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
106 
107 #elif defined(OVR_CPU_MIPS)
108  struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("sync\n"); } };
109  struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("sync\n"); } };
110  struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
111 
112 #elif defined(OVR_CPU_ARM)
113  struct FullSync { inline FullSync() { asm volatile("dmb\n"); } ~FullSync() { asm volatile("dmb\n"); } };
114  struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("dmb\n"); } };
115  struct ReleaseSync { inline ReleaseSync() { asm volatile("dmb\n"); } };
116 
117 
118 #elif defined(OVR_CC_GNU) && (__GNUC__ >= 4)
119  // __sync functions are already full sync
120  struct FullSync { inline FullSync() { } };
121  struct AcquireSync { inline AcquireSync() { } };
122  struct ReleaseSync { inline ReleaseSync() { } };
123 #endif
124 };
125 
126 
127 // 4-Byte raw data atomic op implementation class.
129 {
130 #if !defined(OVR_ENABLE_THREADS)
131 
132  // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
133  typedef UInt32 T;
134 
135  // *** Thread - Safe Atomic Versions.
136 
137 #elif defined(OVR_OS_WIN32)
138 
139  // Use special defined for VC6, where volatile is not used and
140  // InterlockedCompareExchange is declared incorrectly.
141  typedef LONG T;
142 #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC < 1300)
143  typedef T* InterlockTPtr;
144  typedef LPVOID ET;
145  typedef ET* InterlockETPtr;
146 #else
147  typedef volatile T* InterlockTPtr;
148  typedef T ET;
149  typedef InterlockTPtr InterlockETPtr;
150 #endif
151  inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange((InterlockTPtr)p, val); }
152  inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd((InterlockTPtr)p, val); }
153  inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange((InterlockETPtr)p, (ET)val, (ET)c) == (ET)c; }
154 
155 #elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
156  typedef UInt32 T;
157  static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
158  {
159  UInt32 ret;
160 
161  asm volatile("1:\n\t"
162  "lwarx %[r],0,%[i]\n\t"
163  "stwcx. %[j],0,%[i]\n\t"
164  "bne- 1b\n"
165  : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
166 
167  return ret;
168  }
169 
170  static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
171  {
172  UInt32 dummy, ret;
173 
174  asm volatile("1:\n\t"
175  "lwarx %[r],0,%[i]\n\t"
176  "add %[o],%[r],%[j]\n\t"
177  "stwcx. %[o],0,%[i]\n\t"
178  "bne- 1b\n"
179  : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
180 
181  return ret;
182  }
183 
184  static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
185  {
186  UInt32 ret;
187 
188  asm volatile("1:\n\t"
189  "lwarx %[r],0,%[i]\n\t"
190  "cmpw 0,%[r],%[cmp]\n\t"
191  "mfcr %[r]\n\t"
192  "bne- 2f\n\t"
193  "stwcx. %[val],0,%[i]\n\t"
194  "bne- 1b\n\t"
195  "2:\n"
196  : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc", "memory");
197 
198  return (ret & 0x20000000) ? 1 : 0;
199  }
200 
201 #elif defined(OVR_CPU_MIPS)
202  typedef UInt32 T;
203 
204  static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
205  {
206  UInt32 ret;
207 
208  asm volatile("1:\n\t"
209  "ll %[r],0(%[i])\n\t"
210  "sc %[j],0(%[i])\n\t"
211  "beq %[j],$0,1b\n\t"
212  "nop \n"
213  : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
214 
215  return ret;
216  }
217 
218  static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
219  {
220  UInt32 ret;
221 
222  asm volatile("1:\n\t"
223  "ll %[r],0(%[i])\n\t"
224  "addu %[j],%[r],%[j]\n\t"
225  "sc %[j],0(%[i])\n\t"
226  "beq %[j],$0,1b\n\t"
227  "nop \n"
228  : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
229 
230  return ret;
231  }
232 
233  static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
234  {
235  UInt32 ret, dummy;
236 
237  asm volatile("1:\n\t"
238  "move %[r],$0\n\t"
239  "ll %[o],0(%[i])\n\t"
240  "bne %[o],%[c],2f\n\t"
241  "move %[r],%[v]\n\t"
242  "sc %[r],0(%[i])\n\t"
243  "beq %[r],$0,1b\n\t"
244  "nop \n\t"
245  "2:\n"
246  : "+m" (*i),[r] "=&d" (ret), [o] "=&d" (dummy) : [i] "d" (i), [c] "d" (c), [v] "d" (value)
247  : "cc", "memory");
248 
249  return ret;
250  }
251 
252 #elif defined(OVR_CPU_ARM) && defined(OVR_CC_ARM)
253  typedef UInt32 T;
254 
255  static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
256  {
257  for(;;)
258  {
259  T r = __ldrex(i);
260  if (__strex(j, i) == 0)
261  return r;
262  }
263  }
264  static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
265  {
266  for(;;)
267  {
268  T r = __ldrex(i);
269  if (__strex(r + j, i) == 0)
270  return r;
271  }
272  }
273 
274  static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
275  {
276  for(;;)
277  {
278  T r = __ldrex(i);
279  if (r != c)
280  return 0;
281  if (__strex(value, i) == 0)
282  return 1;
283  }
284  }
285 
286 #elif defined(OVR_CPU_ARM)
287  typedef UInt32 T;
288 
289  static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
290  {
291  UInt32 ret, dummy;
292 
293  asm volatile("1:\n\t"
294  "ldrex %[r],[%[i]]\n\t"
295  "strex %[t],%[j],[%[i]]\n\t"
296  "cmp %[t],#0\n\t"
297  "bne 1b\n\t"
298  : "+m" (*i), [r] "=&r" (ret), [t] "=&r" (dummy) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
299 
300  return ret;
301  }
302 
303  static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
304  {
305  UInt32 ret, dummy, test;
306 
307  asm volatile("1:\n\t"
308  "ldrex %[r],[%[i]]\n\t"
309  "add %[o],%[r],%[j]\n\t"
310  "strex %[t],%[o],[%[i]]\n\t"
311  "cmp %[t],#0\n\t"
312  "bne 1b\n\t"
313  : "+m" (*i), [r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
314 
315  return ret;
316  }
317 
318  static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
319  {
320  UInt32 ret = 1, dummy, test;
321 
322  asm volatile("1:\n\t"
323  "ldrex %[o],[%[i]]\n\t"
324  "cmp %[o],%[c]\n\t"
325  "bne 2f\n\t"
326  "strex %[r],%[v],[%[i]]\n\t"
327  "cmp %[r],#0\n\t"
328  "bne 1b\n\t"
329  "2:\n"
330  : "+m" (*i),[r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [c] "r" (c), [v] "r" (value)
331  : "cc", "memory");
332 
333  return !ret;
334  }
335 
336 #elif defined(OVR_CPU_X86)
337  typedef UInt32 T;
338 
339  static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
340  {
341  asm volatile("xchgl %1,%[i]\n"
342  : "+m" (*i), "=q" (j) : [i] "m" (*i), "1" (j) : "cc", "memory");
343 
344  return j;
345  }
346 
347  static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
348  {
349  asm volatile("lock; xaddl %1,%[i]\n"
350  : "+m" (*i), "+q" (j) : [i] "m" (*i) : "cc", "memory");
351 
352  return j;
353  }
354 
355  static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
356  {
357  UInt32 ret;
358 
359  asm volatile("lock; cmpxchgl %[v],%[i]\n"
360  : "+m" (*i), "=a" (ret) : [i] "m" (*i), "1" (c), [v] "q" (value) : "cc", "memory");
361 
362  return (ret == c);
363  }
364 
365 #elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
366 
367  typedef UInt32 T;
368 
369  static inline T Exchange_NoSync(volatile T *i, T j)
370  {
371  T v;
372  do {
373  v = *i;
374  } while (!__sync_bool_compare_and_swap(i, v, j));
375  return v;
376  }
377 
378  static inline T ExchangeAdd_NoSync(volatile T *i, T j)
379  {
380  return __sync_fetch_and_add(i, j);
381  }
382 
383  static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
384  {
385  return __sync_bool_compare_and_swap(i, c, value);
386  }
387 
388 #endif // OS
389 };
390 
391 
392 // 8-Byte raw data data atomic op implementation class.
393 // Currently implementation is provided only on systems with 64-bit pointers.
395 {
396 #if !defined(OVR_64BIT_POINTERS) || !defined(OVR_ENABLE_THREADS)
397 
398  // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
399  typedef UInt64 T;
400 
401  // *** Thread - Safe OS specific versions.
402 #elif defined(OVR_OS_WIN32)
403 
404  // This is only for 64-bit systems.
405  typedef LONG64 T;
406  typedef volatile T* InterlockTPtr;
407  inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange64((InterlockTPtr)p, val); }
408  inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd64((InterlockTPtr)p, val); }
409  inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange64((InterlockTPtr)p, val, c) == c; }
410 
411 #elif defined(OVR_CPU_PPC64)
412 
413  typedef UInt64 T;
414 
415  static inline UInt64 Exchange_NoSync(volatile UInt64 *i, UInt64 j)
416  {
417  UInt64 dummy, ret;
418 
419  asm volatile("1:\n\t"
420  "ldarx %[r],0,%[i]\n\t"
421  "mr %[o],%[j]\n\t"
422  "stdcx. %[o],0,%[i]\n\t"
423  "bne- 1b\n"
424  : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
425 
426  return ret;
427  }
428 
429  static inline UInt64 ExchangeAdd_NoSync(volatile UInt64 *i, UInt64 j)
430  {
431  UInt64 dummy, ret;
432 
433  asm volatile("1:\n\t"
434  "ldarx %[r],0,%[i]\n\t"
435  "add %[o],%[r],%[j]\n\t"
436  "stdcx. %[o],0,%[i]\n\t"
437  "bne- 1b\n"
438  : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
439 
440  return ret;
441  }
442 
443  static inline bool CompareAndSet_NoSync(volatile UInt64 *i, UInt64 c, UInt64 value)
444  {
445  UInt64 ret, dummy;
446 
447  asm volatile("1:\n\t"
448  "ldarx %[r],0,%[i]\n\t"
449  "cmpw 0,%[r],%[cmp]\n\t"
450  "mfcr %[r]\n\t"
451  "bne- 2f\n\t"
452  "stdcx. %[val],0,%[i]\n\t"
453  "bne- 1b\n\t"
454  "2:\n"
455  : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc");
456 
457  return (ret & 0x20000000) ? 1 : 0;
458  }
459 
460 #elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
461 
462  typedef UInt64 T;
463 
464  static inline T Exchange_NoSync(volatile T *i, T j)
465  {
466  T v;
467  do {
468  v = *i;
469  } while (!__sync_bool_compare_and_swap(i, v, j));
470  return v;
471  }
472 
473  static inline T ExchangeAdd_NoSync(volatile T *i, T j)
474  {
475  return __sync_fetch_and_add(i, j);
476  }
477 
478  static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
479  {
480  return __sync_bool_compare_and_swap(i, c, value);
481  }
482 
483 #endif // OS
484 };
485 
486 
487 // Default implementation for AtomicOpsRaw; provides implementation of mem-fenced
488 // atomic operations where fencing is done with a sync object wrapped around a NoSync
489 // operation implemented in the base class. If such implementation is not possible
490 // on a given platform, #ifdefs can be used to disable it and then op functions can be
491 // implemented individually in the appropriate AtomicOpsRaw<size> class.
492 
493 template<class O>
494 struct AtomicOpsRaw_DefImpl : public O
495 {
496  typedef typename O::T O_T;
497  typedef typename O::FullSync O_FullSync;
498  typedef typename O::AcquireSync O_AcquireSync;
499  typedef typename O::ReleaseSync O_ReleaseSync;
500 
501  // If there is no thread support, provide the default implementation. In this case,
502  // the base class (0) must still provide the T declaration.
503 #ifndef OVR_ENABLE_THREADS
504 
505  // Atomic exchange of val with argument. Returns old val.
506  inline static O_T Exchange_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p = val; return old; }
507  // Adds a new val to argument; returns its old val.
508  inline static O_T ExchangeAdd_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p += val; return old; }
509  // Compares the argument data with 'c' val.
510  // If succeeded, stores val int '*p' and returns true; otherwise returns false.
511  inline static bool CompareAndSet_NoSync(volatile O_T* p, O_T c, O_T val) { if (*p==c) { *p = val; return 1; } return 0; }
512 
513 #endif
514 
515  // If NoSync wrapped implementation may not be possible, it this block should be
516  // replaced with per-function implementation in O.
517  // "AtomicOpsRaw_DefImpl<O>::" prefix in calls below.
518  inline static O_T Exchange_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
519  inline static O_T Exchange_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
520  inline static O_T Exchange_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
521  inline static O_T ExchangeAdd_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
522  inline static O_T ExchangeAdd_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
523  inline static O_T ExchangeAdd_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
524  inline static bool CompareAndSet_Sync(volatile O_T* p, O_T c, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
525  inline static bool CompareAndSet_Release(volatile O_T* p, O_T c, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
526  inline static bool CompareAndSet_Acquire(volatile O_T* p, O_T c, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
527 
528  // Loads and stores with memory fence. These have only the relevant versions.
529 #ifdef OVR_CPU_X86
530  // On X86, Store_Release is implemented as exchange. Note that we can also
531  // consider 'sfence' in the future, although it is not as compatible with older CPUs.
532  inline static void Store_Release(volatile O_T* p, O_T val) { Exchange_Release(p, val); }
533 #else
534  inline static void Store_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); *p = val; }
535 #endif
536  inline static O_T Load_Acquire(const volatile O_T* p) { O_AcquireSync sync; OVR_UNUSED(sync); return *p; }
537 };
538 
539 
540 template<int size>
541 struct AtomicOpsRaw : public AtomicOpsRawBase { };
542 
543 template<>
544 struct AtomicOpsRaw<4> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>
545 {
546  // Ensure that assigned type size is correct.
549 };
550 template<>
551 struct AtomicOpsRaw<8> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>
552 {
555 };
556 
557 
558 // *** AtomicOps - implementation of atomic Ops for specified class
559 
560 // Implements atomic ops on a class, provided that the object is either
561 // 4 or 8 bytes in size (depending on the AtomicOpsRaw specializations
562 // available). Relies on AtomicOpsRaw for much of implementation.
563 
564 template<class C>
565 class AtomicOps
566 {
568  typedef typename Ops::T T;
569  typedef volatile typename Ops::T* PT;
570  // We cast through unions to (1) avoid pointer size compiler warnings
571  // and (2) ensure that there are no problems with strict pointer aliasing.
572  union C2T_union { C c; T t; };
573 
574 public:
575  // General purpose implementation for standard syncs.
576  inline static C Exchange_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Sync((PT)p, u.t); return u.c; }
577  inline static C Exchange_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Release((PT)p, u.t); return u.c; }
578  inline static C Exchange_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Acquire((PT)p, u.t); return u.c; }
579  inline static C Exchange_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_NoSync((PT)p, u.t); return u.c; }
580  inline static C ExchangeAdd_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Sync((PT)p, u.t); return u.c; }
581  inline static C ExchangeAdd_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Release((PT)p, u.t); return u.c; }
582  inline static C ExchangeAdd_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Acquire((PT)p, u.t); return u.c; }
583  inline static C ExchangeAdd_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_NoSync((PT)p, u.t); return u.c; }
584  inline static bool CompareAndSet_Sync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Sync((PT)p, cu.t, u.t); }
585  inline static bool CompareAndSet_Release(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Release((PT)p, cu.t, u.t); }
586  inline static bool CompareAndSet_Relse(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); }
587  inline static bool CompareAndSet_NoSync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_NoSync((PT)p, cu.t, u.t); }
588  // Loads and stores with memory fence. These have only the relevant versions.
589  inline static void Store_Release(volatile C* p, C val) { C2T_union u; u.c = val; Ops::Store_Release((PT)p, u.t); }
590  inline static C Load_Acquire(const volatile C* p) { C2T_union u; u.t = Ops::Load_Acquire((PT)p); return u.c; }
591 };
592 
593 
594 
595 // Atomic value base class - implements operations shared for integers and pointers.
596 template<class T>
598 {
599 protected:
600  typedef AtomicOps<T> Ops;
601 public:
602 
603  volatile T Value;
604 
605  inline AtomicValueBase() { }
606  explicit inline AtomicValueBase(T val) { Ops::Store_Release(&Value, val); }
607 
608  // Most libraries (TBB and Joshua Scholar's) library do not do Load_Acquire
609  // here, since most algorithms do not require atomic loads. Needs some research.
610  inline operator T() const { return Value; }
611 
612  // *** Standard Atomic inlines
613  inline T Exchange_Sync(T val) { return Ops::Exchange_Sync(&Value, val); }
614  inline T Exchange_Release(T val) { return Ops::Exchange_Release(&Value, val); }
615  inline T Exchange_Acquire(T val) { return Ops::Exchange_Acquire(&Value, val); }
616  inline T Exchange_NoSync(T val) { return Ops::Exchange_NoSync(&Value, val); }
617  inline bool CompareAndSet_Sync(T c, T val) { return Ops::CompareAndSet_Sync(&Value, c, val); }
618  inline bool CompareAndSet_Release(T c, T val) { return Ops::CompareAndSet_Release(&Value, c, val); }
619  inline bool CompareAndSet_Acquire(T c, T val) { return Ops::CompareAndSet_Relse(&Value, c, val); }
620  inline bool CompareAndSet_NoSync(T c, T val) { return Ops::CompareAndSet_NoSync(&Value, c, val); }
621  // Load & Store.
622  inline void Store_Release(T val) { Ops::Store_Release(&Value, val); }
623  inline T Load_Acquire() const { return Ops::Load_Acquire(&Value); }
624 };
625 
626 
627 // ***** AtomicPtr - Atomic pointer template
628 
629 // This pointer class supports atomic assignments with release,
630 // increment / decrement operations, and conditional compare + set.
631 
632 template<class T>
633 class AtomicPtr : public AtomicValueBase<T*>
634 {
635  typedef typename AtomicValueBase<T*>::Ops Ops;
636 
637 public:
638  // Initialize pointer value to 0 by default; use Store_Release only with explicit constructor.
639  inline AtomicPtr() : AtomicValueBase<T*>() { this->Value = 0; }
640  explicit inline AtomicPtr(T* val) : AtomicValueBase<T*>(val) { }
641 
642  // Pointer access.
643  inline T* operator -> () const { return this->Load_Acquire(); }
644 
645  // It looks like it is convenient to have Load_Acquire characteristics
646  // for this, since that is convenient for algorithms such as linked
647  // list traversals that can be added to bu another thread.
648  inline operator T* () const { return this->Load_Acquire(); }
649 
650 
651  // *** Standard Atomic inlines (applicable to pointers)
652 
653  // ExhangeAdd considers pointer size for pointers.
654  template<class I>
655  inline T* ExchangeAdd_Sync(I incr) { return Ops::ExchangeAdd_Sync(&this->Value, ((T*)0) + incr); }
656  template<class I>
657  inline T* ExchangeAdd_Release(I incr) { return Ops::ExchangeAdd_Release(&this->Value, ((T*)0) + incr); }
658  template<class I>
659  inline T* ExchangeAdd_Acquire(I incr) { return Ops::ExchangeAdd_Acquire(&this->Value, ((T*)0) + incr); }
660  template<class I>
661  inline T* ExchangeAdd_NoSync(I incr) { return Ops::ExchangeAdd_NoSync(&this->Value, ((T*)0) + incr); }
662 
663  // *** Atomic Operators
664 
665  inline T* operator = (T* val) { this->Store_Release(val); return val; }
666 
667  template<class I>
668  inline T* operator += (I val) { return ExchangeAdd_Sync(val) + val; }
669  template<class I>
670  inline T* operator -= (I val) { return operator += (-val); }
671 
672  inline T* operator ++ () { return ExchangeAdd_Sync(1) + 1; }
673  inline T* operator -- () { return ExchangeAdd_Sync(-1) - 1; }
674  inline T* operator ++ (int) { return ExchangeAdd_Sync(1); }
675  inline T* operator -- (int) { return ExchangeAdd_Sync(-1); }
676 };
677 
678 
679 // ***** AtomicInt - Atomic integer template
680 
681 // Implements an atomic integer type; the exact type to use is provided
682 // as an argument. Supports atomic Acquire / Release semantics, atomic
683 // arithmetic operations, and atomic conditional compare + set.
684 
685 template<class T>
686 class AtomicInt : public AtomicValueBase<T>
687 {
688  typedef typename AtomicValueBase<T>::Ops Ops;
689 
690 public:
691  inline AtomicInt() : AtomicValueBase<T>() { }
692  explicit inline AtomicInt(T val) : AtomicValueBase<T>(val) { }
693 
694 
695  // *** Standard Atomic inlines (applicable to int)
696  inline T ExchangeAdd_Sync(T val) { return Ops::ExchangeAdd_Sync(&this->Value, val); }
697  inline T ExchangeAdd_Release(T val) { return Ops::ExchangeAdd_Release(&this->Value, val); }
698  inline T ExchangeAdd_Acquire(T val) { return Ops::ExchangeAdd_Acquire(&this->Value, val); }
699  inline T ExchangeAdd_NoSync(T val) { return Ops::ExchangeAdd_NoSync(&this->Value, val); }
700  // These increments could be more efficient because they don't return a value.
701  inline void Increment_Sync() { ExchangeAdd_Sync((T)1); }
702  inline void Increment_Release() { ExchangeAdd_Release((T)1); }
703  inline void Increment_Acquire() { ExchangeAdd_Acquire((T)1); }
704  inline void Increment_NoSync() { ExchangeAdd_NoSync((T)1); }
705 
706  // *** Atomic Operators
707 
708  inline T operator = (T val) { this->Store_Release(val); return val; }
709  inline T operator += (T val) { return ExchangeAdd_Sync(val) + val; }
710  inline T operator -= (T val) { return ExchangeAdd_Sync(0 - val) - val; }
711 
712  inline T operator ++ () { return ExchangeAdd_Sync((T)1) + 1; }
713  inline T operator -- () { return ExchangeAdd_Sync(((T)0)-1) - 1; }
714  inline T operator ++ (int) { return ExchangeAdd_Sync((T)1); }
715  inline T operator -- (int) { return ExchangeAdd_Sync(((T)0)-1); }
716 
717  // More complex atomic operations. Leave it to compiler whether to optimize them or not.
718  T operator &= (T arg)
719  {
720  T comp, newVal;
721  do {
722  comp = this->Value;
723  newVal = comp & arg;
724  } while(!this->CompareAndSet_Sync(comp, newVal));
725  return newVal;
726  }
727 
728  T operator |= (T arg)
729  {
730  T comp, newVal;
731  do {
732  comp = this->Value;
733  newVal = comp | arg;
734  } while(!this->CompareAndSet_Sync(comp, newVal));
735  return newVal;
736  }
737 
738  T operator ^= (T arg)
739  {
740  T comp, newVal;
741  do {
742  comp = this->Value;
743  newVal = comp ^ arg;
744  } while(!this->CompareAndSet_Sync(comp, newVal));
745  return newVal;
746  }
747 
748  T operator *= (T arg)
749  {
750  T comp, newVal;
751  do {
752  comp = this->Value;
753  newVal = comp * arg;
754  } while(!this->CompareAndSet_Sync(comp, newVal));
755  return newVal;
756  }
757 
758  T operator /= (T arg)
759  {
760  T comp, newVal;
761  do {
762  comp = this->Value;
763  newVal = comp / arg;
764  } while(!CompareAndSet_Sync(comp, newVal));
765  return newVal;
766  }
767 
768  T operator >>= (unsigned bits)
769  {
770  T comp, newVal;
771  do {
772  comp = this->Value;
773  newVal = comp >> bits;
774  } while(!CompareAndSet_Sync(comp, newVal));
775  return newVal;
776  }
777 
778  T operator <<= (unsigned bits)
779  {
780  T comp, newVal;
781  do {
782  comp = this->Value;
783  newVal = comp << bits;
784  } while(!this->CompareAndSet_Sync(comp, newVal));
785  return newVal;
786  }
787 };
788 
789 
790 
791 //-----------------------------------------------------------------------------------
792 // ***** Lock
793 
794 // Lock is a simplest and most efficient mutual-exclusion lock class.
795 // Unlike Mutex, it cannot be waited on.
796 
797 class Lock
798 {
799  // NOTE: Locks are not allocatable and they themselves should not allocate
800  // memory by standard means. This is the case because StandardAllocator
801  // relies on this class.
802  // Make 'delete' private. Don't do this for 'new' since it can be redefined.
803  void operator delete(void*) {}
804 
805 
806  // *** Lock implementation for various platforms.
807 
808 #if !defined(OVR_ENABLE_THREADS)
809 
810 public:
811  // With no thread support, lock does nothing.
812  inline Lock() { }
813  inline Lock(unsigned) { }
814  inline ~Lock() { }
815  inline void DoLock() { }
816  inline void Unlock() { }
817 
818  // Windows.
819 #elif defined(OVR_OS_WIN32)
820 
821  CRITICAL_SECTION cs;
822 public:
823  Lock(unsigned spinCount = 0);
824  ~Lock();
825  // Locking functions.
826  inline void DoLock() { ::EnterCriticalSection(&cs); }
827  inline void Unlock() { ::LeaveCriticalSection(&cs); }
828 
829 #else
831 
832 public:
834  static bool RecursiveAttrInit;
835 
836  Lock (unsigned dummy = 0)
837  {
838  OVR_UNUSED(dummy);
839  if (!RecursiveAttrInit)
840  {
841  pthread_mutexattr_init(&RecursiveAttr);
842  pthread_mutexattr_settype(&RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
843  RecursiveAttrInit = 1;
844  }
845  pthread_mutex_init(&mutex,&RecursiveAttr);
846  }
847  ~Lock () { pthread_mutex_destroy(&mutex); }
848  inline void DoLock() { pthread_mutex_lock(&mutex); }
849  inline void Unlock() { pthread_mutex_unlock(&mutex); }
850 
851 #endif // OVR_ENABLE_THREDS
852 
853 
854 public:
855  // Locker class, used for automatic locking
856  class Locker
857  {
858  public:
860  inline Locker(Lock *plock)
861  { pLock = plock; pLock->DoLock(); }
862  inline ~Locker()
863  { pLock->Unlock(); }
864  };
865 };
866 
867 
868 //-------------------------------------------------------------------------------------
869 // Globally shared Lock implementation used for MessageHandlers, etc.
870 
872 {
873 public:
875 
876  Lock* GetLockAddRef();
877  void ReleaseLock(Lock* plock);
878 
879 private:
880  Lock* toLock() { return (Lock*)Buffer; }
881 
882  // UseCount and max alignment.
883  volatile int UseCount;
884  UInt64 Buffer[(sizeof(Lock)+sizeof(UInt64)-1)/sizeof(UInt64)];
885 };
886 
887 
888 } // OVR
889 
890 #endif
void ReleaseLock(Lock *plock)
Definition: OVR_Atomic.cpp:131
static O_T Exchange_Release(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:519
static C Exchange_Acquire(volatile C *p, C val)
Definition: OVR_Atomic.h:578
AtomicValueBase< T >::Ops Ops
Definition: OVR_Atomic.h:688
bool CompareAndSet_NoSync(T c, T val)
Definition: OVR_Atomic.h:620
static bool RecursiveAttrInit
Definition: OVR_Atomic.h:834
static C Exchange_Release(volatile C *p, C val)
Definition: OVR_Atomic.h:577
static bool CompareAndSet_Sync(volatile O_T *p, O_T c, O_T val)
Definition: OVR_Atomic.h:524
static O_T Exchange_Sync(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:518
bool CompareAndSet_Acquire(T c, T val)
Definition: OVR_Atomic.h:619
T ExchangeAdd_NoSync(T val)
Definition: OVR_Atomic.h:699
T ExchangeAdd_Acquire(T val)
Definition: OVR_Atomic.h:698
bool CompareAndSet_Sync(T c, T val)
Definition: OVR_Atomic.h:617
T * operator++()
Definition: OVR_Atomic.h:672
uint64_t UInt64
Definition: OVR_Types.h:255
T ExchangeAdd_Release(T val)
Definition: OVR_Atomic.h:697
T * operator=(T *val)
Definition: OVR_Atomic.h:665
static O_T Load_Acquire(const volatile O_T *p)
Definition: OVR_Atomic.h:536
T * operator-=(I val)
Definition: OVR_Atomic.h:670
T * ExchangeAdd_Sync(I incr)
Definition: OVR_Atomic.h:655
uint32_t UInt32
Definition: OVR_Types.h:253
static C Exchange_NoSync(volatile C *p, C val)
Definition: OVR_Atomic.h:579
T operator+=(T val)
Definition: OVR_Atomic.h:709
T operator<<=(unsigned bits)
Definition: OVR_Atomic.h:778
#define OVR_UNUSED(a)
pthread_mutex_t mutex
Definition: OVR_Atomic.h:830
static bool CompareAndSet_Release(volatile C *p, C c, C val)
Definition: OVR_Atomic.h:585
static pthread_mutexattr_t RecursiveAttr
Definition: OVR_Atomic.h:833
static C ExchangeAdd_Release(volatile C *p, C val)
Definition: OVR_Atomic.h:581
Locker(Lock *plock)
Definition: OVR_Atomic.h:860
AtomicOpsRaw< sizeof(C)> Ops
Definition: OVR_Atomic.h:567
void DoLock()
Definition: OVR_Atomic.h:848
T operator*=(T arg)
Definition: OVR_Atomic.h:748
T Exchange_Release(T val)
Definition: OVR_Atomic.h:614
static void Store_Release(volatile C *p, C val)
Definition: OVR_Atomic.h:589
AtomicInt(T val)
Definition: OVR_Atomic.h:692
static bool CompareAndSet_Release(volatile O_T *p, O_T c, O_T val)
Definition: OVR_Atomic.h:525
static bool CompareAndSet_NoSync(volatile C *p, C c, C val)
Definition: OVR_Atomic.h:587
AtomicOps< T > Ops
Definition: OVR_Atomic.h:600
static O_T ExchangeAdd_Sync(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:521
void Store_Release(T val)
Definition: OVR_Atomic.h:622
O::AcquireSync O_AcquireSync
Definition: OVR_Atomic.h:498
T * ExchangeAdd_NoSync(I incr)
Definition: OVR_Atomic.h:661
T * operator->() const
Definition: OVR_Atomic.h:643
T * ExchangeAdd_Acquire(I incr)
Definition: OVR_Atomic.h:659
static bool CompareAndSet_Acquire(volatile O_T *p, O_T c, O_T val)
Definition: OVR_Atomic.h:526
T operator/=(T arg)
Definition: OVR_Atomic.h:758
T operator>>=(unsigned bits)
Definition: OVR_Atomic.h:768
static void Store_Release(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:534
static C ExchangeAdd_NoSync(volatile C *p, C val)
Definition: OVR_Atomic.h:583
void Increment_NoSync()
Definition: OVR_Atomic.h:704
Lock * GetLockAddRef()
Definition: OVR_Atomic.cpp:104
T operator|=(T arg)
Definition: OVR_Atomic.h:728
static bool CompareAndSet_Sync(volatile C *p, C c, C val)
Definition: OVR_Atomic.h:584
AtomicValueBase< T * >::Ops Ops
Definition: OVR_Atomic.h:635
T operator&=(T arg)
Definition: OVR_Atomic.h:718
volatile Ops::T * PT
Definition: OVR_Atomic.h:569
static O_T Exchange_Acquire(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:520
T operator-=(T val)
Definition: OVR_Atomic.h:710
AtomicPtr(T *val)
Definition: OVR_Atomic.h:640
T Load_Acquire() const
Definition: OVR_Atomic.h:623
static C ExchangeAdd_Acquire(volatile C *p, C val)
Definition: OVR_Atomic.h:582
T * operator--()
Definition: OVR_Atomic.h:673
UInt64 Buffer[(sizeof(Lock)+sizeof(UInt64)-1)/sizeof(UInt64)]
Definition: OVR_Atomic.h:884
void Increment_Sync()
Definition: OVR_Atomic.h:701
static C Load_Acquire(const volatile C *p)
Definition: OVR_Atomic.h:590
static O_T ExchangeAdd_Acquire(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:523
T Exchange_Acquire(T val)
Definition: OVR_Atomic.h:615
void Increment_Release()
Definition: OVR_Atomic.h:702
void Unlock()
Definition: OVR_Atomic.h:849
volatile int UseCount
Definition: OVR_Atomic.h:883
static C ExchangeAdd_Sync(volatile C *p, C val)
Definition: OVR_Atomic.h:580
static bool CompareAndSet_Relse(volatile C *p, C c, C val)
Definition: OVR_Atomic.h:586
Lock(unsigned dummy=0)
Definition: OVR_Atomic.h:836
T Exchange_Sync(T val)
Definition: OVR_Atomic.h:613
T operator=(T val)
Definition: OVR_Atomic.h:708
T ExchangeAdd_Sync(T val)
Definition: OVR_Atomic.h:696
T * operator+=(I val)
Definition: OVR_Atomic.h:668
Lock * toLock()
Definition: OVR_Atomic.h:880
bool CompareAndSet_Release(T c, T val)
Definition: OVR_Atomic.h:618
static O_T ExchangeAdd_Release(volatile O_T *p, O_T val)
Definition: OVR_Atomic.h:522
static C Exchange_Sync(volatile C *p, C val)
Definition: OVR_Atomic.h:576
T operator^=(T arg)
Definition: OVR_Atomic.h:738
T * ExchangeAdd_Release(I incr)
Definition: OVR_Atomic.h:657
#define OVR_COMPILER_ASSERT(x)
T Exchange_NoSync(T val)
Definition: OVR_Atomic.h:616
O::ReleaseSync O_ReleaseSync
Definition: OVR_Atomic.h:499
void Increment_Acquire()
Definition: OVR_Atomic.h:703