ADTF
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
22namespace A_UTILS_NS
23{
24
25tBool 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
128template <class T>
129class 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
309template <class T>
310class 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
unsigned long tUInt32
type definition for unsigned integer values (32bit) (platform and compiler independent type).
unsigned int tUInt16
type definition for unsigned integer values (16bit) (platform and compiler independent type).
signed long tInt32
type definition for signed integer values (32bit) (platform and compiler independent type).
int64_t tInt64
type definition for signed integer values (64bit) (platform and compiler independent type).
void tVoid
The tVoid is always the definition for the void (non-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).
uint64_t tUInt64
type definition for unsigned integer values (64bit) (platform and compiler independent type).
tBool operator!=(const tErrorCode &lhs, const tErrorCode &rhs)
Compare two POD error code types for inequality.
tBool operator==(const tErrorCode &lhs, const tErrorCode &rhs)
Compare two POD error code types for equality.
ADTF A_UTIL Namespace - Within adtf this is used as 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