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