412 lines
12 KiB
C++
412 lines
12 KiB
C++
#ifndef BOOST_DETAIL_ATOMIC_BUILDER_HPP
|
|
#define BOOST_DETAIL_ATOMIC_BUILDER_HPP
|
|
|
|
// Copyright (c) 2009 Helge Bahmann
|
|
//
|
|
// 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)
|
|
|
|
#include <boost/detail/endian.hpp>
|
|
#include <boost/atomic/detail/valid_integral_types.hpp>
|
|
|
|
namespace boost {
|
|
namespace detail {
|
|
namespace atomic {
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
|
|
generates exchange and compare_exchange_strong
|
|
*/
|
|
template<typename Base>
|
|
class build_exchange : public Base {
|
|
public:
|
|
typedef typename Base::integral_type integral_type;
|
|
|
|
using Base::load;
|
|
using Base::compare_exchange_weak;
|
|
|
|
bool compare_exchange_strong(
|
|
integral_type &expected,
|
|
integral_type desired,
|
|
memory_order success_order,
|
|
memory_order failure_order) volatile
|
|
{
|
|
integral_type expected_save=expected;
|
|
while(true) {
|
|
if (compare_exchange_weak(expected, desired, success_order, failure_order)) return true;
|
|
if (expected_save!=expected) return false;
|
|
expected=expected_save;
|
|
}
|
|
}
|
|
|
|
integral_type exchange(integral_type replacement, memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
integral_type o=load(memory_order_relaxed);
|
|
do {} while(!compare_exchange_weak(o, replacement, order, memory_order_relaxed));
|
|
return o;
|
|
}
|
|
|
|
build_exchange() {}
|
|
explicit build_exchange(integral_type i) : Base(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- fetch_add_var(integral_type c, memory_order order)
|
|
- fetch_inc(memory_order order)
|
|
- fetch_dec(memory_order order)
|
|
|
|
creates a fetch_add method that delegates to fetch_inc/fetch_dec if operand
|
|
is constant +1/-1, and uses fetch_add_var otherwise
|
|
|
|
the intention is to allow optimizing the incredibly common case of +1/-1
|
|
*/
|
|
template<typename Base>
|
|
class build_const_fetch_add : public Base {
|
|
public:
|
|
typedef typename Base::integral_type integral_type;
|
|
|
|
integral_type fetch_add(
|
|
integral_type c,
|
|
memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
if (__builtin_constant_p(c)) {
|
|
switch(c) {
|
|
case -1: return fetch_dec(order);
|
|
case 1: return fetch_inc(order);
|
|
}
|
|
}
|
|
return fetch_add_var(c, order);
|
|
}
|
|
|
|
build_const_fetch_add() {}
|
|
explicit build_const_fetch_add(integral_type i) : Base(i) {}
|
|
protected:
|
|
using Base::fetch_add_var;
|
|
using Base::fetch_inc;
|
|
using Base::fetch_dec;
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
|
|
generates a -- not very efficient, but correct -- fetch_add operation
|
|
*/
|
|
template<typename Base>
|
|
class build_fetch_add : public Base {
|
|
public:
|
|
typedef typename Base::integral_type integral_type;
|
|
|
|
using Base::compare_exchange_weak;
|
|
|
|
integral_type fetch_add(
|
|
integral_type c, memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
integral_type o=Base::load(memory_order_relaxed), n;
|
|
do {n=o+c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
|
return o;
|
|
}
|
|
|
|
build_fetch_add() {}
|
|
explicit build_fetch_add(integral_type i) : Base(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- fetch_add(integral_type c, memory_order order)
|
|
|
|
generates fetch_sub and post/pre- increment/decrement operators
|
|
*/
|
|
template<typename Base>
|
|
class build_arithmeticops : public Base {
|
|
public:
|
|
typedef typename Base::integral_type integral_type;
|
|
|
|
using Base::fetch_add;
|
|
|
|
integral_type fetch_sub(
|
|
integral_type c,
|
|
memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
#if defined(BOOST_MSVC)
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned
|
|
#endif
|
|
return fetch_add(-c, order);
|
|
#if defined(BOOST_MSVC)
|
|
#pragma warning(pop)
|
|
#endif
|
|
}
|
|
|
|
build_arithmeticops() {}
|
|
explicit build_arithmeticops(integral_type i) : Base(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
|
|
generates -- not very efficient, but correct -- fetch_and, fetch_or and fetch_xor operators
|
|
*/
|
|
template<typename Base>
|
|
class build_logicops : public Base {
|
|
public:
|
|
typedef typename Base::integral_type integral_type;
|
|
|
|
using Base::compare_exchange_weak;
|
|
using Base::load;
|
|
|
|
integral_type fetch_and(integral_type c, memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
integral_type o=load(memory_order_relaxed), n;
|
|
do {n=o&c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
|
return o;
|
|
}
|
|
integral_type fetch_or(integral_type c, memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
integral_type o=load(memory_order_relaxed), n;
|
|
do {n=o|c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
|
return o;
|
|
}
|
|
integral_type fetch_xor(integral_type c, memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
integral_type o=load(memory_order_relaxed), n;
|
|
do {n=o^c;} while(!compare_exchange_weak(o, n, order, memory_order_relaxed));
|
|
return o;
|
|
}
|
|
|
|
build_logicops() {}
|
|
build_logicops(integral_type i) : Base(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- store(integral_type i, memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
|
|
generates the full set of atomic operations for integral types
|
|
*/
|
|
template<typename Base>
|
|
class build_atomic_from_minimal : public build_logicops< build_arithmeticops< build_fetch_add< build_exchange<Base> > > > {
|
|
public:
|
|
typedef build_logicops< build_arithmeticops< build_fetch_add< build_exchange<Base> > > > super;
|
|
typedef typename super::integral_type integral_type;
|
|
|
|
build_atomic_from_minimal(void) {}
|
|
build_atomic_from_minimal(typename super::integral_type i) : super(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- store(integral_type i, memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
- compare_exchange_strong(integral_type &expected, integral_type desired, memory_order order)
|
|
- exchange(integral_type replacement, memory_order order)
|
|
- fetch_add_var(integral_type c, memory_order order)
|
|
- fetch_inc(memory_order order)
|
|
- fetch_dec(memory_order order)
|
|
|
|
generates the full set of atomic operations for integral types
|
|
*/
|
|
template<typename Base>
|
|
class build_atomic_from_typical : public build_logicops< build_arithmeticops< build_const_fetch_add<Base> > > {
|
|
public:
|
|
typedef build_logicops< build_arithmeticops< build_const_fetch_add<Base> > > super;
|
|
typedef typename super::integral_type integral_type;
|
|
|
|
build_atomic_from_typical(void) {}
|
|
build_atomic_from_typical(typename super::integral_type i) : super(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- store(integral_type i, memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
- compare_exchange_strong(integral_type &expected, integral_type desired, memory_order order)
|
|
- exchange(integral_type replacement, memory_order order)
|
|
- fetch_add(integral_type c, memory_order order)
|
|
|
|
generates the full set of atomic operations for integral types
|
|
*/
|
|
template<typename Base>
|
|
class build_atomic_from_add : public build_logicops< build_arithmeticops<Base> > {
|
|
public:
|
|
typedef build_logicops< build_arithmeticops<Base> > super;
|
|
typedef typename super::integral_type integral_type;
|
|
|
|
build_atomic_from_add(void) {}
|
|
build_atomic_from_add(typename super::integral_type i) : super(i) {}
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- load(memory_order order)
|
|
- store(integral_type i, memory_order order)
|
|
- compare_exchange_weak(integral_type &expected, integral_type desired, memory_order order)
|
|
- compare_exchange_strong(integral_type &expected, integral_type desired, memory_order order)
|
|
- exchange(integral_type replacement, memory_order order)
|
|
|
|
generates the full set of atomic operations for integral types
|
|
*/
|
|
template<typename Base>
|
|
class build_atomic_from_exchange : public build_logicops< build_arithmeticops< build_fetch_add<Base> > > {
|
|
public:
|
|
typedef build_logicops< build_arithmeticops< build_fetch_add<Base> > > super;
|
|
typedef typename super::integral_type integral_type;
|
|
|
|
build_atomic_from_exchange(void) {}
|
|
build_atomic_from_exchange(typename super::integral_type i) : super(i) {}
|
|
};
|
|
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- compare_exchange_weak()
|
|
|
|
generates load, store and compare_exchange_weak for a smaller
|
|
data type (e.g. an atomic "byte" embedded into a temporary
|
|
and properly aligned atomic "int").
|
|
*/
|
|
template<typename Base, typename Type>
|
|
class build_base_from_larger_type {
|
|
public:
|
|
typedef Type integral_type;
|
|
|
|
build_base_from_larger_type() {}
|
|
build_base_from_larger_type(integral_type t) {store(t, memory_order_relaxed);}
|
|
|
|
integral_type load(memory_order order=memory_order_seq_cst) const volatile
|
|
{
|
|
larger_integral_type v=get_base().load(order);
|
|
return extract(v);
|
|
}
|
|
bool compare_exchange_weak(integral_type &expected,
|
|
integral_type desired,
|
|
memory_order success_order,
|
|
memory_order failure_order) volatile
|
|
{
|
|
larger_integral_type expected_;
|
|
larger_integral_type desired_;
|
|
|
|
expected_=get_base().load(memory_order_relaxed);
|
|
expected_=insert(expected_, expected);
|
|
desired_=insert(expected_, desired);
|
|
bool success=get_base().compare_exchange_weak(expected_, desired_, success_order, failure_order);
|
|
expected=extract(expected_);
|
|
return success;
|
|
}
|
|
void store(integral_type v,
|
|
memory_order order=memory_order_seq_cst) volatile
|
|
{
|
|
larger_integral_type expected, desired;
|
|
expected=get_base().load(memory_order_relaxed);
|
|
do {
|
|
desired=insert(expected, v);
|
|
} while(!get_base().compare_exchange_weak(expected, desired, order, memory_order_relaxed));
|
|
}
|
|
|
|
bool is_lock_free(void)
|
|
{
|
|
return get_base().is_lock_free();
|
|
}
|
|
private:
|
|
typedef typename Base::integral_type larger_integral_type;
|
|
|
|
const Base &get_base(void) const volatile
|
|
{
|
|
intptr_t address=(intptr_t)this;
|
|
address&=~(sizeof(larger_integral_type)-1);
|
|
return *reinterpret_cast<const Base *>(address);
|
|
}
|
|
Base &get_base(void) volatile
|
|
{
|
|
intptr_t address=(intptr_t)this;
|
|
address&=~(sizeof(larger_integral_type)-1);
|
|
return *reinterpret_cast<Base *>(address);
|
|
}
|
|
unsigned int get_offset(void) const volatile
|
|
{
|
|
intptr_t address=(intptr_t)this;
|
|
address&=(sizeof(larger_integral_type)-1);
|
|
return address;
|
|
}
|
|
|
|
unsigned int get_shift(void) const volatile
|
|
{
|
|
#if defined(BOOST_LITTLE_ENDIAN)
|
|
return get_offset()*8;
|
|
#elif defined(BOOST_BIG_ENDIAN)
|
|
return (sizeof(larger_integral_type)-sizeof(integral_type)-get_offset())*8;
|
|
#else
|
|
#error "Unknown endian"
|
|
#endif
|
|
}
|
|
|
|
integral_type extract(larger_integral_type v) const volatile
|
|
{
|
|
return v>>get_shift();
|
|
}
|
|
|
|
larger_integral_type insert(larger_integral_type target, integral_type source) const volatile
|
|
{
|
|
larger_integral_type tmp=source;
|
|
larger_integral_type mask=(larger_integral_type)-1;
|
|
|
|
mask=~(mask<<(8*sizeof(integral_type)));
|
|
|
|
mask=mask<<get_shift();
|
|
tmp=tmp<<get_shift();
|
|
|
|
tmp=(tmp & mask) | (target & ~mask);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
integral_type i;
|
|
};
|
|
|
|
/*
|
|
given a Base that implements:
|
|
|
|
- compare_exchange_weak()
|
|
|
|
generates the full set of atomic ops for a smaller
|
|
data type (e.g. an atomic "byte" embedded into a temporary
|
|
and properly aligned atomic "int").
|
|
*/
|
|
template<typename Base, typename Type>
|
|
class build_atomic_from_larger_type : public build_atomic_from_minimal< build_base_from_larger_type<Base, Type> > {
|
|
public:
|
|
typedef build_atomic_from_minimal< build_base_from_larger_type<Base, Type> > super;
|
|
//typedef typename super::integral_type integral_type;
|
|
typedef Type integral_type;
|
|
|
|
build_atomic_from_larger_type() {}
|
|
build_atomic_from_larger_type(integral_type v) : super(v) {}
|
|
};
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|