MDL SDK API nvidia_logo_transpbg.gif 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 2022 NVIDIA Corporation. All rights reserved.
3  **************************************************************************************************/
8 
9 #ifndef MI_BASE_ATOM_H
10 #define MI_BASE_ATOM_H
11 
12 #include <mi/base/config.h>
13 #include <mi/base/types.h>
14 
15 // Select implementation to use
16 #if defined( MI_ARCH_X86) && (defined( MI_COMPILER_GCC) || defined( MI_COMPILER_ICC))
17 # define MI_ATOM32_X86GCC
18 #elif (__cplusplus >= 201103L)
19 # define MI_ATOM32_STD
20 # include <atomic>
21 #elif defined( MI_ARCH_X86) && defined( MI_COMPILER_MSC)
22 # define MI_ATOM32_X86MSC
23 # include <intrin.h>
24 # pragma intrinsic( _InterlockedExchangeAdd)
25 # pragma intrinsic( _InterlockedCompareExchange)
26 #else
27 # define MI_ATOM32_GENERIC
28 # include <mi/base/lock.h>
29 #endif
30 
31 namespace mi {
32 
33 namespace base {
34 
39 class Atom32
41 {
42 public:
44  Atom32() : m_value( 0) { }
45 
47  Atom32( const Uint32 value) : m_value( value) { }
48 
49 #if defined( MI_ATOM32_STD) || defined( MI_ATOM32_GENERIC)
50  Atom32( const Atom32& other);
52 
54  Atom32& operator=( const Atom32& rhs);
55 #endif
56 
58  Uint32 operator=( const Uint32 rhs) { m_value = rhs; return rhs; }
59 
61  Uint32 operator+=( const Uint32 rhs);
62 
64  Uint32 operator-=( const Uint32 rhs);
65 
68 
70  Uint32 operator++( int);
71 
74 
76  Uint32 operator--( int);
77 
79  operator Uint32() const { return m_value; }
80 
82  Uint32 swap( const Uint32 rhs);
83 
84 private:
85 #if defined( MI_ATOM32_STD)
86  // The counter.
87  std::atomic_uint32_t m_value;
88 #else
89  // The counter.
90  volatile Uint32 m_value;
91 #endif
92 
93 #if defined( MI_ATOM32_GENERIC)
94  // The lock for #m_value needed by the generic implementation.
95  mi::base::Lock m_lock;
96 #endif
97 };
98 
99 #if !defined( MI_FOR_DOXYGEN_ONLY)
100 
101 #if defined( MI_ATOM32_X86GCC)
102 
103 inline Uint32 Atom32::operator+=( const Uint32 rhs)
104 {
105  Uint32 retval;
106  asm volatile(
107  "movl %2,%0\n"
108  "lock; xaddl %0,%1\n"
109  "addl %2,%0\n"
110  : "=&r"( retval), "+m"( m_value)
111  : "r"( rhs)
112  : "cc"
113  );
114  return retval;
115 }
116 
117 inline Uint32 Atom32::operator-=( const Uint32 rhs)
118 {
119  Uint32 retval;
120  asm volatile(
121  "neg %2\n"
122  "movl %2,%0\n"
123  "lock; xaddl %0,%1\n"
124  "addl %2,%0\n"
125  : "=&r"( retval), "+m"( m_value)
126  : "r"( rhs)
127  : "cc", "%2"
128  );
129  return retval;
130 }
131 
132 inline Uint32 Atom32::operator++()
133 {
134  Uint32 retval;
135  asm volatile(
136  "movl $1,%0\n"
137  "lock; xaddl %0,%1\n"
138  "addl $1,%0\n"
139  : "=&r"( retval), "+m"( m_value)
140  :
141  : "cc"
142  );
143  return retval;
144 }
145 
146 inline Uint32 Atom32::operator++( int)
147 {
148  Uint32 retval;
149  asm volatile(
150  "movl $1,%0\n"
151  "lock; xaddl %0,%1\n"
152  : "=&r"( retval), "+m"( m_value)
153  :
154  : "cc"
155  );
156  return retval;
157 }
158 
159 inline Uint32 Atom32::operator--()
160 {
161  Uint32 retval;
162  asm volatile(
163  "movl $-1,%0\n"
164  "lock; xaddl %0,%1\n"
165  "addl $-1,%0\n"
166  : "=&r"( retval), "+m"( m_value)
167  :
168  : "cc"
169  );
170  return retval;
171 }
172 
173 inline Uint32 Atom32::operator--( int)
174 {
175  Uint32 retval;
176  asm volatile(
177  "movl $-1,%0\n"
178  "lock; xaddl %0,%1\n"
179  : "=&r"( retval), "+m"( m_value)
180  :
181  : "cc"
182  );
183  return retval;
184 }
185 
186 inline Uint32 Atom32::swap( const Uint32 rhs)
187 {
188  Uint32 retval;
189  asm volatile(
190  "0:\n"
191  "movl %1,%0\n"
192  "lock; cmpxchg %2,%1\n"
193  "jnz 0b\n"
194  : "=&a"( retval), "+m"( m_value)
195  : "r"( rhs)
196  : "cc"
197  );
198  return retval;
199 }
200 
201 #elif defined( MI_ATOM32_STD)
202 
203 inline Atom32::Atom32( const Atom32& other) : m_value( other.m_value.load()) { }
204 
205 inline Atom32& Atom32::operator=( const Atom32& rhs)
206 {
207  m_value = rhs.m_value.load();
208  return *this;
209 }
210 
211 inline Uint32 Atom32::operator+=( const Uint32 rhs)
212 {
213  m_value += rhs;
214  return m_value;
215 }
216 
217 inline Uint32 Atom32::operator-=( const Uint32 rhs)
218 {
219  m_value -= rhs;
220  return m_value;
221 }
222 
223 inline Uint32 Atom32::operator++()
224 {
225  return ++m_value;
226 }
227 
228 inline Uint32 Atom32::operator++( int)
229 {
230  return m_value++;
231 }
232 
233 inline Uint32 Atom32::operator--()
234 {
235  return --m_value;
236 }
237 
238 inline Uint32 Atom32::operator--( int)
239 {
240  return m_value--;
241 }
242 
243 inline Uint32 Atom32::swap( const Uint32 rhs)
244 {
245  return m_value.exchange( rhs);
246 }
247 
248 #elif defined( MI_ATOM32_X86MSC)
249 
250 __forceinline Uint32 Atom32::operator+=( const Uint32 rhs)
251 {
252  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), rhs) + rhs;
253 }
254 
255 __forceinline Uint32 Atom32::operator-=( const Uint32 rhs)
256 {
257  return _InterlockedExchangeAdd(
258  reinterpret_cast<volatile long*>( &m_value), -static_cast<const Sint32>( rhs)) - rhs;
259 }
260 
261 __forceinline Uint32 Atom32::operator++()
262 {
263  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), 1L) + 1L;
264 }
265 
266 __forceinline Uint32 Atom32::operator++( int)
267 {
268  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), 1L);
269 }
270 
271 __forceinline Uint32 Atom32::operator--()
272 {
273  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), -1L) - 1L;
274 }
275 
276 __forceinline Uint32 Atom32::operator--( int)
277 {
278  return _InterlockedExchangeAdd( reinterpret_cast<volatile long*>( &m_value), -1L);
279 }
280 
281 __forceinline Uint32 Atom32::swap( const Uint32 rhs)
282 {
283  return _InterlockedExchange( reinterpret_cast<volatile long*>( &m_value), rhs);
284 }
285 
286 #elif defined( MI_ATOM32_GENERIC)
287 
288 inline Atom32::Atom32( const Atom32& other) : m_value( other.m_value) { }
289 
290 inline Atom32& Atom32::operator=( const Atom32& rhs)
291 {
292  m_value = rhs.m_value;
293  return *this;
294 }
295 
296 inline Uint32 Atom32::operator+=( const Uint32 rhs)
297 {
298  mi::base::Lock::Block block( &m_lock);
299  return m_value += rhs;
300 }
301 
302 inline Uint32 Atom32::operator-=( const Uint32 rhs)
303 {
304  mi::base::Lock::Block block( &m_lock);
305  return m_value -= rhs;
306 }
307 
308 inline Uint32 Atom32::operator++()
309 {
310  mi::base::Lock::Block block( &m_lock);
311  return ++m_value;
312 }
313 
314 inline Uint32 Atom32::operator++( int)
315 {
316  mi::base::Lock::Block block( &m_lock);
317  return m_value++;
318 }
319 
320 inline Uint32 Atom32::operator--()
321 {
322  mi::base::Lock::Block block( &m_lock);
323  return --m_value;
324 }
325 
326 inline Uint32 Atom32::operator--( int)
327 {
328  mi::base::Lock::Block block( &m_lock);
329  return m_value--;
330 }
331 
332 inline Uint32 Atom32::swap( const Uint32 rhs)
333 {
334  mi::base::Lock::Block block( &m_lock);
335  Uint32 retval = m_value;
336  m_value = rhs;
337  return retval;
338 }
339 
340 #else
341 #error One of MI_ATOM32_X86GCC, MI_ATOM32_STD, MI_ATOM32_X86MSC, or MI_ATOM32_GENERIC must be \
342  defined.
343 #endif
344 
345 #undef MI_ATOM32_X86GCC
346 #undef MI_ATOM32_STD
347 #undef MI_ATOM32_X86MSC
348 #undef MI_ATOM32_GENERIC
349 
350 #endif // !MI_FOR_DOXYGEN_ONLY
351  // end group mi_base_threads
353 
354 } // namespace base
355 
356 } // namespace mi
357 
358 #endif // MI_BASE_ATOM_H