PageRenderTime 175ms CodeModel.GetById 34ms app.highlight 98ms RepoModel.GetById 39ms app.codeStats 0ms

/mordor/atomic.h

http://github.com/mozy/mordor
C Header | 286 lines | 268 code | 16 blank | 2 comment | 44 complexity | 376fc7caa902f242126ed3cd6a679935 MD5 | raw file
  1#ifndef __MORDOR_ATOMIC_H__
  2#define __MORDOR_ATOMIC_H__
  3
  4#include <boost/utility/enable_if.hpp>
  5
  6#include "predef.h"
  7
  8#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1 && defined(__arm__))
  9#include <boost/smart_ptr/detail/sp_counted_base_spin.hpp>
 10#endif
 11
 12#ifdef OSX
 13#include <libkern/OSAtomic.h>
 14#endif
 15
 16#ifdef _MSC_VER
 17#include <intrin.h>
 18#endif
 19
 20namespace Mordor {
 21
 22#ifdef WINDOWS
 23template <class T>
 24typename boost::enable_if_c<sizeof(T) == sizeof(LONG), T>::type
 25atomicDecrement(volatile T& t)
 26{
 27    return InterlockedDecrement((volatile LONG*)&t);
 28}
 29template <class T>
 30typename boost::enable_if_c<sizeof(T) == sizeof(LONG), T>::type
 31atomicIncrement(volatile T& t)
 32{
 33    return InterlockedIncrement((volatile LONG*)&t);
 34}
 35template <class T>
 36typename boost::enable_if_c<sizeof(T) == sizeof(LONG), T>::type
 37atomicAdd(volatile T& t, T v)
 38{
 39    return InterlockedExchangeAdd((volatile LONG*)&t, (LONG)v) + v;
 40}
 41template <class T>
 42typename boost::enable_if_c<sizeof(T) == sizeof(LONG), T>::type
 43atomicCompareAndSwap(volatile T& t, T newvalue, T comparand)
 44{
 45    return InterlockedCompareExchange((volatile LONG*)&t, (LONG)newvalue, (LONG)comparand);
 46}
 47template <class T>
 48typename boost::enable_if_c<sizeof(T) == sizeof(LONG), T>::type
 49atomicSwap(volatile T& t, T newvalue)
 50{
 51    return InterlockedExchange((volatile LONG*)&t, (LONG)newvalue);
 52}
 53inline
 54bool
 55atomicTestAndSet(volatile void *address, int bit = 0)
 56{
 57    return !!InterlockedBitTestAndSet((volatile LONG*)address + (bit >> 5), (LONG)(0x80000000 >> (bit & 31)));
 58}
 59inline
 60bool
 61atomicTestAndClear(volatile void *address, int bit = 0)
 62{
 63    return !!InterlockedBitTestAndReset((volatile LONG*)address + (bit >> 5), (LONG)(0x80000000 >> (bit & 31)));
 64}
 65#ifdef X86_64
 66template <class T>
 67typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG), T>::type
 68atomicDecrement(volatile T& t)
 69{
 70    return InterlockedDecrement64((volatile LONGLONG*)&t);
 71}
 72template <class T>
 73typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG), T>::type
 74atomicIncrement(volatile T& t)
 75{
 76    return InterlockedIncrement64((volatile LONGLONG*)&t);
 77}
 78template <class T>
 79typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG), T>::type
 80atomicAdd(volatile T& t, T v)
 81{
 82    return InterlockedExchangeAdd64((volatile LONGLONG*)&t, (LONGLONG)v) + v;
 83}
 84template <class T>
 85typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG), T>::type
 86atomicCompareAndSwap(volatile T& t, T newvalue, T comparand)
 87{
 88    return InterlockedCompareExchange64((volatile LONGLONG*)&t, (LONGLONG)newvalue, (LONGLONG)comparand);
 89}
 90template <class T>
 91typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG), T>::type
 92atomicSwap(volatile T& t, T newvalue)
 93{
 94    return InterlockedExchange64((volatile LONGLONG*)&t, (LONGLONG)newvalue);
 95}
 96#endif
 97#elif defined(OSX)
 98
 99#include <libkern/OSAtomic.h>
