lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
atomic.h
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