feat():initial version
This commit is contained in:
66
install/boost_1_75_0/include/boost/fiber/detail/config.hpp
Normal file
66
install/boost_1_75_0/include/boost/fiber/detail/config.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_CONFIG_H
|
||||
#define BOOST_FIBERS_DETAIL_CONFIG_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef.h>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#ifdef BOOST_FIBERS_DECL
|
||||
# undef BOOST_FIBERS_DECL
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_FIBERS_DYN_LINK) ) && ! defined(BOOST_FIBERS_STATIC_LINK)
|
||||
# if defined(BOOST_FIBERS_SOURCE)
|
||||
# define BOOST_FIBERS_DECL BOOST_SYMBOL_EXPORT
|
||||
# define BOOST_FIBERS_BUILD_DLL
|
||||
# else
|
||||
# define BOOST_FIBERS_DECL BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ! defined(BOOST_FIBERS_DECL)
|
||||
# define BOOST_FIBERS_DECL
|
||||
#endif
|
||||
|
||||
#if ! defined(BOOST_FIBERS_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_FIBERS_NO_LIB)
|
||||
# define BOOST_LIB_NAME boost_fiber
|
||||
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_FIBERS_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# include <boost/config/auto_link.hpp>
|
||||
#endif
|
||||
|
||||
#if BOOST_OS_LINUX || BOOST_OS_WINDOWS
|
||||
# define BOOST_FIBERS_HAS_FUTEX
|
||||
#endif
|
||||
|
||||
#if (!defined(BOOST_FIBERS_HAS_FUTEX) && \
|
||||
(defined(BOOST_FIBERS_SPINLOCK_TTAS_FUTEX) || defined(BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX)))
|
||||
# error "futex not supported on this platform"
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)
|
||||
# define BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD 16
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_FIBERS_RETRY_THRESHOLD)
|
||||
# define BOOST_FIBERS_RETRY_THRESHOLD 64
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_FIBERS_SPIN_BEFORE_SLEEP0)
|
||||
# define BOOST_FIBERS_SPIN_BEFORE_SLEEP0 32
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_FIBERS_SPIN_BEFORE_YIELD)
|
||||
# define BOOST_FIBERS_SPIN_BEFORE_YIELD 64
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_CONFIG_H
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2015.
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_SPINLOCK_QUEUE_H
|
||||
#define BOOST_FIBERS_DETAIL_SPINLOCK_QUEUE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/context.hpp>
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/spinlock.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class context_spinlock_queue {
|
||||
private:
|
||||
typedef context * slot_type;
|
||||
|
||||
mutable spinlock splk_{};
|
||||
std::size_t pidx_{ 0 };
|
||||
std::size_t cidx_{ 0 };
|
||||
std::size_t capacity_;
|
||||
slot_type * slots_;
|
||||
|
||||
void resize_() {
|
||||
slot_type * old_slots = slots_;
|
||||
slots_ = new slot_type[2*capacity_];
|
||||
std::size_t offset = capacity_ - cidx_;
|
||||
std::memcpy( slots_, old_slots + cidx_, offset * sizeof( slot_type) );
|
||||
if ( 0 < cidx_) {
|
||||
std::memcpy( slots_ + offset, old_slots, pidx_ * sizeof( slot_type) );
|
||||
}
|
||||
cidx_ = 0;
|
||||
pidx_ = capacity_ - 1;
|
||||
capacity_ *= 2;
|
||||
delete [] old_slots;
|
||||
}
|
||||
|
||||
bool is_full_() const noexcept {
|
||||
return cidx_ == ((pidx_ + 1) % capacity_);
|
||||
}
|
||||
|
||||
bool is_empty_() const noexcept {
|
||||
return cidx_ == pidx_;
|
||||
}
|
||||
|
||||
public:
|
||||
context_spinlock_queue( std::size_t capacity = 4096) :
|
||||
capacity_{ capacity } {
|
||||
slots_ = new slot_type[capacity_];
|
||||
}
|
||||
|
||||
~context_spinlock_queue() {
|
||||
delete [] slots_;
|
||||
}
|
||||
|
||||
context_spinlock_queue( context_spinlock_queue const&) = delete;
|
||||
context_spinlock_queue & operator=( context_spinlock_queue const&) = delete;
|
||||
|
||||
bool empty() const noexcept {
|
||||
spinlock_lock lk{ splk_ };
|
||||
return is_empty_();
|
||||
}
|
||||
|
||||
void push( context * c) {
|
||||
spinlock_lock lk{ splk_ };
|
||||
if ( is_full_() ) {
|
||||
resize_();
|
||||
}
|
||||
slots_[pidx_] = c;
|
||||
pidx_ = (pidx_ + 1) % capacity_;
|
||||
}
|
||||
|
||||
context * pop() {
|
||||
spinlock_lock lk{ splk_ };
|
||||
context * c = nullptr;
|
||||
if ( ! is_empty_() ) {
|
||||
c = slots_[cidx_];
|
||||
cidx_ = (cidx_ + 1) % capacity_;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
context * steal() {
|
||||
spinlock_lock lk{ splk_ };
|
||||
context * c = nullptr;
|
||||
if ( ! is_empty_() ) {
|
||||
c = slots_[cidx_];
|
||||
if ( c->is_context( type::pinned_context) ) {
|
||||
return nullptr;
|
||||
}
|
||||
cidx_ = (cidx_ + 1) % capacity_;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_SPINLOCK_QUEUE_H
|
||||
@@ -0,0 +1,197 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_CONTEXT_SPMC_QUEUE_H
|
||||
#define BOOST_FIBERS_DETAIL_CONTEXT_SPMC_QUEUE_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/context.hpp>
|
||||
|
||||
// David Chase and Yossi Lev. Dynamic circular work-stealing deque.
|
||||
// In SPAA ’05: Proceedings of the seventeenth annual ACM symposium
|
||||
// on Parallelism in algorithms and architectures, pages 21–28,
|
||||
// New York, NY, USA, 2005. ACM.
|
||||
//
|
||||
// Nhat Minh Lê, Antoniu Pop, Albert Cohen, and Francesco Zappa Nardelli. 2013.
|
||||
// Correct and efficient work-stealing for weak memory models.
|
||||
// In Proceedings of the 18th ACM SIGPLAN symposium on Principles and practice
|
||||
// of parallel programming (PPoPP '13). ACM, New York, NY, USA, 69-80.
|
||||
|
||||
#if BOOST_COMP_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-private-field"
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class context_spmc_queue {
|
||||
private:
|
||||
class array {
|
||||
private:
|
||||
typedef std::atomic< context * > atomic_type;
|
||||
typedef atomic_type storage_type;
|
||||
|
||||
std::size_t capacity_;
|
||||
storage_type * storage_;
|
||||
|
||||
public:
|
||||
array( std::size_t capacity) :
|
||||
capacity_{ capacity },
|
||||
storage_{ new storage_type[capacity_] } {
|
||||
for ( std::size_t i = 0; i < capacity_; ++i) {
|
||||
::new ( static_cast< void * >( std::addressof( storage_[i]) ) ) atomic_type{ nullptr };
|
||||
}
|
||||
}
|
||||
|
||||
~array() {
|
||||
for ( std::size_t i = 0; i < capacity_; ++i) {
|
||||
reinterpret_cast< atomic_type * >( std::addressof( storage_[i]) )->~atomic_type();
|
||||
}
|
||||
delete [] storage_;
|
||||
}
|
||||
|
||||
std::size_t capacity() const noexcept {
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
void push( std::size_t bottom, context * ctx) noexcept {
|
||||
reinterpret_cast< atomic_type * >(
|
||||
std::addressof( storage_[bottom % capacity_]) )
|
||||
->store( ctx, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
context * pop( std::size_t top) noexcept {
|
||||
return reinterpret_cast< atomic_type * >(
|
||||
std::addressof( storage_[top % capacity_]) )
|
||||
->load( std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
array * resize( std::size_t bottom, std::size_t top) {
|
||||
std::unique_ptr< array > tmp{ new array{ 2 * capacity_ } };
|
||||
for ( std::size_t i = top; i != bottom; ++i) {
|
||||
tmp->push( i, pop( i) );
|
||||
}
|
||||
return tmp.release();
|
||||
}
|
||||
};
|
||||
|
||||
std::atomic< std::size_t > top_{ 0 };
|
||||
std::atomic< std::size_t > bottom_{ 0 };
|
||||
std::atomic< array * > array_;
|
||||
std::vector< array * > old_arrays_{};
|
||||
char padding_[cacheline_length];
|
||||
|
||||
public:
|
||||
context_spmc_queue( std::size_t capacity = 4096) :
|
||||
array_{ new array{ capacity } } {
|
||||
old_arrays_.reserve( 32);
|
||||
}
|
||||
|
||||
~context_spmc_queue() {
|
||||
for ( array * a : old_arrays_) {
|
||||
delete a;
|
||||
}
|
||||
delete array_.load();
|
||||
}
|
||||
|
||||
context_spmc_queue( context_spmc_queue const&) = delete;
|
||||
context_spmc_queue & operator=( context_spmc_queue const&) = delete;
|
||||
|
||||
bool empty() const noexcept {
|
||||
std::size_t bottom = bottom_.load( std::memory_order_relaxed);
|
||||
std::size_t top = top_.load( std::memory_order_relaxed);
|
||||
return bottom <= top;
|
||||
}
|
||||
|
||||
void push( context * ctx) {
|
||||
std::size_t bottom = bottom_.load( std::memory_order_relaxed);
|
||||
std::size_t top = top_.load( std::memory_order_acquire);
|
||||
array * a = array_.load( std::memory_order_relaxed);
|
||||
if ( (a->capacity() - 1) < (bottom - top) ) {
|
||||
// queue is full
|
||||
// resize
|
||||
array * tmp = a->resize( bottom, top);
|
||||
old_arrays_.push_back( a);
|
||||
std::swap( a, tmp);
|
||||
array_.store( a, std::memory_order_relaxed);
|
||||
}
|
||||
a->push( bottom, ctx);
|
||||
std::atomic_thread_fence( std::memory_order_release);
|
||||
bottom_.store( bottom + 1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
context * pop() {
|
||||
std::size_t bottom = bottom_.load( std::memory_order_relaxed) - 1;
|
||||
array * a = array_.load( std::memory_order_relaxed);
|
||||
bottom_.store( bottom, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence( std::memory_order_seq_cst);
|
||||
std::size_t top = top_.load( std::memory_order_relaxed);
|
||||
context * ctx = nullptr;
|
||||
if ( top <= bottom) {
|
||||
// queue is not empty
|
||||
ctx = a->pop( bottom);
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
if ( top == bottom) {
|
||||
// last element dequeued
|
||||
if ( ! top_.compare_exchange_strong( top, top + 1,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_relaxed) ) {
|
||||
// lose the race
|
||||
ctx = nullptr;
|
||||
}
|
||||
bottom_.store( bottom + 1, std::memory_order_relaxed);
|
||||
}
|
||||
} else {
|
||||
// queue is empty
|
||||
bottom_.store( bottom + 1, std::memory_order_relaxed);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
context * steal() {
|
||||
std::size_t top = top_.load( std::memory_order_acquire);
|
||||
std::atomic_thread_fence( std::memory_order_seq_cst);
|
||||
std::size_t bottom = bottom_.load( std::memory_order_acquire);
|
||||
context * ctx = nullptr;
|
||||
if ( top < bottom) {
|
||||
// queue is not empty
|
||||
array * a = array_.load( std::memory_order_consume);
|
||||
ctx = a->pop( top);
|
||||
BOOST_ASSERT( nullptr != ctx);
|
||||
// do not steal pinned context (e.g. main-/dispatcher-context)
|
||||
if ( ctx->is_context( type::pinned_context) ) {
|
||||
return nullptr;
|
||||
}
|
||||
if ( ! top_.compare_exchange_strong( top, top + 1,
|
||||
std::memory_order_seq_cst,
|
||||
std::memory_order_relaxed) ) {
|
||||
// lose the race
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#if BOOST_COMP_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_CONTEXT_SPMC_QUEUE_H
|
||||
43
install/boost_1_75_0/include/boost/fiber/detail/convert.hpp
Normal file
43
install/boost_1_75_0/include/boost/fiber/detail/convert.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_CONVERT_H
|
||||
#define BOOST_FIBERS_DETAIL_CONVERT_H
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
inline
|
||||
std::chrono::steady_clock::time_point convert(
|
||||
std::chrono::steady_clock::time_point const& timeout_time) noexcept {
|
||||
return timeout_time;
|
||||
}
|
||||
|
||||
template< typename Clock, typename Duration >
|
||||
std::chrono::steady_clock::time_point convert(
|
||||
std::chrono::time_point< Clock, Duration > const& timeout_time) {
|
||||
return std::chrono::steady_clock::now() + ( timeout_time - Clock::now() );
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_CONVERT_H
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2016.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_CPU_RELAX_H
|
||||
#define BOOST_FIBERS_DETAIL_CPU_RELAX_H
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#if BOOST_COMP_MSVC || BOOST_COMP_MSVC_EMULATED
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
#if BOOST_ARCH_ARM
|
||||
# if BOOST_COMP_MSVC
|
||||
# define cpu_relax() YieldProcessor();
|
||||
# elif (defined(__ARM_ARCH_6K__) || \
|
||||
defined(__ARM_ARCH_6Z__) || \
|
||||
defined(__ARM_ARCH_6ZK__) || \
|
||||
defined(__ARM_ARCH_6T2__) || \
|
||||
defined(__ARM_ARCH_7__) || \
|
||||
defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__) || \
|
||||
defined(__ARM_ARCH_7M__) || \
|
||||
defined(__ARM_ARCH_7S__) || \
|
||||
defined(__ARM_ARCH_8A__) || \
|
||||
defined(__aarch64__))
|
||||
// http://groups.google.com/a/chromium.org/forum/#!msg/chromium-dev/YGVrZbxYOlU/Vpgy__zeBQAJ
|
||||
// mnemonic 'yield' is supported from ARMv6k onwards
|
||||
# define cpu_relax() asm volatile ("yield" ::: "memory");
|
||||
# else
|
||||
# define cpu_relax() asm volatile ("nop" ::: "memory");
|
||||
# endif
|
||||
#elif BOOST_ARCH_MIPS && (__mips_isa_rev > 1)
|
||||
# define cpu_relax() asm volatile ("pause" ::: "memory");
|
||||
#elif BOOST_ARCH_PPC
|
||||
// http://code.metager.de/source/xref/gnu/glibc/sysdeps/powerpc/sys/platform/ppc.h
|
||||
// http://stackoverflow.com/questions/5425506/equivalent-of-x86-pause-instruction-for-ppc
|
||||
// mnemonic 'or' shared resource hints
|
||||
// or 27, 27, 27 This form of 'or' provides a hint that performance
|
||||
// will probably be imrpoved if shared resources dedicated
|
||||
// to the executing processor are released for use by other
|
||||
// processors
|
||||
// extended mnemonics (available with POWER7)
|
||||
// yield == or 27, 27, 27
|
||||
# define cpu_relax() asm volatile ("or 27,27,27" ::: "memory");
|
||||
#elif BOOST_ARCH_X86
|
||||
# if BOOST_COMP_MSVC || BOOST_COMP_MSVC_EMULATED
|
||||
# define cpu_relax() YieldProcessor();
|
||||
# else
|
||||
# define cpu_relax() asm volatile ("pause" ::: "memory");
|
||||
# endif
|
||||
#else
|
||||
# define cpu_relax() { \
|
||||
static constexpr std::chrono::microseconds us0{ 0 }; \
|
||||
std::this_thread::sleep_for( us0); \
|
||||
}
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_CPU_RELAX_H
|
||||
54
install/boost_1_75_0/include/boost/fiber/detail/data.hpp
Normal file
54
install/boost_1_75_0/include/boost/fiber/detail/data.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_DATA_H
|
||||
#define BOOST_FIBERS_DETAIL_DATA_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/spinlock.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
|
||||
class context;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct data_t {
|
||||
spinlock_lock * lk{ nullptr };
|
||||
context * ctx{ nullptr };
|
||||
context * from;
|
||||
|
||||
explicit data_t( context * from_) noexcept :
|
||||
from{ from_ } {
|
||||
}
|
||||
|
||||
explicit data_t( spinlock_lock * lk_,
|
||||
context * from_) noexcept :
|
||||
lk{ lk_ },
|
||||
from{ from_ } {
|
||||
}
|
||||
|
||||
explicit data_t( context * ctx_,
|
||||
context * from_) noexcept :
|
||||
ctx{ ctx_ },
|
||||
from{ from_ } {
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_DATA_H
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2014.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBER_DETAIL_DECAY_COPY_H
|
||||
#define BOOST_FIBER_DETAIL_DECAY_COPY_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename T >
|
||||
typename std::decay< T >::type
|
||||
decay_copy( T && t) {
|
||||
return std::forward< T >( t);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
#include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBER_DETAIL_DECAY_COPY_H
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2014.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBER_DETAIL_DISABLE_OVERLOAD_H
|
||||
#define BOOST_FIBER_DETAIL_DISABLE_OVERLOAD_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/context/detail/disable_overload.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename X, typename Y >
|
||||
using disable_overload = boost::context::detail::disable_overload< X, Y >;
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
#include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBER_DETAIL_DISABLE_OVERLOAD_H
|
||||
36
install/boost_1_75_0/include/boost/fiber/detail/exchange.hpp
Normal file
36
install/boost_1_75_0/include/boost/fiber/detail/exchange.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2018.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBER_DETAIL_EXCHANGE_H
|
||||
#define BOOST_FIBER_DETAIL_EXCHANGE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename T, typename U = T >
|
||||
T exchange( T & t, U && nv) {
|
||||
T ov = std::move( t);
|
||||
t = std::forward< U >( nv);
|
||||
return ov;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
#include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBER_DETAIL_EXCHANGE_H
|
||||
59
install/boost_1_75_0/include/boost/fiber/detail/fss.hpp
Normal file
59
install/boost_1_75_0/include/boost/fiber/detail/fss.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
//
|
||||
// based on tss.hpp from boost.thread
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_FSS_H
|
||||
#define BOOST_FIBERS_DETAIL_FSS_H
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class fss_cleanup_function {
|
||||
private:
|
||||
std::atomic< std::size_t > use_count_{ 0 };
|
||||
|
||||
public:
|
||||
typedef intrusive_ptr< fss_cleanup_function > ptr_t;
|
||||
|
||||
fss_cleanup_function() noexcept = default;
|
||||
|
||||
virtual ~fss_cleanup_function() = default;
|
||||
|
||||
virtual void operator()( void * data) = 0;
|
||||
|
||||
friend inline
|
||||
void intrusive_ptr_add_ref( fss_cleanup_function * p) noexcept {
|
||||
p->use_count_.fetch_add( 1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
friend inline
|
||||
void intrusive_ptr_release( fss_cleanup_function * p) noexcept {
|
||||
if ( 1 == p->use_count_.fetch_sub( 1, std::memory_order_release) ) {
|
||||
std::atomic_thread_fence( std::memory_order_acquire);
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_FSS_H
|
||||
61
install/boost_1_75_0/include/boost/fiber/detail/futex.hpp
Normal file
61
install/boost_1_75_0/include/boost/fiber/detail/futex.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2016.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_FUTEX_H
|
||||
#define BOOST_FIBERS_DETAIL_FUTEX_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
extern "C" {
|
||||
#include <linux/futex.h>
|
||||
#include <sys/syscall.h>
|
||||
}
|
||||
#elif BOOST_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
BOOST_FORCEINLINE
|
||||
int sys_futex( void * addr, std::int32_t op, std::int32_t x) {
|
||||
return ::syscall( SYS_futex, addr, op, x, nullptr, nullptr, 0);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE
|
||||
int futex_wake( std::atomic< std::int32_t > * addr) {
|
||||
return 0 <= sys_futex( static_cast< void * >( addr), FUTEX_WAKE_PRIVATE, 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE
|
||||
int futex_wait( std::atomic< std::int32_t > * addr, std::int32_t x) {
|
||||
return 0 <= sys_futex( static_cast< void * >( addr), FUTEX_WAIT_PRIVATE, x) ? 0 : -1;
|
||||
}
|
||||
#elif BOOST_OS_WINDOWS
|
||||
BOOST_FORCEINLINE
|
||||
int futex_wake( std::atomic< std::int32_t > * addr) {
|
||||
::WakeByAddressSingle( static_cast< void * >( addr) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE
|
||||
int futex_wait( std::atomic< std::int32_t > * addr, std::int32_t x) {
|
||||
::WaitOnAddress( static_cast< volatile void * >( addr), & x, sizeof( x), INFINITE);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
# warn "no futex support on this platform"
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_FUTEX_H
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2017.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_DETAIL_IS_ALL_SAME_H
|
||||
#define BOOST_FIBERS_DETAIL_IS_ALL_SAME_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename X, typename ... Y >
|
||||
struct is_all_same;
|
||||
|
||||
template< typename X, typename Y0, typename ... Y >
|
||||
struct is_all_same< X, Y0, Y ... > {
|
||||
static constexpr bool value =
|
||||
std::is_same< X, Y0 >::value && is_all_same< X, Y ... >::value;
|
||||
};
|
||||
|
||||
template< typename X, typename Y0 >
|
||||
struct is_all_same< X, Y0 > {
|
||||
static constexpr bool value = std::is_same< X, Y0 >::value;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_DETAIL_IS_ALL_SAME_H
|
||||
94
install/boost_1_75_0/include/boost/fiber/detail/rtm.hpp
Normal file
94
install/boost_1_75_0/include/boost/fiber/detail/rtm.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2017.
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BOOST_FIBER_DETAIL_RTM_H
|
||||
#define BOOST_FIBER_DETAIL_RTM_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
struct rtm_status {
|
||||
enum {
|
||||
none = 0,
|
||||
explicit_abort = 1 << 0,
|
||||
may_retry = 1 << 1,
|
||||
memory_conflict = 1 << 2,
|
||||
buffer_overflow = 1 << 3,
|
||||
debug_hit = 1 << 4,
|
||||
nested_abort = 1 << 5
|
||||
};
|
||||
|
||||
static constexpr std::uint32_t success = ~std::uint32_t{ 0 };
|
||||
};
|
||||
|
||||
static BOOST_FORCEINLINE
|
||||
std::uint32_t rtm_begin() noexcept {
|
||||
std::uint32_t result = rtm_status::success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
".byte 0xc7,0xf8 ; .long 0"
|
||||
: "+a" (result)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE
|
||||
void rtm_end() noexcept {
|
||||
__asm__ __volatile__
|
||||
(
|
||||
".byte 0x0f,0x01,0xd5"
|
||||
:
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE
|
||||
void rtm_abort_lock_not_free() noexcept {
|
||||
__asm__ __volatile__
|
||||
(
|
||||
".byte 0xc6,0xf8,0xff"
|
||||
:
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static BOOST_FORCEINLINE
|
||||
bool rtm_test() noexcept {
|
||||
bool result;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
".byte 0x0f,0x01,0xd6; setz %0"
|
||||
: "=q" (result)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBER_DETAIL_RTM_H
|
||||
84
install/boost_1_75_0/include/boost/fiber/detail/spinlock.hpp
Normal file
84
install/boost_1_75_0/include/boost/fiber/detail/spinlock.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_SPINLOCK_H
|
||||
#define BOOST_FIBERS_SPINLOCK_H
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#if !defined(BOOST_FIBERS_NO_ATOMICS)
|
||||
# include <mutex>
|
||||
# include <boost/fiber/detail/spinlock_ttas_adaptive.hpp>
|
||||
# include <boost/fiber/detail/spinlock_ttas.hpp>
|
||||
# if defined(BOOST_FIBERS_HAS_FUTEX)
|
||||
# include <boost/fiber/detail/spinlock_ttas_adaptive_futex.hpp>
|
||||
# include <boost/fiber/detail/spinlock_ttas_futex.hpp>
|
||||
# endif
|
||||
# if defined(BOOST_USE_TSX)
|
||||
# include <boost/fiber/detail/spinlock_rtm.hpp>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_FIBERS_NO_ATOMICS)
|
||||
struct spinlock {
|
||||
constexpr spinlock() noexcept {}
|
||||
void lock() noexcept {}
|
||||
void unlock() noexcept {}
|
||||
};
|
||||
|
||||
struct spinlock_lock {
|
||||
constexpr spinlock_lock( spinlock &) noexcept {}
|
||||
void lock() noexcept {}
|
||||
void unlock() noexcept {}
|
||||
};
|
||||
#else
|
||||
# if defined(BOOST_FIBERS_SPINLOCK_STD_MUTEX)
|
||||
using spinlock = std::mutex;
|
||||
# elif defined(BOOST_FIBERS_SPINLOCK_TTAS_FUTEX)
|
||||
# if defined(BOOST_USE_TSX)
|
||||
using spinlock = spinlock_rtm< spinlock_ttas_futex >;
|
||||
# else
|
||||
using spinlock = spinlock_ttas_futex;
|
||||
# endif
|
||||
# elif defined(BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX)
|
||||
# if defined(BOOST_USE_TSX)
|
||||
using spinlock = spinlock_rtm< spinlock_ttas_adaptive_futex >;
|
||||
# else
|
||||
using spinlock = spinlock_ttas_adaptive_futex;
|
||||
# endif
|
||||
# elif defined(BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE)
|
||||
# if defined(BOOST_USE_TSX)
|
||||
using spinlock = spinlock_rtm< spinlock_ttas_adaptive >;
|
||||
# else
|
||||
using spinlock = spinlock_ttas_adaptive;
|
||||
# endif
|
||||
# else
|
||||
# if defined(BOOST_USE_TSX)
|
||||
using spinlock = spinlock_rtm< spinlock_ttas >;
|
||||
# else
|
||||
using spinlock = spinlock_ttas;
|
||||
# endif
|
||||
# endif
|
||||
using spinlock_lock = std::unique_lock< spinlock >;
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_SUFFIX
|
||||
#endif
|
||||
|
||||
#endif // BOOST_FIBERS_SPINLOCK_H
|
||||
127
install/boost_1_75_0/include/boost/fiber/detail/spinlock_rtm.hpp
Normal file
127
install/boost_1_75_0/include/boost/fiber/detail/spinlock_rtm.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2017.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_SPINLOCK_RTM_H
|
||||
#define BOOST_FIBERS_SPINLOCK_RTM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/cpu_relax.hpp>
|
||||
#include <boost/fiber/detail/rtm.hpp>
|
||||
#include <boost/fiber/detail/spinlock_status.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
template< typename FBSplk >
|
||||
class spinlock_rtm {
|
||||
private:
|
||||
FBSplk splk_{};
|
||||
|
||||
public:
|
||||
spinlock_rtm() = default;
|
||||
|
||||
spinlock_rtm( spinlock_rtm const&) = delete;
|
||||
spinlock_rtm & operator=( spinlock_rtm const&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
static thread_local std::minstd_rand generator{ std::random_device{}() };
|
||||
std::size_t collisions = 0 ;
|
||||
for ( std::size_t retries = 0; retries < BOOST_FIBERS_RETRY_THRESHOLD; ++retries) {
|
||||
std::uint32_t status;
|
||||
if ( rtm_status::success == ( status = rtm_begin() ) ) {
|
||||
// add lock to read-set
|
||||
if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_relaxed) ) {
|
||||
// lock is free, enter critical section
|
||||
return;
|
||||
}
|
||||
// lock was acquired by another thread
|
||||
// explicit abort of transaction with abort argument 'lock not free'
|
||||
rtm_abort_lock_not_free();
|
||||
}
|
||||
// transaction aborted
|
||||
if ( rtm_status::none != (status & rtm_status::may_retry) ||
|
||||
rtm_status::none != (status & rtm_status::memory_conflict) ) {
|
||||
// another logical processor conflicted with a memory address that was
|
||||
// part or the read-/write-set
|
||||
if ( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD > collisions) {
|
||||
std::uniform_int_distribution< std::size_t > distribution{
|
||||
0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
|
||||
const std::size_t z = distribution( generator);
|
||||
++collisions;
|
||||
for ( std::size_t i = 0; i < z; ++i) {
|
||||
cpu_relax();
|
||||
}
|
||||
} else {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
} else if ( rtm_status::none != (status & rtm_status::explicit_abort) &&
|
||||
rtm_status::none == (status & rtm_status::nested_abort) ) {
|
||||
// another logical processor has acquired the lock and
|
||||
// abort was not caused by a nested transaction
|
||||
// wait till lock becomes free again
|
||||
std::size_t count = 0;
|
||||
while ( spinlock_status::locked == splk_.state_.load( std::memory_order_relaxed) ) {
|
||||
if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > count) {
|
||||
++count;
|
||||
cpu_relax();
|
||||
} else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > count) {
|
||||
++count;
|
||||
static constexpr std::chrono::microseconds us0{ 0 };
|
||||
std::this_thread::sleep_for( us0);
|
||||
#if 0
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for( 0ms);
|
||||
#endif
|
||||
} else {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// transaction aborted due:
|
||||
// - internal buffer to track transactional state overflowed
|
||||
// - debug exception or breakpoint exception was hit
|
||||
// - abort during execution of nested transactions (max nesting limit exceeded)
|
||||
// -> use fallback path
|
||||
break;
|
||||
}
|
||||
}
|
||||
splk_.lock();
|
||||
}
|
||||
|
||||
bool try_lock() noexcept {
|
||||
if ( rtm_status::success != rtm_begin() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add lock to read-set
|
||||
if ( spinlock_status::unlocked != splk_.state_.load( std::memory_order_relaxed) ) {
|
||||
// lock was acquired by another thread
|
||||
// explicit abort of transaction with abort argument 'lock not free'
|
||||
rtm_abort_lock_not_free();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
if ( spinlock_status::unlocked == splk_.state_.load( std::memory_order_acquire) ) {
|
||||
rtm_end();
|
||||
} else {
|
||||
splk_.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_SPINLOCK_RTM_H
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2017.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_SPINLOCK_STATUS_H
|
||||
#define BOOST_FIBERS_SPINLOCK_STATUS_H
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
enum class spinlock_status {
|
||||
locked = 0,
|
||||
unlocked
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_SPINLOCK_STATUS_H
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2016.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_SPINLOCK_TTAS_H
|
||||
#define BOOST_FIBERS_SPINLOCK_TTAS_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/cpu_relax.hpp>
|
||||
#include <boost/fiber/detail/spinlock_status.hpp>
|
||||
|
||||
// based on informations from:
|
||||
// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
|
||||
// https://software.intel.com/en-us/articles/long-duration-spin-wait-loops-on-hyper-threading-technology-enabled-intel-processors
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class spinlock_ttas {
|
||||
private:
|
||||
template< typename FBSplk >
|
||||
friend class spinlock_rtm;
|
||||
|
||||
std::atomic< spinlock_status > state_{ spinlock_status::unlocked };
|
||||
|
||||
public:
|
||||
spinlock_ttas() = default;
|
||||
|
||||
spinlock_ttas( spinlock_ttas const&) = delete;
|
||||
spinlock_ttas & operator=( spinlock_ttas const&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
static thread_local std::minstd_rand generator{ std::random_device{}() };
|
||||
std::size_t collisions = 0 ;
|
||||
for (;;) {
|
||||
// avoid using multiple pause instructions for a delay of a specific cycle count
|
||||
// the delay of cpu_relax() (pause on Intel) depends on the processor family
|
||||
// the cycle count can not guaranteed from one system to the next
|
||||
// -> check the shared variable 'state_' in between each cpu_relax() to prevent
|
||||
// unnecessarily long delays on some systems
|
||||
std::size_t retries = 0;
|
||||
// test shared variable 'status_'
|
||||
// first access to 'state_' -> chache miss
|
||||
// sucessive acccess to 'state_' -> cache hit
|
||||
// if 'state_' was released by other fiber
|
||||
// cached 'state_' is invalidated -> cache miss
|
||||
while ( spinlock_status::locked == state_.load( std::memory_order_relaxed) ) {
|
||||
#if !defined(BOOST_FIBERS_SPIN_SINGLE_CORE)
|
||||
if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > retries) {
|
||||
++retries;
|
||||
// give CPU a hint that this thread is in a "spin-wait" loop
|
||||
// delays the next instruction's execution for a finite period of time (depends on processor family)
|
||||
// the CPU is not under demand, parts of the pipeline are no longer being used
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
} else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > retries) {
|
||||
++retries;
|
||||
// std::this_thread::sleep_for( 0us) has a fairly long instruction path length,
|
||||
// combined with an expensive ring3 to ring 0 transition costing about 1000 cycles
|
||||
// std::this_thread::sleep_for( 0us) lets give up this_thread the remaining part of its time slice
|
||||
// if and only if a thread of equal or greater priority is ready to run
|
||||
static constexpr std::chrono::microseconds us0{ 0 };
|
||||
std::this_thread::sleep_for( us0);
|
||||
} else {
|
||||
// std::this_thread::yield() allows this_thread to give up the remaining part of its time slice,
|
||||
// but only to another thread on the same processor
|
||||
// instead of constant checking, a thread only checks if no other useful work is pending
|
||||
std::this_thread::yield();
|
||||
}
|
||||
#else
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
// test-and-set shared variable 'status_'
|
||||
// everytime 'status_' is signaled over the bus, even if the test failes
|
||||
if ( spinlock_status::locked == state_.exchange( spinlock_status::locked, std::memory_order_acquire) ) {
|
||||
// spinlock now contended
|
||||
// utilize 'Binary Exponential Backoff' algorithm
|
||||
// linear_congruential_engine is a random number engine based on Linear congruential generator (LCG)
|
||||
std::uniform_int_distribution< std::size_t > distribution{
|
||||
0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
|
||||
const std::size_t z = distribution( generator);
|
||||
++collisions;
|
||||
for ( std::size_t i = 0; i < z; ++i) {
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
}
|
||||
} else {
|
||||
// success, thread has acquired the lock
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock() noexcept {
|
||||
return spinlock_status::unlocked == state_.exchange( spinlock_status::locked, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
state_.store( spinlock_status::unlocked, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_SPINLOCK_TTAS_H
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2016.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_H
|
||||
#define BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/cpu_relax.hpp>
|
||||
#include <boost/fiber/detail/spinlock_status.hpp>
|
||||
|
||||
// based on informations from:
|
||||
// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
|
||||
// https://software.intel.com/en-us/articles/long-duration-spin-wait-loops-on-hyper-threading-technology-enabled-intel-processors
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class spinlock_ttas_adaptive {
|
||||
private:
|
||||
template< typename FBSplk >
|
||||
friend class spinlock_rtm;
|
||||
|
||||
std::atomic< spinlock_status > state_{ spinlock_status::unlocked };
|
||||
std::atomic< std::size_t > retries_{ 0 };
|
||||
|
||||
public:
|
||||
spinlock_ttas_adaptive() = default;
|
||||
|
||||
spinlock_ttas_adaptive( spinlock_ttas_adaptive const&) = delete;
|
||||
spinlock_ttas_adaptive & operator=( spinlock_ttas_adaptive const&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
static thread_local std::minstd_rand generator{ std::random_device{}() };
|
||||
std::size_t collisions = 0 ;
|
||||
for (;;) {
|
||||
std::size_t retries = 0;
|
||||
const std::size_t prev_retries = retries_.load( std::memory_order_relaxed);
|
||||
const std::size_t max_relax_retries = (std::min)(
|
||||
static_cast< std::size_t >( BOOST_FIBERS_SPIN_BEFORE_SLEEP0), 2 * prev_retries + 10);
|
||||
const std::size_t max_sleep_retries = (std::min)(
|
||||
static_cast< std::size_t >( BOOST_FIBERS_SPIN_BEFORE_YIELD), 2 * prev_retries + 10);
|
||||
// avoid using multiple pause instructions for a delay of a specific cycle count
|
||||
// the delay of cpu_relax() (pause on Intel) depends on the processor family
|
||||
// the cycle count can not guaranteed from one system to the next
|
||||
// -> check the shared variable 'state_' in between each cpu_relax() to prevent
|
||||
// unnecessarily long delays on some systems
|
||||
// test shared variable 'status_'
|
||||
// first access to 'state_' -> chache miss
|
||||
// sucessive acccess to 'state_' -> cache hit
|
||||
// if 'state_' was released by other fiber
|
||||
// cached 'state_' is invalidated -> cache miss
|
||||
while ( spinlock_status::locked == state_.load( std::memory_order_relaxed) ) {
|
||||
#if !defined(BOOST_FIBERS_SPIN_SINGLE_CORE)
|
||||
if ( max_relax_retries > retries) {
|
||||
++retries;
|
||||
// give CPU a hint that this thread is in a "spin-wait" loop
|
||||
// delays the next instruction's execution for a finite period of time (depends on processor family)
|
||||
// the CPU is not under demand, parts of the pipeline are no longer being used
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
} else if ( max_sleep_retries > retries) {
|
||||
++retries;
|
||||
// std::this_thread::sleep_for( 0us) has a fairly long instruction path length,
|
||||
// combined with an expensive ring3 to ring 0 transition costing about 1000 cycles
|
||||
// std::this_thread::sleep_for( 0us) lets give up this_thread the remaining part of its time slice
|
||||
// if and only if a thread of equal or greater priority is ready to run
|
||||
static constexpr std::chrono::microseconds us0{ 0 };
|
||||
std::this_thread::sleep_for( us0);
|
||||
} else {
|
||||
// std::this_thread::yield() allows this_thread to give up the remaining part of its time slice,
|
||||
// but only to another thread on the same processor
|
||||
// instead of constant checking, a thread only checks if no other useful work is pending
|
||||
std::this_thread::yield();
|
||||
}
|
||||
#else
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
// test-and-set shared variable 'status_'
|
||||
// everytime 'status_' is signaled over the bus, even if the test failes
|
||||
if ( spinlock_status::locked == state_.exchange( spinlock_status::locked, std::memory_order_acquire) ) {
|
||||
// spinlock now contended
|
||||
// utilize 'Binary Exponential Backoff' algorithm
|
||||
// linear_congruential_engine is a random number engine based on Linear congruential generator (LCG)
|
||||
std::uniform_int_distribution< std::size_t > distribution{
|
||||
0, static_cast< std::size_t >( 1) << (std::min)(collisions, static_cast< std::size_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
|
||||
const std::size_t z = distribution( generator);
|
||||
++collisions;
|
||||
for ( std::size_t i = 0; i < z; ++i) {
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
}
|
||||
} else {
|
||||
retries_.store( prev_retries + (retries - prev_retries) / 8, std::memory_order_relaxed);
|
||||
// success, thread has acquired the lock
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock() noexcept {
|
||||
return spinlock_status::unlocked == state_.exchange( spinlock_status::locked, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
state_.store( spinlock_status::unlocked, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_H
|
||||
@@ -0,0 +1,137 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2016.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX_H
|
||||
#define BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/cpu_relax.hpp>
|
||||
#include <boost/fiber/detail/futex.hpp>
|
||||
|
||||
// based on informations from:
|
||||
// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
|
||||
// https://software.intel.com/en-us/articles/long-duration-spin-wait-loops-on-hyper-threading-technology-enabled-intel-processors
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class spinlock_ttas_adaptive_futex {
|
||||
private:
|
||||
template< typename FBSplk >
|
||||
friend class spinlock_rtm;
|
||||
|
||||
std::atomic< std::int32_t > value_{ 0 };
|
||||
std::atomic< std::int32_t > retries_{ 0 };
|
||||
|
||||
public:
|
||||
spinlock_ttas_adaptive_futex() = default;
|
||||
|
||||
spinlock_ttas_adaptive_futex( spinlock_ttas_adaptive_futex const&) = delete;
|
||||
spinlock_ttas_adaptive_futex & operator=( spinlock_ttas_adaptive_futex const&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
static thread_local std::minstd_rand generator{ std::random_device{}() };
|
||||
std::int32_t collisions = 0, retries = 0, expected = 0;
|
||||
const std::int32_t prev_retries = retries_.load( std::memory_order_relaxed);
|
||||
const std::int32_t max_relax_retries = (std::min)(
|
||||
static_cast< std::int32_t >( BOOST_FIBERS_SPIN_BEFORE_SLEEP0), 2 * prev_retries + 10);
|
||||
const std::int32_t max_sleep_retries = (std::min)(
|
||||
static_cast< std::int32_t >( BOOST_FIBERS_SPIN_BEFORE_YIELD), 2 * prev_retries + 10);
|
||||
// after max. spins or collisions suspend via futex
|
||||
while ( retries++ < BOOST_FIBERS_RETRY_THRESHOLD) {
|
||||
// avoid using multiple pause instructions for a delay of a specific cycle count
|
||||
// the delay of cpu_relax() (pause on Intel) depends on the processor family
|
||||
// the cycle count can not guaranteed from one system to the next
|
||||
// -> check the shared variable 'value_' in between each cpu_relax() to prevent
|
||||
// unnecessarily long delays on some systems
|
||||
// test shared variable 'status_'
|
||||
// first access to 'value_' -> chache miss
|
||||
// sucessive acccess to 'value_' -> cache hit
|
||||
// if 'value_' was released by other fiber
|
||||
// cached 'value_' is invalidated -> cache miss
|
||||
if ( 0 != ( expected = value_.load( std::memory_order_relaxed) ) ) {
|
||||
#if !defined(BOOST_FIBERS_SPIN_SINGLE_CORE)
|
||||
if ( max_relax_retries > retries) {
|
||||
// give CPU a hint that this thread is in a "spin-wait" loop
|
||||
// delays the next instruction's execution for a finite period of time (depends on processor family)
|
||||
// the CPU is not under demand, parts of the pipeline are no longer being used
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
} else if ( max_sleep_retries > retries) {
|
||||
// std::this_thread::sleep_for( 0us) has a fairly long instruction path length,
|
||||
// combined with an expensive ring3 to ring 0 transition costing about 1000 cycles
|
||||
// std::this_thread::sleep_for( 0us) lets give up this_thread the remaining part of its time slice
|
||||
// if and only if a thread of equal or greater priority is ready to run
|
||||
static constexpr std::chrono::microseconds us0{ 0 };
|
||||
std::this_thread::sleep_for( us0);
|
||||
} else {
|
||||
// std::this_thread::yield() allows this_thread to give up the remaining part of its time slice,
|
||||
// but only to another thread on the same processor
|
||||
// instead of constant checking, a thread only checks if no other useful work is pending
|
||||
std::this_thread::yield();
|
||||
}
|
||||
#else
|
||||
// std::this_thread::yield() allows this_thread to give up the remaining part of its time slice,
|
||||
// but only to another thread on the same processor
|
||||
// instead of constant checking, a thread only checks if no other useful work is pending
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
} else if ( ! value_.compare_exchange_strong( expected, 1, std::memory_order_acquire) ) {
|
||||
// spinlock now contended
|
||||
// utilize 'Binary Exponential Backoff' algorithm
|
||||
// linear_congruential_engine is a random number engine based on Linear congruential generator (LCG)
|
||||
std::uniform_int_distribution< std::int32_t > distribution{
|
||||
0, static_cast< std::int32_t >( 1) << (std::min)(collisions, static_cast< std::int32_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
|
||||
const std::int32_t z = distribution( generator);
|
||||
++collisions;
|
||||
for ( std::int32_t i = 0; i < z; ++i) {
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
}
|
||||
} else {
|
||||
// success, lock acquired
|
||||
retries_.store( prev_retries + (retries - prev_retries) / 8, std::memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// failure, lock not acquired
|
||||
// pause via futex
|
||||
if ( 2 != expected) {
|
||||
expected = value_.exchange( 2, std::memory_order_acquire);
|
||||
}
|
||||
while ( 0 != expected) {
|
||||
futex_wait( & value_, 2);
|
||||
expected = value_.exchange( 2, std::memory_order_acquire);
|
||||
}
|
||||
// success, lock acquired
|
||||
retries_.store( prev_retries + (retries - prev_retries) / 8, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool try_lock() noexcept {
|
||||
std::int32_t expected = 0;
|
||||
return value_.compare_exchange_strong( expected, 1, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
if ( 1 != value_.fetch_sub( 1, std::memory_order_acquire) ) {
|
||||
value_.store( 0, std::memory_order_release);
|
||||
futex_wake( & value_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_SPINLOCK_TTAS_ADAPTIVE_FUTEX_H
|
||||
@@ -0,0 +1,128 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2016.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBERS_spinlock_ttas_futex_FUTEX_H
|
||||
#define BOOST_FIBERS_spinlock_ttas_futex_FUTEX_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
#include <boost/fiber/detail/cpu_relax.hpp>
|
||||
#include <boost/fiber/detail/futex.hpp>
|
||||
|
||||
// based on informations from:
|
||||
// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
|
||||
// https://software.intel.com/en-us/articles/long-duration-spin-wait-loops-on-hyper-threading-technology-enabled-intel-processors
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class spinlock_ttas_futex {
|
||||
private:
|
||||
template< typename FBSplk >
|
||||
friend class spinlock_rtm;
|
||||
|
||||
std::atomic< std::int32_t > value_{ 0 };
|
||||
|
||||
public:
|
||||
spinlock_ttas_futex() = default;
|
||||
|
||||
spinlock_ttas_futex( spinlock_ttas_futex const&) = delete;
|
||||
spinlock_ttas_futex & operator=( spinlock_ttas_futex const&) = delete;
|
||||
|
||||
void lock() noexcept {
|
||||
static thread_local std::minstd_rand generator{ std::random_device{}() };
|
||||
std::int32_t collisions = 0, retries = 0, expected = 0;
|
||||
// after max. spins or collisions suspend via futex
|
||||
while ( retries++ < BOOST_FIBERS_RETRY_THRESHOLD) {
|
||||
// avoid using multiple pause instructions for a delay of a specific cycle count
|
||||
// the delay of cpu_relax() (pause on Intel) depends on the processor family
|
||||
// the cycle count can not guaranteed from one system to the next
|
||||
// -> check the shared variable 'value_' in between each cpu_relax() to prevent
|
||||
// unnecessarily long delays on some systems
|
||||
// test shared variable 'status_'
|
||||
// first access to 'value_' -> chache miss
|
||||
// sucessive acccess to 'value_' -> cache hit
|
||||
// if 'value_' was released by other fiber
|
||||
// cached 'value_' is invalidated -> cache miss
|
||||
if ( 0 != ( expected = value_.load( std::memory_order_relaxed) ) ) {
|
||||
#if !defined(BOOST_FIBERS_SPIN_SINGLE_CORE)
|
||||
if ( BOOST_FIBERS_SPIN_BEFORE_SLEEP0 > retries) {
|
||||
// give CPU a hint that this thread is in a "spin-wait" loop
|
||||
// delays the next instruction's execution for a finite period of time (depends on processor family)
|
||||
// the CPU is not under demand, parts of the pipeline are no longer being used
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
} else if ( BOOST_FIBERS_SPIN_BEFORE_YIELD > retries) {
|
||||
// std::this_thread::sleep_for( 0us) has a fairly long instruction path length,
|
||||
// combined with an expensive ring3 to ring 0 transition costing about 1000 cycles
|
||||
// std::this_thread::sleep_for( 0us) lets give up this_thread the remaining part of its time slice
|
||||
// if and only if a thread of equal or greater priority is ready to run
|
||||
static constexpr std::chrono::microseconds us0{ 0 };
|
||||
std::this_thread::sleep_for( us0);
|
||||
} else {
|
||||
// std::this_thread::yield() allows this_thread to give up the remaining part of its time slice,
|
||||
// but only to another thread on the same processor
|
||||
// instead of constant checking, a thread only checks if no other useful work is pending
|
||||
std::this_thread::yield();
|
||||
}
|
||||
#else
|
||||
// std::this_thread::yield() allows this_thread to give up the remaining part of its time slice,
|
||||
// but only to another thread on the same processor
|
||||
// instead of constant checking, a thread only checks if no other useful work is pending
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
} else if ( ! value_.compare_exchange_strong( expected, 1, std::memory_order_acquire) ) {
|
||||
// spinlock now contended
|
||||
// utilize 'Binary Exponential Backoff' algorithm
|
||||
// linear_congruential_engine is a random number engine based on Linear congruential generator (LCG)
|
||||
std::uniform_int_distribution< std::int32_t > distribution{
|
||||
0, static_cast< std::int32_t >( 1) << (std::min)(collisions, static_cast< std::int32_t >( BOOST_FIBERS_CONTENTION_WINDOW_THRESHOLD)) };
|
||||
const std::int32_t z = distribution( generator);
|
||||
++collisions;
|
||||
for ( std::int32_t i = 0; i < z; ++i) {
|
||||
// -> reduces the power consumed by the CPU
|
||||
// -> prevent pipeline stalls
|
||||
cpu_relax();
|
||||
}
|
||||
} else {
|
||||
// success, lock acquired
|
||||
return;
|
||||
}
|
||||
}
|
||||
// failure, lock not acquired
|
||||
// pause via futex
|
||||
if ( 2 != expected) {
|
||||
expected = value_.exchange( 2, std::memory_order_acquire);
|
||||
}
|
||||
while ( 0 != expected) {
|
||||
futex_wait( & value_, 2);
|
||||
expected = value_.exchange( 2, std::memory_order_acquire);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock() noexcept {
|
||||
std::int32_t expected = 0;
|
||||
return value_.compare_exchange_strong( expected, 1, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void unlock() noexcept {
|
||||
if ( 1 != value_.fetch_sub( 1, std::memory_order_acquire) ) {
|
||||
value_.store( 0, std::memory_order_release);
|
||||
futex_wake( & value_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBERS_spinlock_ttas_futex_FUTEX_H
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
// Copyright Oliver Kowalke 2013.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_FIBER_DETAIL_THREAD_BARRIER_H
|
||||
#define BOOST_FIBER_DETAIL_THREAD_BARRIER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/fiber/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_ABI_HEADERS
|
||||
# include BOOST_ABI_PREFIX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace fibers {
|
||||
namespace detail {
|
||||
|
||||
class thread_barrier {
|
||||
private:
|
||||
std::size_t initial_;
|
||||
std::size_t current_;
|
||||
bool cycle_{ true };
|
||||
std::mutex mtx_{};
|
||||
std::condition_variable cond_{};
|
||||
|
||||
public:
|
||||
explicit thread_barrier( std::size_t initial) :
|
||||
initial_{ initial },
|
||||
current_{ initial_ } {
|
||||
BOOST_ASSERT ( 0 != initial);
|
||||
}
|
||||
|
||||
thread_barrier( thread_barrier const&) = delete;
|
||||
thread_barrier & operator=( thread_barrier const&) = delete;
|
||||
|
||||
bool wait() {
|
||||
std::unique_lock< std::mutex > lk( mtx_);
|
||||
const bool cycle = cycle_;
|
||||
if ( 0 == --current_) {
|
||||
cycle_ = ! cycle_;
|
||||
current_ = initial_;
|
||||
lk.unlock(); // no pessimization
|
||||
cond_.notify_all();
|
||||
return true;
|
||||
}
|
||||
cond_.wait( lk, [&](){ return cycle != cycle_; });
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // BOOST_FIBER_DETAIL_THREAD_BARRIER_H
|
||||
Reference in New Issue
Block a user