lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
00001 /*****************************************************/ 00002 /* lean Concurrent (c) Tobias Zirr 2011 */ 00003 /*****************************************************/ 00004 00005 #ifndef LEAN_CONCURRENT_ATOMIC 00006 #define LEAN_CONCURRENT_ATOMIC 00007 00008 #include "../lean.h" 00009 #include "../meta/strip.h" 00010 00011 #ifdef _MSC_VER 00012 00013 #include <intrin.h> 00014 00015 namespace lean 00016 { 00017 namespace concurrent 00018 { 00019 namespace impl 00020 { 00022 00024 __forceinline long atomic_increment(volatile long &value) 00025 { 00026 return _InterlockedIncrement(&value); 00027 } 00028 00030 __forceinline long atomic_decrement(volatile long &value) 00031 { 00032 return _InterlockedDecrement(&value); 00033 } 00034 00036 __forceinline bool atomic_test_and_set(volatile long &value, long expectedValue, long newValue) 00037 { 00038 return (_InterlockedCompareExchange(&value, newValue, expectedValue) == expectedValue); 00039 } 00040 00042 __forceinline long atomic_set(volatile long &value, long newValue) 00043 { 00044 return _InterlockedExchange(&value, newValue); 00045 } 00046 00048 00050 __forceinline short atomic_increment(volatile short &value) 00051 { 00052 return _InterlockedIncrement16(&value); 00053 } 00054 00056 __forceinline short atomic_decrement(volatile short &value) 00057 { 00058 return _InterlockedDecrement16(&value); 00059 } 00060 00062 __forceinline bool atomic_test_and_set(volatile short &value, short expectedValue, short newValue) 00063 { 00064 return (_InterlockedCompareExchange16(&value, newValue, expectedValue) == expectedValue); 00065 } 00066 00068 __forceinline short atomic_set(volatile short &value, short newValue) 00069 { 00070 return _InterlockedExchange16(&value, newValue); 00071 } 00072 00074 00075 template <size_t Size> 00076 struct atomic_type 00077 { 00078 // Always checked, therefore use static_assert with care 00079 LEAN_STATIC_ASSERT_MSG_ALT(Size & ~Size, // = false, dependent 00080 "Atomic operations on integers of the given type unsupported.", 00081 Atomic_operations_on_integers_of_the_given_type_unsupported); 00082 }; 00083 00084 template <> struct atomic_type<sizeof(short)> { typedef short type; }; 00085 template <> struct atomic_type<sizeof(long)> { typedef long type; }; 00086 00088 00090 __forceinline bool atomic_test_and_set(void *volatile &ptr, void *expectedPtr, void *newPtr) 00091 { 00092 #ifdef _M_IX86 00093 return atomic_test_and_set( 00094 reinterpret_cast<volatile long&>(ptr), 00095 reinterpret_cast<long>(expectedPtr), 00096 reinterpret_cast<long>(newPtr) ); 00097 #else 00098 return (_InterlockedCompareExchangePointer(&ptr, newPtr, expectedPtr) == expectedPtr); 00099 #endif 00100 } 00101 00103 __forceinline void* atomic_set(void *volatile &ptr, void *newPtr) 00104 { 00105 #ifdef _M_IX86 00106 return reinterpret_cast<void*>( atomic_set( 00107 reinterpret_cast<volatile long&>(ptr), 00108 reinterpret_cast<long>(newPtr) ) ); 00109 #else 00110 return _InterlockedExchangePointer(&ptr, newPtr); 00111 #endif 00112 } 00113 00114 } // namespace 00115 00116 } // namespace 00117 } // namespace 00118 00119 #else 00120 00121 #error Unknown compiler, intrinsics unavailable. 00122 00123 #endif 00124 00125 namespace lean 00126 { 00127 namespace concurrent 00128 { 00130 00132 template <class Integer> 00133 LEAN_INLINE Integer atomic_increment(volatile Integer &value) 00134 { 00135 typedef typename impl::atomic_type<sizeof(Integer)>::type atomic_int; 00136 00137 return static_cast<Integer>( impl::atomic_increment( 00138 reinterpret_cast<volatile atomic_int&>(value) ) ); 00139 } 00140 00142 template <class Integer> 00143 LEAN_INLINE Integer atomic_decrement(volatile Integer &value) 00144 { 00145 typedef typename impl::atomic_type<sizeof(Integer)>::type atomic_int; 00146 00147 return static_cast<Integer>( impl::atomic_decrement( 00148 reinterpret_cast<volatile atomic_int&>(value) ) ); 00149 } 00150 00152 template <class Integer> 00153 LEAN_INLINE bool atomic_test_and_set(volatile Integer &value, typename identity<Integer>::type expectedValue, typename identity<Integer>::type newValue) 00154 { 00155 typedef typename impl::atomic_type<sizeof(Integer)>::type atomic_int; 00156 00157 return impl::atomic_test_and_set( 00158 reinterpret_cast<volatile atomic_int&>(value), 00159 static_cast<atomic_int>(expectedValue), 00160 static_cast<atomic_int>(newValue) ); 00161 } 00162 00164 template <class Integer> 00165 LEAN_INLINE Integer atomic_set(volatile Integer &value, typename identity<Integer>::type newValue) 00166 { 00167 typedef typename impl::atomic_type<sizeof(Integer)>::type atomic_int; 00168 00169 return static_cast<Integer>( impl::atomic_set( 00170 reinterpret_cast<volatile atomic_int&>(value), 00171 static_cast<atomic_int>(newValue) ) ); 00172 } 00173 00175 template <class Pointer> 00176 LEAN_INLINE bool atomic_test_and_set(Pointer *volatile &value, typename identity<Pointer>::type *expectedValue, typename identity<Pointer>::type *newValue) 00177 { 00178 return impl::atomic_test_and_set( 00179 const_cast<void *volatile &>(reinterpret_cast<const void *volatile &>(const_cast<const Pointer *volatile &>(value))), 00180 const_cast<void*>(static_cast<const void*>(expectedValue)), 00181 const_cast<void*>(static_cast<const void*>(newValue)) ); 00182 } 00183 00185 template <class Pointer> 00186 LEAN_INLINE Pointer* atomic_set(Pointer *volatile &value, typename identity<Pointer>::type *newValue) 00187 { 00188 return static_cast<Pointer*>( impl::atomic_set( 00189 const_cast<void *volatile &>(reinterpret_cast<const void *volatile &>(const_cast<const Pointer *volatile &>(value))), 00190 const_cast<void*>(static_cast<const void*>(newValue)) ) ); 00191 } 00192 00193 } // namespace 00194 00195 using concurrent::atomic_increment; 00196 using concurrent::atomic_decrement; 00197 using concurrent::atomic_test_and_set; 00198 using concurrent::atomic_set; 00199 00200 } // namespace 00201 00202 #endif