a portable and fast pairing-based cryptography library
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.
 
 
 
 
 
 
mcl/include/cybozu/atomic.hpp

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