peerplays-fc/include/boost/atomic/detail/linux-arm.hpp
2012-09-07 22:50:37 -04:00

171 lines
5.6 KiB
C++

#ifndef BOOST_DETAIL_ATOMIC_LINUX_ARM_HPP
#define BOOST_DETAIL_ATOMIC_LINUX_ARM_HPP
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Copyright (c) 2009 Helge Bahmann
// Copyright (c) 2009 Phil Endecott
// ARM Code by Phil Endecott, based on other architectures.
#include <boost/memory_order.hpp>
#include <boost/atomic/detail/base.hpp>
#include <boost/atomic/detail/builder.hpp>
namespace boost {
namespace detail {
namespace atomic {
// Different ARM processors have different atomic instructions. In particular,
// architecture versions before v6 (which are still in widespread use, e.g. the
// Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap.
// On Linux the kernel provides some support that lets us abstract away from
// these differences: it provides emulated CAS and barrier functions at special
// addresses that are garaunteed not to be interrupted by the kernel. Using
// this facility is slightly slower than inline assembler would be, but much
// faster than a system call.
//
// For documentation, see arch/arm/kernel/entry-armv.S in the kernel source
// (search for "User Helpers").
typedef void (kernel_dmb_t)(void);
#define BOOST_ATOMIC_KERNEL_DMB (*(kernel_dmb_t *)0xffff0fa0)
static inline void fence_before(memory_order order)
{
switch(order) {
// FIXME I really don't know which of these cases should call
// kernel_dmb() and which shouldn't...
case memory_order_consume:
case memory_order_release:
case memory_order_acq_rel:
case memory_order_seq_cst:
BOOST_ATOMIC_KERNEL_DMB();
default:;
}
}
static inline void fence_after(memory_order order)
{
switch(order) {
// FIXME I really don't know which of these cases should call
// kernel_dmb() and which shouldn't...
case memory_order_acquire:
case memory_order_acq_rel:
case memory_order_seq_cst:
BOOST_ATOMIC_KERNEL_DMB();
default:;
}
}
#undef BOOST_ATOMIC_KERNEL_DMB
template<typename T>
class atomic_linux_arm_4 {
// typedef int (kernel_cmpxchg_t)(T oldval, T newval, T *ptr);
typedef int (kernel_cmpxchg_t)(T oldval, T newval, volatile T *ptr);
# define BOOST_ATOMIC_KERNEL_CMPXCHG (*(kernel_cmpxchg_t *)0xffff0fc0)
// Returns 0 if *ptr was changed.
public:
explicit atomic_linux_arm_4(T v) : i(v) {}
atomic_linux_arm_4() {}
T load(memory_order order=memory_order_seq_cst) const volatile
{
T v=const_cast<volatile const T &>(i);
fence_after(order);
return v;
}
void store(T v, memory_order order=memory_order_seq_cst) volatile
{
fence_before(order);
const_cast<volatile T &>(i)=v;
}
bool compare_exchange_strong(
T &expected,
T desired,
memory_order success_order,
memory_order failure_order) volatile
{
// Aparently we can consider kernel_cmpxchg to be strong if it is retried
// by the kernel after being interrupted, which I think it is.
// Also it seems that when an ll/sc implementation is used the kernel
// loops until the store succeeds.
bool success = BOOST_ATOMIC_KERNEL_CMPXCHG(expected,desired,&i)==0;
if (!success) expected = load(memory_order_relaxed);
return success;
}
bool compare_exchange_weak(
T &expected,
T desired,
memory_order success_order,
memory_order failure_order) volatile
{
return compare_exchange_strong(expected, desired, success_order, failure_order);
}
T exchange(T replacement, memory_order order=memory_order_seq_cst) volatile
{
// Copied from build_exchange.
T o=load(memory_order_relaxed);
do {} while(!compare_exchange_weak(o, replacement, order, order));
return o;
// Note that ARM has an atomic swap instruction that we could use here:
// T oldval;
// asm volatile ("swp\t%0, %1, [%2]" : "=&r"(oldval) : "r" (replacement), "r" (&i) : "memory");
// return oldval;
// This instruction is deprecated in architecture >= 6. I'm unsure how inefficient
// its implementation is on those newer architectures.
// I don't think this would gain
// much since exchange() is not used often.
}
bool is_lock_free(void) const volatile {return true;}
typedef T integral_type;
protected:
private:
T i;
# undef BOOST_ATOMIC_KERNEL_CMPXCHG
};
template<typename T>
class platform_atomic_integral<T, 4> : public build_atomic_from_exchange<atomic_linux_arm_4<T> > {
public:
typedef build_atomic_from_exchange<atomic_linux_arm_4<T> > super;
explicit platform_atomic_integral(T v) : super(v) {}
platform_atomic_integral(void) {}
};
template<typename T>
class platform_atomic_integral<T, 1> : public build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T > {
public:
typedef build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T> super;
explicit platform_atomic_integral(T v) : super(v) {}
platform_atomic_integral(void) {}
};
template<typename T>
class platform_atomic_integral<T, 2> : public build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T > {
public:
typedef build_atomic_from_larger_type<atomic_linux_arm_4<uint32_t>, T> super;
explicit platform_atomic_integral(T v) : super(v) {}
platform_atomic_integral(void) {}
};
typedef atomic_linux_arm_4<void *> platform_atomic_address;
}
}
}
#endif