Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/interprocess/sync/spin/wait.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/interprocess/sync/spin/wait.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,181 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Peter Dimov 2008. +// (C) Copyright Ion Gaztanaga 2013-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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//Parts of this file come from boost/smart_ptr/detail/yield_k.hpp +//Many thanks to Peter Dimov. + +#ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED +#define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include <boost/interprocess/detail/config_begin.hpp> +#include <boost/interprocess/detail/workaround.hpp> +#include <boost/interprocess/detail/os_thread_functions.hpp> + +//#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG +#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG +#include <iostream> +#endif + +// BOOST_INTERPROCESS_SMT_PAUSE + +#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_IX86) || defined(_M_X64) ) + +extern "C" void _mm_pause(); +#pragma intrinsic( _mm_pause ) + +#define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + +#define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); + +#endif + +namespace boost{ +namespace interprocess{ +namespace ipcdetail { + +template<int Dummy = 0> +class num_core_holder +{ + public: + static unsigned int get() + { + if(!num_cores){ + return ipcdetail::get_num_cores(); + } + else{ + return num_cores; + } + } + + private: + static unsigned int num_cores; +}; + +template<int Dummy> +unsigned int num_core_holder<Dummy>::num_cores = ipcdetail::get_num_cores(); + +} //namespace ipcdetail { + +class spin_wait +{ + public: + + static const unsigned int nop_pause_limit = 32u; + spin_wait() + : m_count_start(), m_ul_yield_only_counts(), m_k() + {} + + #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG + ~spin_wait() + { + if(m_k){ + std::cout << "final m_k: " << m_k + << " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl; + } + } + #endif + + unsigned int count() const + { return m_k; } + + void yield() + { + //Lazy initialization of limits + if( !m_k){ + this->init_limits(); + } + //Nop tries + if( m_k < (nop_pause_limit >> 2) ){ + + } + //Pause tries if the processor supports it + #if defined(BOOST_INTERPROCESS_SMT_PAUSE) + else if( m_k < nop_pause_limit ){ + BOOST_INTERPROCESS_SMT_PAUSE + } + #endif + //Yield/Sleep strategy + else{ + //Lazy initialization of tick information + if(m_k == nop_pause_limit){ + this->init_tick_info(); + } + else if( this->yield_or_sleep() ){ + ipcdetail::thread_yield(); + } + else{ + ipcdetail::thread_sleep_tick(); + } + } + ++m_k; + } + + void reset() + { + m_k = 0u; + } + + private: + + void init_limits() + { + unsigned int num_cores = ipcdetail::num_core_holder<0>::get(); + m_k = num_cores > 1u ? 0u : nop_pause_limit; + } + + void init_tick_info() + { + m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts(); + m_count_start = ipcdetail::get_current_system_highres_count(); + } + + //Returns true if yield must be called, false is sleep must be called + bool yield_or_sleep() + { + if(!m_ul_yield_only_counts){ //If yield-only limit was reached then yield one in every two tries + return (m_k & 1u) != 0; + } + else{ //Try to see if we've reched yield-only time limit + const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count(); + const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start); + if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){ + #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG + std::cout << "elapsed!\n" + << " m_ul_yield_only_counts: " << m_ul_yield_only_counts + << " system tick(us): " << ipcdetail::get_system_tick_us() << '\n' + << " m_k: " << m_k << " elapsed counts: "; + ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl; + #endif + //Yield-only time reached, now it's time to sleep + m_ul_yield_only_counts = 0ul; + return false; + } + } + return true; //Otherwise yield + } + + ipcdetail::OS_highres_count_t m_count_start; + unsigned long m_ul_yield_only_counts; + unsigned int m_k; +}; + +} // namespace interprocess +} // namespace boost + +#include <boost/interprocess/detail/config_end.hpp> + +#endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED