Thea
AtomicInt32.hpp
1 //============================================================================
2 //
3 // This file is part of the Thea toolkit.
4 //
5 // This software is distributed under the BSD license, as detailed in the
6 // accompanying LICENSE.txt file. Portions are derived from other works:
7 // their respective licenses and copyright information are reproduced in
8 // LICENSE.txt and/or in the relevant source files.
9 //
10 // Author: Siddhartha Chaudhuri
11 // First version: 2013
12 //
13 //============================================================================
14 
15 /*
16  ORIGINAL HEADER
17 
18  @file AtomicInt32.h
19 
20  @maintainer Morgan McGuire, http://graphics.cs.williams.edu
21 
22  @created 2005-09-01
23  @edited 2006-06-21
24  */
25 
26 #ifndef __Thea_AtomicInt32_hpp__
27 #define __Thea_AtomicInt32_hpp__
28 
29 #include "Platform.hpp"
30 #include "NumericType.hpp"
31 
32 #if defined(THEA_MAC)
33 # include <libkern/OSAtomic.h>
34 #elif defined(THEA_WINDOWS)
35 # include <windows.h>
36 #endif
37 
38 namespace Thea {
39 
44 class THEA_API AtomicInt32
45 {
46  private:
47 #if defined(THEA_WINDOWS)
48  typedef LONG ImplT;
49  volatile ImplT m_value;
50 #elif defined(THEA_MAC)
51  typedef int32_t ImplT;
52  ImplT m_value;
53 #else
54  typedef int32 ImplT;
55  volatile ImplT m_value;
56 #endif
57 
58  public:
61 
63  explicit AtomicInt32(int32 x)
64  {
65  m_value = (ImplT)x;
66  }
67 
70  {
71  m_value = x.m_value;
72  }
73 
75  AtomicInt32 const & operator=(int32 x)
76  {
77  m_value = (ImplT)x;
78  return *this;
79  }
80 
82  void operator=(AtomicInt32 const & x)
83  {
84  m_value = x.m_value;
85  }
86 
88  int32 value() const
89  {
90  return m_value;
91  }
92 
94  int32 add(int32 const x)
95  {
96 #if defined(THEA_WINDOWS)
97  return InterlockedExchangeAdd(&m_value, x);
98 #elif defined(THEA_LINUX) || defined(THEA_FREEBSD)
99  int32 old;
100  asm volatile ("lock; xaddl %0,%1"
101  : "=r"(old), "=m"(m_value) /* outputs */
102  : "0"(x), "m"(m_value) /* inputs */
103  : "memory", "cc");
104  return old;
105 #elif defined(THEA_MAC)
106  int32 old = m_value;
107 # pragma clang diagnostic push
108 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
109  OSAtomicAdd32(x, &m_value);
110 # pragma clang diagnostic pop
111  return old;
112 #endif
113  }
114 
116  int32 sub(int32 const x)
117  {
118  return add(-x);
119  }
120 
122  void increment()
123  {
124 #if defined(THEA_WINDOWS)
125  // Note: returns the newly incremented value
126  InterlockedIncrement(&m_value);
127 #elif defined(THEA_LINUX) || defined(THEA_FREEBSD)
128  add(1);
129 #elif defined(THEA_MAC)
130 # pragma clang diagnostic push
131 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
132  // Note: returns the newly incremented value
133  OSAtomicIncrement32(&m_value);
134 # pragma clang diagnostic pop
135 #endif
136  }
137 
143  int32 decrement()
144  {
145 #if defined(THEA_WINDOWS)
146  // Note: returns the newly decremented value
147  return InterlockedDecrement(&m_value);
148 #elif defined(THEA_LINUX) || defined(THEA_FREEBSD)
149  unsigned char nz;
150  asm volatile ("lock; decl %1;\n\t"
151  "setnz %%al"
152  : "=a" (nz)
153  : "m" (m_value)
154  : "memory", "cc");
155  return nz;
156 #elif defined(THEA_MAC)
157 # pragma clang diagnostic push
158 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
159  // Note: returns the newly decremented value
160  return OSAtomicDecrement32(&m_value);
161 # pragma clang diagnostic pop
162 #endif
163  }
164 
174  int32 compareAndSet(int32 comperand, int32 exchange)
175  {
176 #if defined(THEA_WINDOWS)
177  return InterlockedCompareExchange(&m_value, exchange, comperand);
178 #elif defined(THEA_LINUX) || defined(THEA_FREEBSD) || defined(THEA_MAC)
179  // Based on Apache Portable Runtime
180  // http://koders.com/c/fid3B6631EE94542CDBAA03E822CA780CBA1B024822.aspx
181  int32 ret;
182  asm volatile ("lock; cmpxchgl %1, %2"
183  : "=a" (ret)
184  : "r" (exchange), "m" (m_value), "0"(comperand)
185  : "memory", "cc");
186  return ret;
187  // Note that OSAtomicCompareAndSwap32 does not return a useful value for us
188  // so it can't satisfy the cmpxchgl contract.
189 #endif
190  }
191 
192 }; // class AtomicInt32
193 
194 } // namespace Thea
195 
196 #endif
Root namespace for the Thea library.
int32 add(int32 const x)
Increment by x and return the old value, before the addition.
Definition: AtomicInt32.hpp:94
int32 decrement()
Decrement by 1.
int32 compareAndSet(int32 comperand, int32 exchange)
Atomic test-and-set: if *this == comperand then *this := exchange, else do nothing.
int32 sub(int32 const x)
Decrement by x and return the old value, before the subtraction.
AtomicInt32(int32 x)
Atomic initialization.
Definition: AtomicInt32.hpp:63
AtomicInt32(AtomicInt32 const &x)
Atomic copy constructor.
Definition: AtomicInt32.hpp:69
AtomicInt32 const & operator=(int32 x)
Atomic set.
Definition: AtomicInt32.hpp:75
void increment()
Increment by 1.
AtomicInt32()
Initial value is undefined.
Definition: AtomicInt32.hpp:60
void operator=(AtomicInt32 const &x)
Atomic set.
Definition: AtomicInt32.hpp:82
An integer that may safely be used on different threads without external locking. ...
Definition: AtomicInt32.hpp:44
int32 value() const
Get the current value.
Definition: AtomicInt32.hpp:88
This file must be included in every file in the project, before any other include.