NVIDIA Iray: Math API Home  Up
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
atom.h
Go to the documentation of this file.
1 //*****************************************************************************
2 // Copyright 1986, 2016 NVIDIA Corporation. All rights reserved.
3 //*****************************************************************************
8 //*****************************************************************************
9 
10 #ifndef MI_BASE_ATOM_H
11 #define MI_BASE_ATOM_H
12 
13 #include <mi/base/config.h>
14 #include <mi/base/types.h>
15 
16 // Select implementation to use
17 #if defined( MI_ARCH_X86) && defined( MI_COMPILER_MSC)
18 # define MI_ATOM32_X86MSC
19 # include <intrin.h>
20 # pragma intrinsic( _InterlockedExchangeAdd)
21 # pragma intrinsic( _InterlockedCompareExchange)
22 #elif defined( MI_ARCH_X86) && (defined( MI_COMPILER_GCC) || defined( MI_COMPILER_ICC))
23 # define MI_ATOM32_X86GCC
24 #else
25 # define MI_ATOM32_GENERIC
26 # include <mi/base/lock.h>
27 #endif
28 
29 namespace mi {
30 
31 namespace base {
32 
37 class Atom32
39 {
40 public:
42  Atom32() : m_value( 0) { }
43 
45  Atom32( const Uint32 value) : m_value( value) { }
46 
47 #if defined( MI_ATOM32_GENERIC)
48  Atom32( const mi::base::Atom32& other) : m_value( other.m_value) { }
50 
53 #endif
54 
56  Uint32 operator=( const Uint32 rhs) { m_value = rhs; return rhs; }
57 
59  Uint32 operator+=( const Uint32 rhs);
60 
62  Uint32 operator-=( const Uint32 rhs);
63 
66 
68  Uint32 operator++( int);
69 
72 
74  Uint32 operator--( int);
75 
77  operator Uint32() const { return m_value; }
78 
80  Uint32 swap( const Uint32 rhs);
81 
82 private:
83  // The counter.
84  volatile Uint32 m_value;
85 
86 #if defined( MI_ATOM32_GENERIC)
87  // The lock for #m_value needed by the generic implementation.
88  mi::base::Lock m_lock;
89 #endif
90 };
91 
92 #if !defined( MI_FOR_DOXYGEN_ONLY)
93 
94 #if defined( MI_ATOM32_X86MSC)
95 
96 __forceinline Uint32 Atom32::operator+=( const Uint32 rhs)
97 {
98  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), rhs) + rhs;
99 }
100 
101 __forceinline Uint32 Atom32::operator-=( const Uint32 rhs)
102 {
103  return _InterlockedExchangeAdd(
104  reinterpret_cast<volatile long*>( &m_value), -static_cast<const Sint32>( rhs)) - rhs;
105 }
106 
107 __forceinline Uint32 Atom32::operator++()
108 {
109  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), 1L) + 1L;
110 }
111 
112 __forceinline Uint32 Atom32::operator++( int)
113 {
114  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), 1L);
115 }
116 
117 __forceinline Uint32 Atom32::operator--()
118 {
119  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), -1L) - 1L;
120 }
121 
122 __forceinline Uint32 Atom32::operator--( int)
123 {
124  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), -1L);
125 }
126 
127 __forceinline Uint32 Atom32::swap( const Uint32 rhs)
128 {
129  return _InterlockedExchange( reinterpret_cast<volatile long*>( &m_value), rhs);
130 }
131 
132 #elif defined( MI_ATOM32_X86GCC) // defined( MI_ATOM32_X86MSC)
133 
134 inline Uint32 Atom32::operator+=( const Uint32 rhs)
135 {
136  Uint32 retval;
137  asm volatile(
138  "movl %2,%0\n"
139  "lock; xaddl %0,%1\n"
140  "addl %2,%0\n"
141  : "=&r"( retval), "+m"( m_value)
142  : "r"( rhs)
143  : "cc"
144  );
145  return retval;
146 }
147 
148 inline Uint32 Atom32::operator-=( const Uint32 rhs)
149 {
150  Uint32 retval;
151  asm volatile(
152  "neg %2\n"
153  "movl %2,%0\n"
154  "lock; xaddl %0,%1\n"
155  "addl %2,%0\n"
156  : "=&r"( retval), "+m"( m_value)
157  : "r"( rhs)
158  : "cc", "%2"
159  );
160  return retval;
161 }
162 
163 inline Uint32 Atom32::operator++()
164 {
165  Uint32 retval;
166  asm volatile(
167  "movl $1,%0\n"
168  "lock; xaddl %0,%1\n"
169  "addl $1,%0\n"
170  : "=&r"( retval), "+m"( m_value)
171  :
172  : "cc"
173  );
174  return retval;
175 }
176 
177 inline Uint32 Atom32::operator++( int)
178 {
179  Uint32 retval;
180  asm volatile(
181  "movl $1,%0\n"
182  "lock; xaddl %0,%1\n"
183  : "=&r"( retval), "+m"( m_value)
184  :
185  : "cc"
186  );
187  return retval;
188 }
189 
190 inline Uint32 Atom32::operator--()
191 {
192  Uint32 retval;
193  asm volatile(
194  "movl $-1,%0\n"
195  "lock; xaddl %0,%1\n"
196  "addl $-1,%0\n"
197  : "=&r"( retval), "+m"( m_value)
198  :
199  : "cc"
200  );
201  return retval;
202 }
203 
204 inline Uint32 Atom32::operator--( int)
205 {
206  Uint32 retval;
207  asm volatile(
208  "movl $-1,%0\n"
209  "lock; xaddl %0,%1\n"
210  : "=&r"( retval), "+m"( m_value)
211  :
212  : "cc"
213  );
214  return retval;
215 }
216 
217 inline Uint32 Atom32::swap( const Uint32 rhs)
218 {
219  Uint32 retval;
220  asm volatile(
221  "0:\n"
222  "movl %1,%0\n"
223  "lock; cmpxchg %2,%1\n"
224  "jnz 0b\n"
225  : "=&a"( retval), "+m"( m_value)
226  : "r"( rhs)
227  : "cc"
228  );
229  return retval;
230 }
231 
232 #elif defined( MI_ATOM32_GENERIC) // defined( MI_ATOM32_X86GCC)
233 
235 {
236  m_value = rhs.m_value;
237  return *this;
238 }
239 
240 inline Uint32 Atom32::operator+=( const Uint32 rhs)
241 {
242  mi::base::Lock::Block block( &m_lock);
243  return m_value += rhs;
244 }
245 
246 inline Uint32 Atom32::operator-=( const Uint32 rhs)
247 {
248  mi::base::Lock::Block block( &m_lock);
249  return m_value -= rhs;
250 }
251 
252 inline Uint32 Atom32::operator++()
253 {
254  mi::base::Lock::Block block( &m_lock);
255  return ++m_value;
256 }
257 
258 inline Uint32 Atom32::operator++( int)
259 {
260  mi::base::Lock::Block block( &m_lock);
261  return m_value++;
262 }
263 
264 inline Uint32 Atom32::operator--()
265 {
266  mi::base::Lock::Block block( &m_lock);
267  return --m_value;
268 }
269 
270 inline Uint32 Atom32::operator--( int)
271 {
272  mi::base::Lock::Block block( &m_lock);
273  return m_value--;
274 }
275 
276 inline Uint32 Atom32::swap( const Uint32 rhs)
277 {
278  mi::base::Lock::Block block( &m_lock);
279  Uint32 retval = m_value;
280  m_value = rhs;
281  return retval;
282 }
283 
284 #else // MI_ATOM32_GENERIC
285 #error One of MI_ATOM32_X86MSC, MI_ATOM32_X86GCC, or MI_ATOM32_GENERIC must be defined.
286 #endif
287 
288 #undef MI_ATOM32_X86MSC
289 #undef MI_ATOM32_X86GCC
290 #undef MI_ATOM32_GENERIC
291 
292 #endif // !MI_FOR_DOXYGEN_ONLY
293  // end group mi_base_threads
295 
296 } // namespace base
297 
298 } // namespace mi
299 
300 #endif // MI_BASE_ATOM_H