100
101template <class T>
102typename boost::enable_if_c<sizeof(T) == sizeof(int32_t), T>::type
103atomicDecrement(volatile T &t)
104{
105    return OSAtomicDecrement32Barrier((volatile int32_t *)&t);
106}
107template <class T>
108typename boost::enable_if_c<sizeof(T) == sizeof(int32_t), T>::type
109atomicIncrement(volatile T &t)
110{
111    return OSAtomicIncrement32Barrier((volatile int32_t *)&t);
112}
113template <class T>
114typename boost::enable_if_c<sizeof(T) == sizeof(int32_t), T>::type
115atomicAdd(volatile T &t, T v)
116{
117    return OSAtomicAdd32Barrier((int32_t)v, (volatile int32_t *)&t);
118}
119template <class T>
120typename boost::enable_if_c<sizeof(T) == sizeof(int32_t), T>::type
121atomicCompareAndSwap(volatile T &t, T newvalue, T comparand)
122{
123    return OSAtomicCompareAndSwap32Barrier((int32_t)comparand, (int32_t)newvalue, (volatile int32_t *)&t) ? comparand : t;
124}
125template <class T>
126typename boost::enable_if_c<sizeof(T) == sizeof(int32_t), T>::type
127atomicSwap(volatile T &t, T newvalue)
128{
129    int32_t comparand = (int32_t)t;
130    while (!OSAtomicCompareAndSwap32Barrier((int32_t)comparand, (int32_t)newvalue, (volatile int32_t *) &t))
131        comparand = (int32_t)t;
132    return comparand;
133}
134inline
135bool
136atomicTestAndSet(volatile void *addr, int bit = 0)
137{
138    return OSAtomicTestAndSetBarrier((uint32_t)bit, addr);
139}
140template <class T>
141bool
142atomicTestAndClear(volatile void *addr, int bit = 0)
143{
144    return OSAtomicTestAndClearBarrier((uint32_t)bit, addr);
145}
146#ifdef X86_64
147template <class T>
148typename boost::enable_if_c<sizeof(T) == sizeof(int64_t), T>::type
149atomicDecrement(volatile T &t)
150{
151    return OSAtomicDecrement64Barrier((volatile int64_t *)&t);
152}
153template <class T>
154typename boost::enable_if_c<sizeof(T) == sizeof(int64_t), T>::type
155atomicIncrement(volatile T &t)
156{
157    return OSAtomicIncrement64Barrier((volatile int64_t *)&t);
158}
159template <class T>
160typename boost::enable_if_c<sizeof(T) == sizeof(int64_t), T>::type
161atomicAdd(volatile T &t, T v)
162{
163    return OSAtomicAdd64Barrier((int64_t)v, (volatile int64_t *)&t);
164}
165template <class T>
166typename boost::enable_if_c<sizeof(T) == sizeof(int64_t), T>::type
167atomicCompareAndSwap(volatile T &t, T newvalue, T comparand)
168{
169    return OSAtomicCompareAndSwap64Barrier((int64_t)comparand, (int64_t)newvalue, (volatile int64_t *)&t) ? comparand : t;
170}
171template <class T>
172typename boost::enable_if_c<sizeof(T) == sizeof(int64_t), T>::type
173atomicSwap(volatile T &t, T newvalue)
174{
175    int64_t comparand = (int64_t)t;
176    while (!OSAtomicCompareAndSwap64Barrier((int64_t)comparand, (int64_t)newvalue, (volatile int64_t *)&t))
177        comparand = (int64_t)t;
178    return comparand;
179}
180#endif
181#elif ((__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1) && !defined(__arm__))
182template <class T>
183typename boost::enable_if_c<sizeof(T) <= sizeof(void *), T>::type
184atomicDecrement(volatile T& t) { return __sync_sub_and_fetch(&t, 1); }
185template <class T>
186typename boost::enable_if_c<sizeof(T) <= sizeof(void *), T>::type
187atomicIncrement(volatile T& t) { return __sync_add_and_fetch(&t, 1); }
188template <class T>
189typename boost::enable_if_c<sizeof(T) <= sizeof(void *), T>::type
190atomicAdd(volatile T& t, T v) { return __sync_add_and_fetch(&t, v); }
191template <class T>
192typename boost::enable_if_c<sizeof(T) <= sizeof(void *), T>::type
193atomicCompareAndSwap(volatile T &t, T newvalue, T comparand)
194{ return __sync_val_compare_and_swap((volatile T *)&t, comparand, newvalue); }
195template <class T>
196typename boost::enable_if_c<sizeof(T) <= sizeof(void *), T>::type
197atomicSwap(volatile T &t, T newvalue)
198{ return __sync_lock_test_and_set(&t, newvalue); }
199inline
200bool
201atomicTestAndSet(volatile void *address, int bit = 0)
202{
203    int mask = (1 << (sizeof(int) * 8 - 1)) >> (bit & (sizeof(int) * 8 - 1));
204    volatile int &target = *(volatile int *)((intptr_t)address >> (sizeof(int) >> 3));
205    int oldvalue, newvalue;
206    do {
207        oldvalue = target;
208        newvalue = oldvalue | mask;
209    } while (newvalue != atomicCompareAndSwap(target, newvalue, oldvalue));
210    return !!(oldvalue & mask);
211}
212inline
213bool
214atomicTestAndClear(volatile void *address, int bit = 0)
215{
216    int mask = (1 << (sizeof(int) * 8 - 1)) >> (bit & (sizeof(int) * 8 - 1));
217    volatile int &target = *(volatile int *)((intptr_t)address >> (sizeof(int) >> 3));
218    int oldvalue, newvalue;
219    do {
220        oldvalue = target;
221        newvalue = oldvalue & ~mask;
222    } while (newvalue != atomicCompareAndSwap(target, newvalue, oldvalue));
223    return !!(oldvalue & mask);
224}
225#elif (__GNUC__ == 4 && __GNUC_MINOR__ == 0) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
226template <class T>
227typename boost::enable_if_c<sizeof(T) <= sizeof(_Atomic_word), T>::type
228atomicDecrement(volatile T& t) { return __gnu_cxx::__exchange_and_add((_Atomic_word*)_&t, -1) - 1; }
229template <class T>
230typename boost::enable_if_c<sizeof(T) <= sizeof(_Atomic_word), T>::type
231atomicIncrement(volatile T& t) { return __gnu_cxx::__exchange_and_add((_Atomic_word*)_&t, 1) + 1; }
232template <class T>
233typename boost::enable_if_c<sizeof(T) <= sizeof(_Atomic_word), T>::type
234atomicAdd(volatile T& t, T v) { return __gnu_cxx::__exchange_and_add((_Atomic_word*)_&t, v) + v; }
235#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1 && defined(__arm__))
236template <class T>
237typename boost::enable_if_c<sizeof(T) <= sizeof(int), T>::type
238atomicAdd(volatile T& t, T v) { return boost::detail::atomic_exchange_and_add((int *)&t, (int)v) + v; }
239template <class T>
240typename boost::enable_if_c<sizeof(T) <= sizeof(int), T>::type
241atomicIncrement(volatile T& t) { return atomicAdd(t, (T)1); }
242template <class T>
243typename boost::enable_if_c<sizeof(T) <= sizeof(int), T>::type
244atomicCompareAndSwap(volatile T &t, T newvalue, T comparand) {
245    ::boost::detail::spinlock_pool<1>::scoped_lock lock((void *)&t);
246    T oldvalue = t;
247    if (oldvalue == comparand)
248        t = newvalue;
249    return oldvalue;
250}
251#endif
252
253template <typename T>
254class Atomic
255{
256public:
257    Atomic(T val = 0) : m_val(val) { }
258
259    operator T(void) const { return atomicAdd(m_val, T(0)); }
260    T operator +=(T v) { return atomicAdd(m_val, v); }
261    T operator -=(T v) { return atomicAdd(m_val, -v); }
262    T operator ++(void) { return atomicIncrement(m_val); }
263    T operator --(void) { return atomicDecrement(m_val); }
264
265    // the postfix operators couild be a little more efficient if we
266    // created atomicPost(Increment,Decrement) functions, but meh
267    T operator ++(int) { return atomicIncrement(m_val) - 1; }
268    T operator --(int) { return atomicDecrement(m_val) + 1; }
269
270private:
271    mutable T m_val;
272};
273
274#ifdef _MSC_VER
275inline void compilerReadWriteBarrier() { _ReadWriteBarrier(); }
276inline void compilerReadBarrier() { _ReadBarrier(); }
277inline void compilerWriteBarrier() { _WriteBarrier(); }
278#elif defined (__GNUC__)
279inline void compilerReadWriteBarrier() { __asm__ __volatile__ ("" ::: "memory"); }
280inline void compilerReadBarrier() { compilerReadWriteBarrier(); }
281inline void compilerWriteBarrier() { compilerReadWriteBarrier(); }
282#endif
283
284}
285
286#endif