You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
8.1 KiB
287 lines
8.1 KiB
/* -*-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 <OpenThreads/Config> |
|
#include <OpenThreads/Exports> |
|
|
|
#if defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC) |
|
# include <libkern/OSAtomic.h> |
|
# define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES |
|
#elif 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 <atomic.h> |
|
# include "Mutex" |
|
# include "ScopedLock" |
|
#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; |
|
mutable Mutex _mutex; // needed for xor |
|
#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<Mutex> 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<Mutex> 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<Mutex> 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<Mutex> 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) |
|
ScopedLock<Mutex> lock(_mutex); |
|
_value ^= value; |
|
return _value; |
|
#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) |
|
ScopedLock<Mutex> 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<Mutex> 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<Mutex> 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, const_cast<void*>(ptrOld), ptrNew); |
|
#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX) |
|
ScopedLock<Mutex> 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<Mutex> lock(_mutex); |
|
return _ptr; |
|
#else |
|
return _ptr; |
|
#endif |
|
} |
|
|
|
#endif // !defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES) |
|
|
|
} |
|
|
|
#endif // _OPENTHREADS_ATOMIC_
|
|
|