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.
146 lines
2.7 KiB
146 lines
2.7 KiB
#pragma once
|
|
/**
|
|
@file
|
|
@brief atomic operation
|
|
|
|
@author MITSUNARI Shigeo(@herumi)
|
|
@author MITSUNARI Shigeo
|
|
*/
|
|
#include <cybozu/inttype.hpp>
|
|
#ifdef _WIN32
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include <windows.h>
|
|
#include <intrin.h>
|
|
#else
|
|
#include <emmintrin.h>
|
|
#endif
|
|
|
|
namespace cybozu {
|
|
|
|
namespace atomic_local {
|
|
|
|
template<size_t S>
|
|
struct Tag {};
|
|
|
|
template<>
|
|
struct Tag<4> {
|
|
template<class T>
|
|
static inline T AtomicAddSub(T *p, T y)
|
|
{
|
|
#ifdef _WIN32
|
|
return (T)_InterlockedExchangeAdd((long*)p, (long)y);
|
|
#else
|
|
return static_cast<T>(__sync_fetch_and_add(p, y));
|
|
#endif
|
|
}
|
|
|
|
template<class T>
|
|
static inline T AtomicCompareExchangeSub(T *p, T newValue, T oldValue)
|
|
{
|
|
#ifdef _WIN32
|
|
return (T)_InterlockedCompareExchange((long*)p, (long)newValue, (long)oldValue);
|
|
#else
|
|
return static_cast<T>(__sync_val_compare_and_swap(p, oldValue, newValue));
|
|
#endif
|
|
}
|
|
|
|
template<class T>
|
|
static inline T AtomicExchangeSub(T *p, T newValue)
|
|
{
|
|
#ifdef _WIN32
|
|
return (T)_InterlockedExchange((long*)p, (long)newValue);
|
|
#else
|
|
return static_cast<T>(__sync_lock_test_and_set(p, newValue));
|
|
#endif
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Tag<8> {
|
|
#if (CYBOZU_OS_BIT == 64)
|
|
template<class T>
|
|
static inline T AtomicAddSub(T *p, T y)
|
|
{
|
|
#ifdef _WIN32
|
|
return (T)_InterlockedExchangeAdd64((int64_t*)p, (int64_t)y);
|
|
#else
|
|
return static_cast<T>(__sync_fetch_and_add(p, y));
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
template<class T>
|
|
static inline T AtomicCompareExchangeSub(T *p, T newValue, T oldValue)
|
|
{
|
|
#ifdef _WIN32
|
|
return (T)_InterlockedCompareExchange64((int64_t*)p, (int64_t)newValue, (int64_t)oldValue);
|
|
#else
|
|
return static_cast<T>(__sync_val_compare_and_swap(p, oldValue, newValue));
|
|
#endif
|
|
}
|
|
|
|
#if (CYBOZU_OS_BIT == 64)
|
|
template<class T>
|
|
static inline T AtomicExchangeSub(T *p, T newValue)
|
|
{
|
|
#ifdef _WIN32
|
|
return (T)_InterlockedExchange64((int64_t*)p, (int64_t)newValue);
|
|
#else
|
|
return static_cast<T>(__sync_lock_test_and_set(p, newValue));
|
|
#endif
|
|
}
|
|
#endif
|
|
};
|
|
|
|
} // atomic_local
|
|
|
|
/**
|
|
atomic operation
|
|
see http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Atomic-Builtins.html
|
|
http://msdn.microsoft.com/en-us/library/ms683504(VS.85).aspx
|
|
*/
|
|
/**
|
|
tmp = *p;
|
|
*p += y;
|
|
return tmp;
|
|
*/
|
|
template<class T>
|
|
T AtomicAdd(T *p, T y)
|
|
{
|
|
return atomic_local::Tag<sizeof(T)>::AtomicAddSub(p, y);
|
|
}
|
|
|
|
/**
|
|
tmp = *p;
|
|
if (*p == oldValue) *p = newValue;
|
|
return tmp;
|
|
*/
|
|
template<class T>
|
|
T AtomicCompareExchange(T *p, T newValue, T oldValue)
|
|
{
|
|
return atomic_local::Tag<sizeof(T)>::AtomicCompareExchangeSub(p, newValue, oldValue);
|
|
}
|
|
|
|
/**
|
|
tmp = *p;
|
|
*p = newValue;
|
|
return tmp;
|
|
*/
|
|
template<class T>
|
|
T AtomicExchange(T *p, T newValue)
|
|
{
|
|
return atomic_local::Tag<sizeof(T)>::AtomicExchangeSub(p, newValue);
|
|
}
|
|
|
|
inline void mfence()
|
|
{
|
|
#ifdef _MSC_VER
|
|
MemoryBarrier();
|
|
#else
|
|
_mm_mfence();
|
|
#endif
|
|
}
|
|
|
|
} // cybozu
|
|
|