atomic.h
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_ATOMIC_H
00044 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_ATOMIC_H
00045
00046 #include "util_common.h"
00047 #include "impl/atomic_impl.h"
00048 #include "../num/safe_bool.h"
00049
00050
00051
00052
00053
00054 namespace lass
00055 {
00056 namespace util
00057 {
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 template <typename T> inline
00069 bool atomicCompareAndSwap(volatile T& dest, T expectedValue, T newValue)
00070 {
00071 return impl::AtomicOperations< sizeof(T) >::compareAndSwap(dest, expectedValue, newValue)
00072 == expectedValue;
00073 }
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 template <typename T1, typename T2> inline
00090 bool atomicCompareAndSwap(volatile T1& dest1, T1 expected1, T2 expected2, T1 new1, T2 new2)
00091 {
00092 LASS_META_ASSERT(sizeof(T1) == sizeof(T2), T1_and_T2_must_be_of_same_size);
00093 return impl::AtomicOperations< sizeof(T1) >::compareAndSwap(
00094 dest1, expected1, expected2, new1, new2);
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 template <typename T> inline
00107 void atomicIncrement(volatile T& value)
00108 {
00109 impl::AtomicOperations< sizeof(T) >::increment(value);
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 template <typename T> inline
00122 void atomicDecrement(volatile T& value)
00123 {
00124 impl::AtomicOperations< sizeof(T) >::decrement(value);
00125 }
00126
00127
00128
00129 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00130 # pragma warning(push)
00131 # pragma warning(disable: 4521) // multiple copy constructors specified
00132 # pragma warning(disable: 4522) // multiple assignment operators specified
00133 #endif
00134
00135
00136
00137
00138
00139
00140 template <typename T>
00141 class TaggedPtr
00142 {
00143 public:
00144 #if LASS_ACTUAL_ADDRESS_SIZE == 48
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 typedef num::Tuint16 TTag;
00157 TaggedPtr(): bits_(0) {}
00158 TaggedPtr(T* ptr, TTag tag): bits_((reinterpret_cast<num::Tuint64>(ptr) << 16) | tag) {}
00159 TaggedPtr(const TaggedPtr& other): bits_(other.bits_) {}
00160 TaggedPtr(const volatile TaggedPtr& other): bits_(other.bits_) {}
00161 TaggedPtr& operator=(const TaggedPtr& other) { bits_ = other.bits_; return *this; }
00162 TaggedPtr& operator=(const volatile TaggedPtr& other) { bits_ = other.bits_; return *this; }
00163 T* const get() const
00164 {
00165 # if defined(LASS_HAVE_INLINE_ASSEMBLY_GCC)
00166 T* ptr;
00167 __asm__ __volatile__("sarq $16, %0;" : "=q"(ptr) : "0"(bits_) : "cc");
00168 return ptr;
00169 # elif defined(LASS_UTIL_IMPL_ATOMIC_MSVC_X64)
00170 return reinterpret_cast<T*>(__ll_rshift(*reinterpret_cast<const volatile __int64*>(&bits_), 16));
00171 # else
00172 return (bits_ & 0xa000000000000000 == 0) ?
00173 reinterpret_cast<T*>(bits_ >> 16) :
00174 reinterpret_cast<T*>((bits_ >> 16) | 0xffff000000000000);
00175 # endif
00176 }
00177 const TTag tag() const { return static_cast<TTag>(bits_ & 0xffff); }
00178 const bool operator==(const TaggedPtr& other) const { return bits_ == other.bits_; }
00179 const bool operator==(const volatile TaggedPtr& other) const { return bits_ == other.bits_; }
00180 bool atomicCompareAndSwap(const TaggedPtr& expected, const TaggedPtr& fresh) volatile
00181 {
00182 return util::atomicCompareAndSwap(bits_, expected.bits_, fresh.bits_);
00183 }
00184 private:
00185 num::Tuint64 bits_;
00186 #elif LASS_ACTUAL_ADDRESS_SIZE == 32
00187
00188
00189 typedef num::TuintPtr TTag;
00190 TaggedPtr(): ptr_(0), tag_(0) {}
00191 TaggedPtr(T* ptr, TTag tag): ptr_(ptr), tag_(tag) {}
00192 TaggedPtr(const TaggedPtr& other): ptr_(other.ptr_), tag_(other.tag_) {}
00193 TaggedPtr(const volatile TaggedPtr& other): ptr_(other.ptr_), tag_(other.tag_) {}
00194 TaggedPtr& operator=(const TaggedPtr& other) { ptr_ = other.ptr_; tag_ = other.tag_; return *this; }
00195 TaggedPtr& operator=(const volatile TaggedPtr& other) { ptr_ = other.ptr_; tag_ = other.tag_; return *this; }
00196 T* const get() const { return ptr_; }
00197 const TTag tag() const { return tag_; }
00198 bool operator==(const TaggedPtr& other) const { return ptr_ == other.ptr_ && tag_ == other.tag_; }
00199 bool operator==(const volatile TaggedPtr& other) const { return ptr_ == other.ptr_ && tag_ == other.tag_; }
00200 bool atomicCompareAndSwap(const TaggedPtr& expected, const TaggedPtr& fresh) volatile
00201 {
00202 return util::atomicCompareAndSwap(
00203 ptr_, expected.ptr_, expected.tag_, fresh.ptr_, fresh.tag_);
00204 }
00205 private:
00206 T* ptr_;
00207 TTag tag_;
00208 #else
00209 # error "not implemented yet [Bramz]"
00210 #endif
00211 public:
00212 T* const operator->() const { LASS_ASSERT(get()); return get(); }
00213 const bool operator!() const { return get() == 0; }
00214 operator num::SafeBool() const { return get() ? num::safeTrue : num::safeFalse; }
00215 };
00216
00217 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00218 # pragma warning(pop)
00219 #endif
00220
00221 }
00222 }
00223
00224 #endif
00225
00226