Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:32

0001 //////////////////////////////////////////////////////////////////////////////
0002 //
0003 // (C) Copyright Peter Dimov 2008.
0004 // (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost
0005 // Software License, Version 1.0. (See accompanying file
0006 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 // See http://www.boost.org/libs/interprocess for documentation.
0009 //
0010 //////////////////////////////////////////////////////////////////////////////
0011 
0012 //Parts of this file come from boost/smart_ptr/detail/yield_k.hpp
0013 //Many thanks to Peter Dimov.
0014 
0015 #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
0016 #define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED
0017 
0018 #ifndef BOOST_CONFIG_HPP
0019 #  include <boost/config.hpp>
0020 #endif
0021 #
0022 #if defined(BOOST_HAS_PRAGMA_ONCE)
0023 # pragma once
0024 #endif
0025 
0026 #include <boost/interprocess/detail/config_begin.hpp>
0027 #include <boost/interprocess/detail/workaround.hpp>
0028 #include <boost/interprocess/detail/os_thread_functions.hpp>
0029 
0030 //#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
0031 #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
0032 #include <iostream>
0033 #endif
0034 
0035 // BOOST_INTERPROCESS_SMT_PAUSE
0036 
0037 #if defined(_MSC_VER) && ( defined(_M_IX86) || defined(_M_X64) )
0038 
0039 extern "C" void _mm_pause();
0040 #pragma intrinsic( _mm_pause )
0041 
0042 #define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause();
0043 
0044 #elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) && !defined(_CRAYC)
0045 
0046 #define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" );
0047 
0048 #endif
0049 
0050 namespace boost{
0051 namespace interprocess{
0052 namespace ipcdetail {
0053 
0054 template<int Dummy = 0>
0055 class num_core_holder
0056 {
0057    public:
0058    static unsigned int get()
0059    {
0060       if(!num_cores){
0061          return ipcdetail::get_num_cores();
0062       }
0063       else{
0064          return num_cores;
0065       }
0066    }
0067 
0068    private:
0069    static unsigned int num_cores;
0070 };
0071 
0072 template<int Dummy>
0073 unsigned int num_core_holder<Dummy>::num_cores = ipcdetail::get_num_cores();
0074 
0075 }  //namespace ipcdetail {
0076 
0077 class spin_wait
0078 {
0079    public:
0080 
0081    static const unsigned int nop_pause_limit = 32u;
0082    spin_wait()
0083       : m_count_start(), m_ul_yield_only_counts(), m_k()
0084    {}
0085 
0086    #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
0087    ~spin_wait()
0088    {
0089       if(m_k){
0090          std::cout << "final m_k: " << m_k
0091                    << " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl;
0092       }
0093    }
0094    #endif
0095 
0096    unsigned int count() const
0097    {  return m_k;  }
0098 
0099    void yield()
0100    {
0101       //Lazy initialization of limits
0102       if( !m_k){
0103          this->init_limits();
0104       }
0105       //Nop tries
0106       if( m_k < (nop_pause_limit >> 2) ){
0107 
0108       }
0109       //Pause tries if the processor supports it
0110       #if defined(BOOST_INTERPROCESS_SMT_PAUSE)
0111       else if( m_k < nop_pause_limit ){
0112          BOOST_INTERPROCESS_SMT_PAUSE
0113       }
0114       #endif
0115       //Yield/Sleep strategy
0116       else{
0117          //Lazy initialization of tick information
0118          if(m_k == nop_pause_limit){
0119             this->init_tick_info();
0120          }
0121          else if( this->yield_or_sleep() ){
0122             ipcdetail::thread_yield();
0123          }
0124          else{
0125             ipcdetail::thread_sleep_tick();
0126          }
0127       }
0128       ++m_k;
0129    }
0130 
0131    void reset()
0132    {
0133       m_k = 0u;
0134    }
0135 
0136    private:
0137 
0138    void init_limits()
0139    {
0140       unsigned int num_cores = ipcdetail::num_core_holder<0>::get();
0141       m_k = num_cores > 1u ? 0u : nop_pause_limit;
0142    }
0143 
0144    void init_tick_info()
0145    {
0146       m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts();
0147       m_count_start = ipcdetail::get_current_system_highres_count();
0148    }
0149 
0150    //Returns true if yield must be called, false is sleep must be called
0151    bool yield_or_sleep()
0152    {
0153       if(!m_ul_yield_only_counts){  //If yield-only limit was reached then yield one in every two tries
0154          return (m_k & 1u) != 0;
0155       }
0156       else{ //Try to see if we've reched yield-only time limit
0157          const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count();
0158          const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start);
0159          if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){
0160             #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
0161             std::cout << "elapsed!\n"
0162                       << "  m_ul_yield_only_counts: " << m_ul_yield_only_counts
0163                      << " system tick(us): " << ipcdetail::get_system_tick_us() << '\n'
0164                       << "  m_k: " << m_k << " elapsed counts: ";
0165                      ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl;
0166             #endif
0167             //Yield-only time reached, now it's time to sleep
0168             m_ul_yield_only_counts = 0ul;
0169             return false;
0170          }
0171       }
0172       return true;   //Otherwise yield
0173    }
0174 
0175    ipcdetail::OS_highres_count_t m_count_start;
0176    unsigned long m_ul_yield_only_counts;
0177    unsigned int  m_k;
0178 };
0179 
0180 } // namespace interprocess
0181 } // namespace boost
0182 
0183 #include <boost/interprocess/detail/config_end.hpp>
0184 
0185 #endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED