1/* -*-c++-*- OpenThreads library, Copyright (C) 2008 The Open Thread Group
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
14#ifndef _OPENTHREADS_ATOMIC_
15#define _OPENTHREADS_ATOMIC_
17#include <OpenThreads/Config>
18#include <OpenThreads/Exports>
20#if defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC)
21# include <libkern/OSAtomic.h>
22# define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES
23#elif defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS) && defined(__i386__)
24# define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES
25#elif defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED)
26# define _OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES
27#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
31#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
36#if defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES)
37#define _OPENTHREADS_ATOMIC_INLINE
39#define _OPENTHREADS_ATOMIC_INLINE inline
42namespace OpenThreads {
46 * @brief This class provides an atomic increment and decrement operation.
48class OPENTHREAD_EXPORT_DIRECTIVE Atomic {
50 Atomic(unsigned value = 0) : _value(value)
52 _OPENTHREADS_ATOMIC_INLINE unsigned operator++();
53 _OPENTHREADS_ATOMIC_INLINE unsigned operator--();
54 _OPENTHREADS_ATOMIC_INLINE unsigned AND(unsigned value);
55 _OPENTHREADS_ATOMIC_INLINE unsigned OR(unsigned value);
56 _OPENTHREADS_ATOMIC_INLINE unsigned XOR(unsigned value);
57 _OPENTHREADS_ATOMIC_INLINE unsigned exchange(unsigned value = 0);
58 _OPENTHREADS_ATOMIC_INLINE operator unsigned() const;
61 Atomic(const Atomic&);
62 Atomic& operator=(const Atomic&);
64#if defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
67#if defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED)
69#elif defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC)
70 volatile int32_t _value;
71#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
72 volatile uint_t _value;
73 mutable Mutex _mutex; // needed for xor
75 volatile unsigned _value;
81 * @brief This class provides an atomic pointer assignment using cas operations.
83class OPENTHREAD_EXPORT_DIRECTIVE AtomicPtr {
85 AtomicPtr(void* ptr = 0) : _ptr(ptr)
90 // assigns a new pointer
91 _OPENTHREADS_ATOMIC_INLINE bool assign(void* ptrNew, const void* const ptrOld);
92 _OPENTHREADS_ATOMIC_INLINE void* get() const;
95 AtomicPtr(const AtomicPtr&);
96 AtomicPtr& operator=(const AtomicPtr&);
98#if defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
104#if !defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES)
106_OPENTHREADS_ATOMIC_INLINE unsigned
109#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
110 return __sync_add_and_fetch(&_value, 1);
111#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
112 return __add_and_fetch(&_value, 1);
113#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
114 return atomic_inc_uint_nv(&_value);
115#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
116 ScopedLock<Mutex> lock(_mutex);
123_OPENTHREADS_ATOMIC_INLINE unsigned
126#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
127 return __sync_sub_and_fetch(&_value, 1);
128#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
129 return __sub_and_fetch(&_value, 1);
130#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
131 return atomic_dec_uint_nv(&_value);
132#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
133 ScopedLock<Mutex> lock(_mutex);
140_OPENTHREADS_ATOMIC_INLINE unsigned
141Atomic::AND(unsigned value)
143#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
144 return __sync_fetch_and_and(&_value, value);
145#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
146 return __and_and_fetch(&_value, value);
147#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
148 return atomic_and_uint_nv(&_value, value);
149#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
150 ScopedLock<Mutex> lock(_mutex);
159_OPENTHREADS_ATOMIC_INLINE unsigned
160Atomic::OR(unsigned value)
162#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
163 return __sync_fetch_and_or(&_value, value);
164#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
165 return __or_and_fetch(&_value, value);
166#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
167 return atomic_or_uint_nv(&_value, value);
168#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
169 ScopedLock<Mutex> lock(_mutex);
178_OPENTHREADS_ATOMIC_INLINE unsigned
179Atomic::XOR(unsigned value)
181#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
182 return __sync_fetch_and_xor(&_value, value);
183#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
184 return __xor_and_fetch(&_value, value);
185#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
186 ScopedLock<Mutex> lock(_mutex);
189#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
190 ScopedLock<Mutex> lock(_mutex);
199_OPENTHREADS_ATOMIC_INLINE unsigned
200Atomic::exchange(unsigned value)
202#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
203 return __sync_lock_test_and_set(&_value, value);
204#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
205 return __compare_and_swap(&_value, _value, value);
206#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
207 return atomic_cas_uint(&_value, _value, value);
208#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
209 ScopedLock<Mutex> lock(_mutex);
210 unsigned oldval = _value;
214 unsigned oldval = _value;
220_OPENTHREADS_ATOMIC_INLINE
221Atomic::operator unsigned() const
223#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
224 __sync_synchronize();
226#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
229#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
230 membar_consumer(); // Hmm, do we need???
232#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
233 ScopedLock<Mutex> lock(_mutex);
240_OPENTHREADS_ATOMIC_INLINE bool
241AtomicPtr::assign(void* ptrNew, const void* const ptrOld)
243#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
244 return __sync_bool_compare_and_swap(&_ptr, (void *)ptrOld, ptrNew);
245#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
246 return __compare_and_swap((unsigned long*)&_ptr, (unsigned long)ptrOld, (unsigned long)ptrNew);
247#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
248 return ptrOld == atomic_cas_ptr(&_ptr, const_cast<void*>(ptrOld), ptrNew);
249#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
250 ScopedLock<Mutex> lock(_mutex);
263_OPENTHREADS_ATOMIC_INLINE void*
264AtomicPtr::get() const
266#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
267 __sync_synchronize();
269#elif defined(_OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS)
272#elif defined(_OPENTHREADS_ATOMIC_USE_SUN)
273 membar_consumer(); // Hmm, do we need???
275#elif defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
276 ScopedLock<Mutex> lock(_mutex);
283#endif // !defined(_OPENTHREADS_ATOMIC_USE_LIBRARY_ROUTINES)
287#endif // _OPENTHREADS_ATOMIC_