VTK
vtkAtomic.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Visualization Toolkit
4  Module: vtkAtomic.h
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
15 // .NAME vtkAtomic - Provides support for atomic integers
16 // .SECTION Description
17 // Objects of atomic types are C++ objects that are free from data races;
18 // that is, if one thread writes to an atomic object while another thread
19 // reads from it, the behavior is well-defined. vtkAtomic provides
20 // a subset of the std::atomic API and implementation for the following types,
21 // 32 bit signed and unsigned integers, 64 bit signed and unsigned integers,
22 // and pointers. For these types, vtkAtomic defines a
23 // number of operations that happen atomically - without interruption
24 // by another thread. Furthermore, these operations happen in a
25 // sequentially-consistent way and use full memory fences. This means
26 // that operations relating to atomic variables happen in the specified
27 // order and the results are made visible to other processing cores to
28 // guarantee proper sequential operation. Other memory access patterns
29 // supported by std::atomic are not currently supported.
30 //
31 // Note that when atomic operations are not available on a particular
32 // platform or compiler, mutexes, which are significantly slower, are used
33 // as a fallback.
34 
35 #ifndef vtkAtomic_h
36 #define vtkAtomic_h
37 
38 #include "vtkCommonCoreModule.h" // For export macro
39 #include "vtkAtomicTypeConcepts.h"
40 #include "vtkConfigure.h"
41 #include "vtkSystemIncludes.h"
42 #include "vtkType.h"
43 
44 #include <cstddef>
45 
46 
47 // Assume 64-bit atomic operations are not available on 32 bit platforms
48 #if defined(VTK_HAVE_SYNC_BUILTINS)
49 # define VTK_GCC_ATOMICS_32
50 # if VTK_SIZEOF_VOID_P == 8
51 # define VTK_GCC_ATOMICS_64
52 # endif
53 #elif defined(__APPLE__)
54 # include <libkern/OSAtomic.h>
55 # define VTK_APPLE_ATOMICS_32
56 # if VTK_SIZEOF_VOID_P == 8
57 # define VTK_APPLE_ATOMICS_64
58 # endif
59 #elif defined(_WIN32) && defined(_MSC_VER)
60 # define VTK_WINDOWS_ATOMICS_32
61 # if VTK_SIZEOF_VOID_P == 8
62 # define VTK_WINDOWS_ATOMICS_64
63 # endif
64 #endif
65 
66 
67 #if defined(_WIN32) && defined(_MSC_VER)
68 // disable warning about the padding due to alignment
69 # pragma warning(disable:4324)
70 # define VTK_ALIGN(X) __declspec(align(X))
71 #elif defined(__GNUC__) // gcc compatible compiler
72 # define VTK_ALIGN(X) __attribute__ ((aligned (X)))
73 #else
74 # define VTK_ALIGN(X)
75 #endif
76 
77 
79 
80 
81 #ifndef __VTK_WRAP__
82 namespace detail
83 {
84 
85 template <size_t size> class AtomicOps;
86 
87 #if defined(VTK_GCC_ATOMICS_64)
88 template <> class AtomicOps<8>
89 {
90 public:
91  typedef vtkTypeInt64 VTK_ALIGN(8) atomic_type;
92  typedef vtkTypeInt64 value_type;
93 
94  static value_type AddAndFetch(value_type *ref, value_type val)
95  {
96  return __sync_add_and_fetch(ref, val);
97  }
98 
99  static value_type SubAndFetch(value_type *ref, value_type val)
100  {
101  return __sync_sub_and_fetch(ref, val);
102  }
103 
104  static value_type PreIncrement(value_type *ref)
105  {
106  return __sync_add_and_fetch(ref, 1);
107  }
108 
109  static value_type PreDecrement(value_type *ref)
110  {
111  return __sync_sub_and_fetch(ref, 1);
112  }
113 
114  static value_type PostIncrement(value_type *ref)
115  {
116  return __sync_fetch_and_add(ref, 1);
117  }
118 
119  static value_type PostDecrement(value_type *ref)
120  {
121  return __sync_fetch_and_sub(ref, 1);
122  }
123 
124  static value_type Load(const value_type *ref)
125  {
126  __sync_synchronize();
127  return *static_cast<const volatile value_type *>(ref);
128  }
129 
130  static void Store(value_type *ref, value_type val)
131  {
132  *static_cast<volatile value_type*>(ref) = val;
133  __sync_synchronize();
134  }
135 };
136 
137 #elif defined(VTK_APPLE_ATOMICS_64)
138 template <> class AtomicOps<8>
139 {
140 public:
141  typedef vtkTypeInt64 VTK_ALIGN(8) atomic_type;
142  typedef vtkTypeInt64 value_type;
143 
144  static vtkTypeInt64 AddAndFetch(vtkTypeInt64 *ref, vtkTypeInt64 val)
145  {
146  return OSAtomicAdd64Barrier(val, ref);
147  }
148 
149  static vtkTypeInt64 SubAndFetch(vtkTypeInt64 *ref, vtkTypeInt64 val)
150  {
151  return OSAtomicAdd64Barrier(-val, ref);
152  }
153 
154  static vtkTypeInt64 PreIncrement(vtkTypeInt64 *ref)
155  {
156  return OSAtomicIncrement64Barrier(ref);
157  }
158 
159  static vtkTypeInt64 PreDecrement(vtkTypeInt64 *ref)
160  {
161  return OSAtomicDecrement64Barrier(ref);
162  }
163 
164  static vtkTypeInt64 PostIncrement(vtkTypeInt64 *ref)
165  {
166  vtkTypeInt64 val = OSAtomicIncrement64Barrier(ref);
167  return --val;
168  }
169 
170  static vtkTypeInt64 PostDecrement(vtkTypeInt64 *ref)
171  {
172  vtkTypeInt64 val = OSAtomicDecrement64Barrier(ref);
173  return ++val;
174  }
175 
176  static vtkTypeInt64 Load(const vtkTypeInt64 *ref);
177  {
178  OSMemoryBarrier();
179  return *static_cast<const volatile vtkTypeInt64*>(ref);
180  }
181 
182  static void Store(vtkTypeInt64 *ref, vtkTypeInt64 val);
183  {
184  *static_cast<volatile vtkTypeInt64*>(ref) = val;
185  OSMemoryBarrier();
186  }
187 };
188 
189 #else
190 
191 template <> class VTKCOMMONCORE_EXPORT AtomicOps<8>
192 {
193 public:
194 #if defined(VTK_WINDOWS_ATOMICS_64)
195  typedef vtkTypeInt64 VTK_ALIGN(8) atomic_type;
196 #else
197  struct VTKCOMMONCORE_EXPORT atomic_type
198  {
199  vtkTypeInt64 var;
201 
202  atomic_type(vtkTypeInt64 init);
203  ~atomic_type();
204  };
205 #endif
206  typedef vtkTypeInt64 value_type;
207 
208  static vtkTypeInt64 AddAndFetch(atomic_type *ref, vtkTypeInt64 val);
209  static vtkTypeInt64 SubAndFetch(atomic_type *ref, vtkTypeInt64 val);
210  static vtkTypeInt64 PreIncrement(atomic_type *ref);
211  static vtkTypeInt64 PreDecrement(atomic_type *ref);
212  static vtkTypeInt64 PostIncrement(atomic_type *ref);
213  static vtkTypeInt64 PostDecrement(atomic_type *ref);
214  static vtkTypeInt64 Load(const atomic_type *ref);
215  static void Store(atomic_type *ref, vtkTypeInt64 val);
216 };
217 
218 #endif
219 
220 #if defined(VTK_GCC_ATOMICS_32)
221 template <> class AtomicOps<4>
222 {
223 public:
224  typedef vtkTypeInt32 VTK_ALIGN(4) atomic_type;
225  typedef vtkTypeInt32 value_type;
226 
227  static value_type AddAndFetch(value_type *ref, value_type val)
228  {
229  return __sync_add_and_fetch(ref, val);
230  }
231 
233  {
234  return __sync_sub_and_fetch(ref, val);
235  }
236 
238  {
239  return __sync_add_and_fetch(ref, 1);
240  }
241 
243  {
244  return __sync_sub_and_fetch(ref, 1);
245  }
246 
248  {
249  return __sync_fetch_and_add(ref, 1);
250  }
251 
253  {
254  return __sync_fetch_and_sub(ref, 1);
255  }
256 
257  static value_type Load(const value_type *ref)
258  {
259  __sync_synchronize();
260  return *static_cast<const volatile value_type *>(ref);
261  }
262 
263  static void Store(value_type *ref, value_type val)
264  {
265  *static_cast<volatile value_type*>(ref) = val;
266  __sync_synchronize();
267  }
268 };
269 
270 #elif defined(VTK_APPLE_ATOMICS_32)
271 template <> class AtomicOps<4>
272 {
273 public:
274  typedef vtkTypeInt32 VTK_ALIGN(4) atomic_type;
275  typedef vtkTypeInt32 value_type;
276 
277  static vtkTypeInt32 AddAndFetch(vtkTypeInt32 *ref, vtkTypeInt32 val)
278  {
279  return OSAtomicAdd32Barrier(val, ref);
280  }
281 
282  static vtkTypeInt32 SubAndFetch(vtkTypeInt32 *ref, vtkTypeInt32 val)
283  {
284  return OSAtomicAdd32Barrier(-val, ref);
285  }
286 
287  static vtkTypeInt32 PreIncrement(vtkTypeInt32 *ref)
288  {
289  return OSAtomicIncrement32Barrier(ref);
290  }
291 
292  static vtkTypeInt32 PreDecrement(vtkTypeInt32 *ref)
293  {
294  return OSAtomicDecrement32Barrier(ref);
295  }
296 
297  static vtkTypeInt32 PostIncrement(vtkTypeInt32 *ref)
298  {
299  vtkTypeInt32 val = OSAtomicIncrement32Barrier(ref);
300  return --val;
301  }
302 
303  static vtkTypeInt32 PostDecrement(vtkTypeInt32 *ref)
304  {
305  vtkTypeInt32 val = OSAtomicDecrement32Barrier(ref);
306  return ++val;
307  }
308 
309  static vtkTypeInt32 Load(const vtkTypeInt32 *ref);
310  {
311  OSMemoryBarrier();
312  return *static_cast<const volatile vtkTypeInt32*>(ref);
313  }
314 
315  static void Store(vtkTypeInt32 *ref, vtkTypeInt32 val);
316  {
317  *static_cast<volatile vtkTypeInt32*>(ref) = val;
318  OSMemoryBarrier();
319  }
320 };
321 
322 #else
323 
324 template <> class VTKCOMMONCORE_EXPORT AtomicOps<4>
325 {
326 public:
327 #if defined(VTK_WINDOWS_ATOMICS_32)
328  typedef vtkTypeInt32 VTK_ALIGN(4) atomic_type;
329 #else
330  struct VTKCOMMONCORE_EXPORT atomic_type
331  {
332  vtkTypeInt32 var;
334 
335  atomic_type(vtkTypeInt32 init);
336  ~atomic_type();
337  };
338 #endif
339  typedef vtkTypeInt32 value_type;
340 
341  static vtkTypeInt32 AddAndFetch(atomic_type *ref, vtkTypeInt32 val);
342  static vtkTypeInt32 SubAndFetch(atomic_type *ref, vtkTypeInt32 val);
343  static vtkTypeInt32 PreIncrement(atomic_type *ref);
344  static vtkTypeInt32 PreDecrement(atomic_type *ref);
345  static vtkTypeInt32 PostIncrement(atomic_type *ref);
346  static vtkTypeInt32 PostDecrement(atomic_type *ref);
347  static vtkTypeInt32 Load(const atomic_type *ref);
348  static void Store(atomic_type *ref, vtkTypeInt32 val);
349 };
350 
351 #endif
352 }
353 #endif // __VTK_WRAP__
354 
355 template <typename T> class vtkAtomic : private vtk::atomic::detail::IntegralType<T>
356 {
357 private:
358  typedef detail::AtomicOps<sizeof(T)> Impl;
359 
360 public:
361  vtkAtomic() : Atomic(0)
362  {
363  }
364 
365  vtkAtomic(T val) : Atomic(static_cast<typename Impl::value_type>(val))
366  {
367  }
368 
369  vtkAtomic(const vtkAtomic<T> &atomic)
370  : Atomic(static_cast<typename Impl::value_type>(atomic.load()))
371  {
372  }
373 
375  {
376  return static_cast<T>(Impl::PreIncrement(&this->Atomic));
377  }
378 
379  T operator++(int)
380  {
381  return static_cast<T>(Impl::PostIncrement(&this->Atomic));
382  }
383 
385  {
386  return static_cast<T>(Impl::PreDecrement(&this->Atomic));
387  }
388 
389  T operator--(int)
390  {
391  return static_cast<T>(Impl::PostDecrement(&this->Atomic));
392  }
393 
394  T operator+=(T val)
395  {
396  return static_cast<T>(Impl::AddAndFetch(&this->Atomic,
397  static_cast<typename Impl::value_type>(val)));
398  }
399 
400  T operator-=(T val)
401  {
402  return static_cast<T>(Impl::SubAndFetch(&this->Atomic,
403  static_cast<typename Impl::value_type>(val)));
404  }
405 
406  operator T() const
407  {
408  return static_cast<T>(Impl::Load(&this->Atomic));
409  }
410 
411  T operator=(T val)
412  {
413  Impl::Store(&this->Atomic, static_cast<typename Impl::value_type>(val));
414  return val;
415  }
416 
418  {
419  this->store(atomic.load());
420  return *this;
421  }
422 
423  T load() const
424  {
425  return static_cast<T>(Impl::Load(&this->Atomic));
426  }
427 
428  void store(T val)
429  {
430  Impl::Store(&this->Atomic, static_cast<typename Impl::value_type>(val));
431  }
432 
433 private:
434  typename Impl::atomic_type Atomic;
435 };
436 
437 
438 template <typename T> class vtkAtomic<T*>
439 {
440 private:
441  typedef detail::AtomicOps<sizeof(T*)> Impl;
442 
443 public:
444  vtkAtomic() : Atomic(0)
445  {
446  }
447 
448  vtkAtomic(T* val)
449  : Atomic(reinterpret_cast<typename Impl::value_type>(val))
450  {
451  }
452 
453  vtkAtomic(const vtkAtomic<T*> &atomic)
454  : Atomic(reinterpret_cast<typename Impl::value_type>(atomic.load()))
455  {
456  }
457 
459  {
460  return reinterpret_cast<T*>(Impl::AddAndFetch(&this->Atomic, sizeof(T)));
461  }
462 
463  T* operator++(int)
464  {
465  T* val = reinterpret_cast<T*>(Impl::AddAndFetch(&this->Atomic, sizeof(T)));
466  return --val;
467  }
468 
470  {
471  return reinterpret_cast<T*>(Impl::SubAndFetch(&this->Atomic, sizeof(T)));
472  }
473 
474  T* operator--(int)
475  {
476  T* val = reinterpret_cast<T*>(Impl::AddAndFetch(&this->Atomic, sizeof(T)));
477  return ++val;
478  }
479 
480  T* operator+=(std::ptrdiff_t val)
481  {
482  return reinterpret_cast<T*>(Impl::AddAndFetch(&this->Atomic,
483  val * sizeof(T)));
484  }
485 
486  T* operator-=(std::ptrdiff_t val)
487  {
488  return reinterpret_cast<T*>(Impl::SubAndFetch(&this->Atomic,
489  val * sizeof(T)));
490  }
491 
492  operator T*() const
493  {
494  return reinterpret_cast<T*>(Impl::Load(&this->Atomic));
495  }
496 
497  T* operator=(T* val)
498  {
499  Impl::Store(&this->Atomic,
500  reinterpret_cast<typename Impl::value_type>(val));
501  return val;
502  }
503 
505  {
506  this->store(atomic.load());
507  return *this;
508  }
509 
510  T* load() const
511  {
512  return reinterpret_cast<T*>(Impl::Load(&this->Atomic));
513  }
514 
515  void store(T* val)
516  {
517  Impl::Store(&this->Atomic,
518  reinterpret_cast<typename Impl::value_type>(val));
519  }
520 
521 private:
522  typename Impl::atomic_type Atomic;
523 };
524 
525 
526 template <> class vtkAtomic<void*>
527 {
528 private:
529  typedef detail::AtomicOps<sizeof(void*)> Impl;
530 
531 public:
532  vtkAtomic() : Atomic(0)
533  {
534  }
535 
536  vtkAtomic(void* val)
537  : Atomic(reinterpret_cast<Impl::value_type>(val))
538  {
539  }
540 
542  : Atomic(reinterpret_cast<Impl::value_type>(atomic.load()))
543  {
544  }
545 
546  operator void*() const
547  {
548  return reinterpret_cast<void*>(Impl::Load(&this->Atomic));
549  }
550 
551  void* operator=(void* val)
552  {
553  Impl::Store(&this->Atomic,
554  reinterpret_cast<Impl::value_type>(val));
555  return val;
556  }
557 
559  {
560  this->store(atomic.load());
561  return *this;
562  }
563 
564  void* load() const
565  {
566  return reinterpret_cast<void*>(Impl::Load(&this->Atomic));
567  }
568 
569  void store(void* val)
570  {
571  Impl::Store(&this->Atomic,
572  reinterpret_cast<Impl::value_type>(val));
573  }
574 
575 private:
576  Impl::atomic_type Atomic;
577 };
578 
579 #endif
580 // VTK-HeaderTest-Exclude: vtkAtomic.h
vtkAtomic< T > & operator=(const vtkAtomic< T > &atomic)
Definition: vtkAtomic.h:417
void * load() const
Definition: vtkAtomic.h:564
T operator++()
Definition: vtkAtomic.h:374
T * operator--(int)
Definition: vtkAtomic.h:474
vtkAtomic(T val)
Definition: vtkAtomic.h:365
T operator--(int)
Definition: vtkAtomic.h:389
vtkSimpleCriticalSection * csec
Definition: vtkAtomic.h:200
static value_type Load(const value_type *ref)
Definition: vtkAtomic.h:257
T * operator+=(std::ptrdiff_t val)
Definition: vtkAtomic.h:480
#define VTKCOMMONCORE_EXPORT
static value_type PostIncrement(value_type *ref)
Definition: vtkAtomic.h:247
#define VTK_ALIGN(X)
Definition: vtkAtomic.h:74
T operator-=(T val)
Definition: vtkAtomic.h:400
static void Store(value_type *ref, value_type val)
Definition: vtkAtomic.h:263
vtkAtomic(const vtkAtomic< T > &atomic)
Definition: vtkAtomic.h:369
static value_type PostDecrement(value_type *ref)
Definition: vtkAtomic.h:252
static value_type PreDecrement(value_type *ref)
Definition: vtkAtomic.h:242
vtkAtomic< T * > & operator=(const vtkAtomic< T * > &atomic)
Definition: vtkAtomic.h:504
static value_type SubAndFetch(value_type *ref, value_type val)
Definition: vtkAtomic.h:232
static value_type PreIncrement(value_type *ref)
Definition: vtkAtomic.h:237
T * operator-=(std::ptrdiff_t val)
Definition: vtkAtomic.h:486
void store(T *val)
Definition: vtkAtomic.h:515
vtkAtomic(T *val)
Definition: vtkAtomic.h:448
T operator--()
Definition: vtkAtomic.h:384
void store(T val)
Definition: vtkAtomic.h:428
vtkTypeInt32 VTK_ALIGN(4) atomic_type
Definition: vtkAtomic.h:224
vtkAtomic< void * > & operator=(const vtkAtomic< void * > &atomic)
Definition: vtkAtomic.h:558
T load() const
Definition: vtkAtomic.h:423
vtkTypeInt64 value_type
Definition: vtkAtomic.h:206
void store(void *val)
Definition: vtkAtomic.h:569
Critical section locking class.
T * load() const
Definition: vtkAtomic.h:510
vtkTypeInt32 value_type
Definition: vtkAtomic.h:225
T * operator=(T *val)
Definition: vtkAtomic.h:497
vtkAtomic(const vtkAtomic< void * > &atomic)
Definition: vtkAtomic.h:541
T operator=(T val)
Definition: vtkAtomic.h:411
vtkAtomic(void *val)
Definition: vtkAtomic.h:536
T operator++(int)
Definition: vtkAtomic.h:379
T operator+=(T val)
Definition: vtkAtomic.h:394
void * operator=(void *val)
Definition: vtkAtomic.h:551
T * operator++(int)
Definition: vtkAtomic.h:463
vtkAtomic(const vtkAtomic< T * > &atomic)
Definition: vtkAtomic.h:453