ADTF
tagged_ptr.h
Go to the documentation of this file.
1 
7 #ifndef _TAGGED_PTR_CLASS_HEADER_
8 #define _TAGGED_PTR_CLASS_HEADER_
9 
10 #ifdef WIN32
11  #define A_UTILS_HAS_ATOMIC_OPERATORS
12  #include <intrin.h>
13  #pragma intrinsic (_InterlockedCompareExchange)
14  #pragma intrinsic (_InterlockedCompareExchange64)
15  #pragma intrinsic (_ReadWriteBarrier)
16 #else
17  #if defined(__i386) || defined(__x86_64)
18  #define A_UTILS_HAS_ATOMIC_OPERATORS
19  #endif
20 #endif
21 
22 namespace A_UTILS_NS
23 {
24 
25 tBool atomic_compare_exchange(tInt32 volatile* pAddress, tInt32 nNewValue, tInt32 nExpectedValue);
26 
27 #ifdef WIN32
31  template <class BasicType>
32  inline tBool atomic_compare_exchange(volatile BasicType* pAddress, const BasicType& nNewValue, const BasicType& nExpectedValue)
33  {
34  BasicType nResult = _InterlockedCompareExchange((long*)pAddress, nNewValue, nExpectedValue);
35  return (nResult == nExpectedValue);
36  }
40  template<>
41  inline tBool atomic_compare_exchange<tUInt64>(volatile tUInt64* pAddress, const tUInt64& nNewValue, const tUInt64& nExpectedValue)
42  {
43  tUInt64 nResult = _InterlockedCompareExchange64((tInt64*)pAddress, nNewValue, nExpectedValue);
44  return (nResult == nExpectedValue);
45  }
46 #else
50  template <class BasicType>
51  inline tBool atomic_compare_exchange(volatile BasicType* pAddress, const BasicType& nNewValue, const BasicType& nExpectedValue)
52  {
53  return __sync_bool_compare_and_swap(pAddress, nExpectedValue, nNewValue);
54  }
55 #endif
56 
64 #ifdef WIN32
65  inline tVoid memory_barrier()
66  {
67  _ReadWriteBarrier();
68  }
69 #else
71  {
72 #if defined(__GNUC__) && ( (__GNUC__ > 4) || ((__GNUC__ >= 4) && \
73  (__GNUC_MINOR__ >= 1)))
74  __sync_synchronize();
75 #elif defined(__GNUC__) && defined (__i386__)
76  asm volatile("lock; addl $0,0(%%esp)":::"memory");
77 #else
78  # warning "no memory barrier implemented for this platform"
79 #endif
80  }
81 #endif
82 
83 
84 
85 #if (defined(WIN32) && !defined(WIN64)) || \
86  defined(A_UTILS_FORCE_TAGGED_POINTER_USE) || \
87  ( \
88  (defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)) || \
89  (!defined(__x86_64__) && \
90  ( \
91  (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) && !defined(A_UTILS_FORCE_NO_TAGGED_POINTER_USE)) || \
92  (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 1))) && !defined(A_UTILS_FORCE_NO_TAGGED_POINTER_USE)) \
93  ) \
94  ) \
95  )
96 
97 #ifdef WIN32
98  #define A_UTILS_CAS_ALIGNMENT __declspec(align(8))
99 #else
100  #ifdef __x86_64__
101  #define A_UTILS_CAS_ALIGNMENT __attribute__((aligned(16)))
102  #else
103  #define A_UTILS_CAS_ALIGNMENT __attribute__((aligned(8)))
104  #endif
105 #endif
106 
112 
113 #define A_UTILS_TAGGED_POINTER_AVALIABLE
114 
128 template <class T>
129 class A_UTILS_CAS_ALIGNMENT tagged_ptr
130 {
131  public:
132  #ifdef __x86_64__
133  typedef int tCompareAndSwapType __attribute__ ((mode (TI)));
134  typedef tUInt64 tTag;
135  #else
136  typedef tUInt64 tCompareAndSwapType;
137  typedef tUInt32 tTag;
138  #endif
139 
140  private:
141  T* m_pPtr;
142  tTag m_nTag;
143 
144  public:
145  tagged_ptr(): m_pPtr(nullptr), m_nTag(0)
146  {
147  }
148 
153  tagged_ptr(tagged_ptr const& oPtr)
154  {
155  Set(oPtr);
156  }
157 
163  explicit tagged_ptr(T* pPtr, tTag nTag = 0): m_pPtr(pPtr), m_nTag(nTag)
164  {
165  }
166 
171  void operator=(tagged_ptr const& oPtr)
172  {
173  Set(oPtr);
174  }
175 
181  void Set(tagged_ptr const& oPtr)
182  {
183  m_pPtr = oPtr.m_pPtr;
184  m_nTag = oPtr.m_nTag;
185  }
186 
193  void Set(T* pPtr, tTag nTag = 0)
194  {
195  m_pPtr = pPtr;
196  m_nTag = nTag;
197  }
198 
204  bool operator== (tagged_ptr const& oPtr) const
205  {
206  return (m_pPtr == oPtr.m_pPtr) && (m_nTag == oPtr.m_nTag);
207  }
208 
214  bool operator!= (tagged_ptr const& oPtr) const
215  {
216  return !operator==(oPtr);
217  }
218 
223  T* GetPtr() const
224  {
225  return m_pPtr;
226  }
227 
232  tTag GetTag() const
233  {
234  return m_nTag;
235  }
236 
243  tBool CompareAndSwap(tagged_ptr const& oOldVal, T* pNewPtr)
244  {
245  return CompareAndSwap(oOldVal, pNewPtr, oOldVal.m_nTag + 1);
246  }
247 
255  tBool CompareAndSwap(tagged_ptr const& oOldVal, T* pNewPtr, tTag nTag)
256  {
257  tagged_ptr oNewVal(pNewPtr, nTag);
258  return atomic_compare_exchange<tCompareAndSwapType>((tCompareAndSwapType*) this, *(tCompareAndSwapType*) &oNewVal, *(tCompareAndSwapType*) &oOldVal);
259  }
260 
265  T* operator->() const
266  {
267  return m_pPtr;
268  }
269 
274  operator bool(void) const
275  {
276  return m_pPtr != nullptr;
277  }
278 };
279 
280 #elif (defined(__x86_64__) \
281  && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) \
282  && !defined(A_UTILS_FORCE_NO_TAGGED_POINTER_USE) \
283  || defined(WIN64) \
284  || defined(__ARM_ARCH_8A))
285 // 64 Bit Linux without 128 Bit compare and swap operation
286 // we use packed pointers since to OS uses only 48 bit for addresses.
287 // this should also work for ARMv8-a - http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch12s04.html
288 
289 #ifdef WIN64
290  #define A_UTILS_CAS_ALIGNMENT __declspec(align(8))
291 #else
292  #define A_UTILS_CAS_ALIGNMENT __attribute__((aligned(8)))
293 #endif
294 
295 #define A_UTILS_TAGGED_POINTER_AVALIABLE
296 
309 template <class T>
310 class A_UTILS_CAS_ALIGNMENT tagged_ptr
311 {
312  public:
313  typedef tUInt64 tCompareAndSwapType;
314  typedef tUInt16 tTag;
315 
316  private:
317  union tCompressedPtr
318  {
319  tCompareAndSwapType nValue;
320  tTag nTag[4];
321  };
322 
323  static const tInt s_nTagIndex = 3;
324  static const tCompareAndSwapType s_nPtrMask = 0xffffffffffff; //(1L<<48L)-1;
325 
326  // this our actual storage
327  tCompressedPtr m_oPtr;
328 
329  public:
330  tagged_ptr()
331  {
332  m_oPtr.nValue = 0;
333  }
334 
339  tagged_ptr(tagged_ptr const& oPtr)
340  {
341  Set(oPtr);
342  }
343 
349  explicit tagged_ptr(T* pPtr, tTag nTag = 0)
350  {
351  Set(pPtr, nTag);
352  }
353 
358  void operator=(tagged_ptr const& oPtr)
359  {
360  Set(oPtr);
361  }
362 
368  void Set(tagged_ptr const& oPtr)
369  {
370  m_oPtr = oPtr.m_oPtr;
371  }
372 
379  void Set(T* pPtr, tTag nTag = 0)
380  {
381  m_oPtr.nValue = tCompareAndSwapType(pPtr);
382  m_oPtr.nTag[s_nTagIndex] = nTag;
383  }
384 
390  bool operator== (tagged_ptr const& oPtr) const
391  {
392  return m_oPtr.nValue == oPtr.m_oPtr.nValue;
393  }
394 
400  bool operator!= (tagged_ptr const& oPtr) const
401  {
402  return !operator==(oPtr);
403  }
404 
409  T* GetPtr() const
410  {
411  return (T*)(m_oPtr.nValue & s_nPtrMask);
412  }
413 
418  tTag GetTag() const
419  {
420  return m_oPtr.nTag[s_nTagIndex];
421  }
422 
429  tBool CompareAndSwap(tagged_ptr const& oOldVal, T* pNewPtr)
430  {
431  return CompareAndSwap(oOldVal, pNewPtr, oOldVal.GetTag() + 1);
432  }
433 
441  tBool CompareAndSwap(tagged_ptr const& oOldVal, T* pNewPtr, tTag nTag)
442  {
443  tagged_ptr oNewVal(pNewPtr, nTag);
444  return atomic_compare_exchange<tCompareAndSwapType>((tCompareAndSwapType*) this, *(tCompareAndSwapType*) &oNewVal, *(tCompareAndSwapType*) &oOldVal);
445  }
446 
451  T* operator->() const
452  {
453  return GetPtr();
454  }
455 
460  operator bool(void) const
461  {
462  return GetPtr() != nullptr;
463  }
464 };
465 
466 #else
467  // we're out of luck! We could probably offer a fallback with mutexes.
468  #warning "No required compare and swap operation avaliable. cLockFree* classes will use mutexes."
469 #endif
470 
471 }
472 
473 #endif
int64_t tInt64
type definition for signed integer values (64bit) (platform and compiler independent type).
int32_t tInt32
type definition for signed integer values (32bit) (platform and compiler independent type).
void tVoid
The tVoid is always the definition for the void (non-type).
uint16_t tUInt16
type definition for unsigned integer values (16bit) (platform and compiler independent type).
int tInt
type definition for signed integer value (platform and compiler dependent type).
bool tBool
The tBool defines the type for the Values tTrue and tFalse (platform and compiler dependent).
uint32_t tUInt32
type definition for unsigned integer values (32bit) (platform and compiler independent type).
uint64_t tUInt64
type definition for unsigned integer values (64bit) (platform and compiler independent type).
ADTF A_UTIL Namespace - Within adtf this is used as adtf::util or adtf_util.
Definition: d_ptr.h:11
tVoid memory_barrier()
This method will help ensure that all memory reads and writes will have been performed before this fu...
Definition: tagged_ptr.h:70
tBool operator==(const cMultiArrayIndex &o_A, const cMultiArrayIndex &o_B)
Comparison operator.
tBool operator!=(const cMultiArrayIndex &o_A, const cMultiArrayIndex &o_B)
Comparison operator.