Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:53:31

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 //Forward declaration of MSVC intrinsics
0036 #if defined(_MSC_VER)
0037 #if defined(_M_AMD64) || defined(_M_IX86) || defined(_M_X64)
0038 extern "C" void _mm_pause(void);
0039 #if defined(BOOST_MSVC)
0040 #pragma intrinsic(_mm_pause)
0041 #endif
0042 #elif defined(_M_ARM64) || defined(_M_ARM)
0043 extern "C" void __yield(void);
0044 #if defined(BOOST_MSVC)
0045 #pragma intrinsic(__yield)
0046 #endif
0047 #endif
0048 #endif
0049 
0050 // BOOST_INTERPROCESS_SMT_PAUSE
0051 
0052 #if defined(_MSC_VER) && ( defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) )
0053 
0054 #define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause();
0055 
0056 #elif defined(_MSC_VER) && ( defined(_M_ARM64) || defined(_M_ARM) )
0057 
0058 #define BOOST_INTERPROCESS_SMT_PAUSE __yield();
0059 
0060 #elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) && !defined(_CRAYC)
0061 
0062 #define BOOST_INTERPROCESS_SMT_PAUSE   __asm__ __volatile__("rep; nop" : : : "memory");
0063 
0064 #elif defined(__GNUC__) && ((defined(__ARM_ARCH) && __ARM_ARCH >= 8) || defined(__ARM_ARCH_8A__) || defined(__aarch64__))
0065 
0066 #define BOOST_INTERPROCESS_SMT_PAUSE   __asm__ __volatile__("yield;" : : : "memory");
0067     
0068 #endif
0069 
0070 
0071 namespace boost{
0072 namespace interprocess{
0073 namespace ipcdetail {
0074 
0075 template<int Dummy = 0>
0076 class num_core_holder
0077 {
0078    public:
0079    static unsigned int get()
0080    {
0081       if(!num_cores){
0082          return ipcdetail::get_num_cores();
0083       }
0084       else{
0085          return num_cores;
0086       }
0087    }
0088 
0089    private:
0090    static unsigned int num_cores;
0091 };
0092 
0093 template<int Dummy>
0094 unsigned int num_core_holder<Dummy>::num_cores = ipcdetail::get_num_cores();
0095 
0096 }  //namespace ipcdetail {
0097 
0098 class spin_wait
0099 {
0100    public:
0101 
0102    static const unsigned int nop_pause_limit = 32u;
0103    spin_wait()
0104       : m_count_start(), m_ul_yield_only_counts(), m_k()
0105    {}
0106 
0107    #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
0108    ~spin_wait()
0109    {
0110       if(m_k){
0111          std::cout << "final m_k: " << m_k
0112                    << " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl;
0113       }
0114    }
0115    #endif
0116 
0117    unsigned int count() const
0118    {  return m_k;  }
0119 
0120    void yield()
0121    {
0122       //Lazy initialization of limits
0123       if( !m_k){
0124          this->init_limits();
0125       }
0126       //Nop tries
0127       if( m_k < (nop_pause_limit >> 2) ){
0128 
0129       }
0130       //Pause tries if the processor supports it
0131       #if defined(BOOST_INTERPROCESS_SMT_PAUSE)
0132       else if( m_k < nop_pause_limit ){
0133          BOOST_INTERPROCESS_SMT_PAUSE
0134       }
0135       #endif
0136       //Yield/Sleep strategy
0137       else{
0138          //Lazy initialization of tick information
0139          if(m_k == nop_pause_limit){
0140             this->init_tick_info();
0141          }
0142          else if( this->yield_or_sleep() ){
0143             ipcdetail::thread_yield();
0144          }
0145          else{
0146             ipcdetail::thread_sleep_tick();
0147          }
0148       }
0149       ++m_k;
0150    }
0151 
0152    void reset()
0153    {
0154       m_k = 0u;
0155    }
0156 
0157    private:
0158 
0159    void init_limits()
0160    {
0161       unsigned int num_cores = ipcdetail::num_core_holder<0>::get();
0162       m_k = num_cores > 1u ? 0u : nop_pause_limit;
0163    }
0164 
0165    void init_tick_info()
0166    {
0167       m_ul_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts();
0168       m_count_start = ipcdetail::get_current_system_highres_count();
0169    }
0170 
0171    //Returns true if yield must be called, false is sleep must be called
0172    bool yield_or_sleep()
0173    {
0174       if(!m_ul_yield_only_counts){  //If yield-only limit was reached then yield one in every two tries
0175          return (m_k & 1u) != 0;
0176       }
0177       else{ //Try to see if we've reched yield-only time limit
0178          const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count();
0179          const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start);
0180          if(!ipcdetail::system_highres_count_less_ul(elapsed, m_ul_yield_only_counts)){
0181             #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG
0182             std::cout << "elapsed!\n"
0183                       << "  m_ul_yield_only_counts: " << m_ul_yield_only_counts
0184                      << " system tick(us): " << ipcdetail::get_system_tick_us() << '\n'
0185                       << "  m_k: " << m_k << " elapsed counts: ";
0186                      ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl;
0187             #endif
0188             //Yield-only time reached, now it's time to sleep
0189             m_ul_yield_only_counts = 0ul;
0190             return false;
0191          }
0192       }
0193       return true;   //Otherwise yield
0194    }
0195 
0196    ipcdetail::OS_highres_count_t m_count_start;
0197    unsigned long m_ul_yield_only_counts;
0198    unsigned int  m_k;
0199 };
0200 
0201 } // namespace interprocess
0202 } // namespace boost
0203 
0204 #include <boost/interprocess/detail/config_end.hpp>
0205 
0206 #endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED