Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // (C) Copyright Peter Dimov 2008. Chris@16: // (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/interprocess for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: //Parts of this file come from boost/smart_ptr/detail/yield_k.hpp Chris@16: //Many thanks to Peter Dimov. Chris@16: Chris@16: #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED Chris@16: #define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: # Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: //#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG Chris@16: #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG Chris@16: #include Chris@16: #endif Chris@16: Chris@16: // BOOST_INTERPROCESS_SMT_PAUSE Chris@16: Chris@101: #if defined(_MSC_VER) && ( defined(_M_IX86) || defined(_M_X64) ) Chris@16: Chris@16: extern "C" void _mm_pause(); Chris@16: #pragma intrinsic( _mm_pause ) Chris@16: Chris@16: #define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause(); Chris@16: Chris@101: #elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) && !defined(_CRAYC) Chris@16: Chris@16: #define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); Chris@16: Chris@16: #endif Chris@16: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: namespace ipcdetail { Chris@16: Chris@16: template Chris@16: class num_core_holder Chris@16: { Chris@16: public: Chris@16: static unsigned int get() Chris@16: { Chris@16: if(!num_cores){ Chris@16: return ipcdetail::get_num_cores(); Chris@16: } Chris@16: else{ Chris@16: return num_cores; Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: static unsigned int num_cores; Chris@16: }; Chris@16: Chris@16: template Chris@16: unsigned int num_core_holder::num_cores = ipcdetail::get_num_cores(); Chris@16: Chris@16: } //namespace ipcdetail { Chris@16: Chris@16: class spin_wait Chris@16: { Chris@16: public: Chris@16: Chris@16: static const unsigned int nop_pause_limit = 32u; Chris@16: spin_wait() Chris@16: : m_count_start(), m_ul_yield_only_counts(), m_k() Chris@16: {} Chris@16: Chris@16: #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG Chris@16: ~spin_wait() Chris@16: { Chris@16: if(m_k){ Chris@16: std::cout << "final m_k: " << m_k Chris@16: << " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl; Chris@16: } Chris@16: } Chris@16: #endif Chris@16: Chris@16: unsigned int count() const Chris@16: { return m_k; } Chris@16: Chris@16: void yield() Chris@16: { Chris@16: //Lazy initialization of limits Chris@16: if( !m_k){ Chris@16: this->init_limits(); Chris@16: } Chris@16: //Nop tries Chris@16: if( m_k < (nop_pause_limit >> 2) ){ Chris@16: Chris@16: } Chris@16: //Pause tries if the processor supports it Chris@16: #if defined(BOOST_INTERPROCESS_SMT_PAUSE) Chris@16: else if( m_k < nop_pause_limit ){ Chris@16: BOOST_INTERPROCESS_SMT_PAUSE Chris@16: } Chris@16: #endif Chris@16: //Yield/Sleep strategy Chris@16: else{ Chris@16: //Lazy initialization of tick information Chris@16: if(m_k == nop_pause_limit){ Chris@16: this->init_tick_info(); Chris@16: } Chris@16: else if( this->yield_or_sleep() ){ Chris@16: ipcdetail::thread_yield(); Chris@16: } Chris@16: else{ Chris@16: ipcdetail::thread_sleep_tick(); Chris@16: } Chris@16: } Chris@16: ++m_k; Chris@16: } Chris@16: Chris@16: void reset() Chris@16: { Chris@16: m_k = 0u; Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: void init_limits() Chris@16: { Chris@16: unsigned int num_cores = ipcdetail::num_core_holder<0>::get(); Chris@16: m_k = num_cores > 1u ? 0u : nop_pause_limit; Chris@16: } Chris@16: Chris@16: void init_tick_info() Chris@16: { Chris@16: m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts(); Chris@16: m_count_start = ipcdetail::get_current_system_highres_count(); Chris@16: } Chris@16: Chris@16: //Returns true if yield must be called, false is sleep must be called Chris@16: bool yield_or_sleep() Chris@16: { Chris@16: if(!m_ul_yield_only_counts){ //If yield-only limit was reached then yield one in every two tries Chris@16: return (m_k & 1u) != 0; Chris@16: } Chris@16: else{ //Try to see if we've reched yield-only time limit Chris@16: const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count(); Chris@16: const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start); Chris@16: if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){ Chris@16: #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG Chris@16: std::cout << "elapsed!\n" Chris@16: << " m_ul_yield_only_counts: " << m_ul_yield_only_counts Chris@16: << " system tick(us): " << ipcdetail::get_system_tick_us() << '\n' Chris@16: << " m_k: " << m_k << " elapsed counts: "; Chris@16: ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl; Chris@16: #endif Chris@16: //Yield-only time reached, now it's time to sleep Chris@16: m_ul_yield_only_counts = 0ul; Chris@16: return false; Chris@16: } Chris@16: } Chris@16: return true; //Otherwise yield Chris@16: } Chris@16: Chris@16: ipcdetail::OS_highres_count_t m_count_start; Chris@16: unsigned long m_ul_yield_only_counts; Chris@16: unsigned int m_k; Chris@16: }; Chris@16: Chris@16: } // namespace interprocess Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED