/* -*-c++-*- OpenThreads library, Copyright (C) 2008 The Open Thread Group * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef _OPENTHREADS_ATOMIC_ #define _OPENTHREADS_ATOMIC_ #include #include #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) && defined(__i386__) #define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES #elif defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED) #define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) # include #elif defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC) # include # define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) # include "Mutex" # include "ScopedLock" #endif #if defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES) #define _OPENTHREADS_ATOMIC_INLINE #else #define _OPENTHREADS_ATOMIC_INLINE inline #endif namespace OpenThreads { /** * @class Atomic * @brief This class provides an atomic increment and decrement operation. */ class OPENTHREAD_EXPORT_DIRECTIVE Atomic { public: Atomic(unsigned value = 0) : _value(value) { } _OPENTHREADS_ATOMIC_INLINE unsigned operator++(); _OPENTHREADS_ATOMIC_INLINE unsigned operator--(); _OPENTHREADS_ATOMIC_INLINE unsigned AND(unsigned value); _OPENTHREADS_ATOMIC_INLINE unsigned OR(unsigned value); _OPENTHREADS_ATOMIC_INLINE unsigned XOR(unsigned value); _OPENTHREADS_ATOMIC_INLINE unsigned exchange(unsigned value = 0); _OPENTHREADS_ATOMIC_INLINE operator unsigned() const; private: Atomic(const Atomic&); Atomic& operator=(const Atomic&); #if defined(_OPENTHREADS_ATOMIC_USE_MUTEX) mutable Mutex _mutex; #endif #if defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED) volatile long _value; #elif defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC) volatile int32_t _value; #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) volatile uint_t _value; #else volatile unsigned _value; #endif }; /** * @class AtomicPtr * @brief This class provides an atomic pointer assignment using cas operations. */ class OPENTHREAD_EXPORT_DIRECTIVE AtomicPtr { public: AtomicPtr(void* ptr = 0) : _ptr(ptr) { } ~AtomicPtr() { _ptr = 0; } // assigns a new pointer _OPENTHREADS_ATOMIC_INLINE bool assign(void* ptrNew, const void* const ptrOld); _OPENTHREADS_ATOMIC_INLINE void* get() const; private: AtomicPtr(const AtomicPtr&); AtomicPtr& operator=(const AtomicPtr&); #if defined(_OPENTHREADS_ATOMIC_USE_MUTEX) mutable Mutex _mutex; #endif void* volatile _ptr; }; #if !defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES) _OPENTHREADS_ATOMIC_INLINE unsigned Atomic::operator++() { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_add_and_fetch(&_value, 1); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __add_and_fetch(&_value, 1); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return atomic_inc_uint_nv(&_value); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); return ++_value; #else return ++_value; #endif } _OPENTHREADS_ATOMIC_INLINE unsigned Atomic::operator--() { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_sub_and_fetch(&_value, 1); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __sub_and_fetch(&_value, 1); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return atomic_dec_uint_nv(&_value); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); return --_value; #else return --_value; #endif } _OPENTHREADS_ATOMIC_INLINE unsigned Atomic::AND(unsigned value) { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_fetch_and_and(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __and_and_fetch(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return atomic_and_uint_nv(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); _value &= value; return _value; #else _value &= value; return _value; #endif } _OPENTHREADS_ATOMIC_INLINE unsigned Atomic::OR(unsigned value) { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_fetch_and_or(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __or_and_fetch(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return atomic_or_uint_nv(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); _value |= value; return _value; #else _value |= value; return _value; #endif } _OPENTHREADS_ATOMIC_INLINE unsigned Atomic::XOR(unsigned value) { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_fetch_and_xor(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __xor_and_fetch(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return atomic_xor_uint_nv(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); _value ^= value; return _value; #else _value ^= value; return _value; #endif } _OPENTHREADS_ATOMIC_INLINE unsigned Atomic::exchange(unsigned value) { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_lock_test_and_set(&_value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __compare_and_swap(&_value, _value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return atomic_cas_uint(&_value, _value, value); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); unsigned oldval = _value; _value = value; return oldval; #else unsigned oldval = _value; _value = value; return oldval; #endif } _OPENTHREADS_ATOMIC_INLINE Atomic::operator unsigned() const { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) __sync_synchronize(); return _value; #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) __synchronize(); return _value; #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) membar_consumer(); // Hmm, do we need??? return _value; #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); return _value; #else return _value; #endif } _OPENTHREADS_ATOMIC_INLINE bool AtomicPtr::assign(void* ptrNew, const void* const ptrOld) { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) return __sync_bool_compare_and_swap(&_ptr, ptrOld, ptrNew); #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) return __compare_and_swap((unsigned long*)&_ptr, (unsigned long)ptrOld, (unsigned long)ptrNew); #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) return ptrOld == atomic_cas_ptr(&_ptr, ptrOld, ptrNew); #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); if (_ptr != ptrOld) return false; _ptr = ptrNew; return true; #else if (_ptr != ptrOld) return false; _ptr = ptrNew; return true; #endif } _OPENTHREADS_ATOMIC_INLINE void* AtomicPtr::get() const { #if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) __sync_synchronize(); return _ptr; #elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS) __synchronize(); return _ptr; #elif defined(_OPENTHREADS_ATOMIC_USE_SUN) membar_consumer(); // Hmm, do we need??? return _ptr; #elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) ScopedLock lock(_mutex); return _ptr; #else return _ptr; #endif } #endif // !defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES) } #endif // _OPENTHREADS_ATOMIC_