Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:20

0001 /*
0002  *          Copyright Andrey Semashev 2007 - 2015.
0003  * Distributed under the Boost Software License, Version 1.0.
0004  *    (See accompanying file LICENSE_1_0.txt or copy at
0005  *          http://www.boost.org/LICENSE_1_0.txt)
0006  */
0007 /*!
0008  * \file   adaptive_mutex.hpp
0009  * \author Andrey Semashev
0010  * \date   01.08.2010
0011  *
0012  * \brief  This header is the Boost.Log library implementation, see the library documentation
0013  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
0014  */
0015 
0016 #ifndef BOOST_LOG_DETAIL_ADAPTIVE_MUTEX_HPP_INCLUDED_
0017 #define BOOST_LOG_DETAIL_ADAPTIVE_MUTEX_HPP_INCLUDED_
0018 
0019 #include <boost/log/detail/config.hpp>
0020 
0021 #ifdef BOOST_HAS_PRAGMA_ONCE
0022 #pragma once
0023 #endif
0024 
0025 #ifndef BOOST_LOG_NO_THREADS
0026 
0027 #include <boost/throw_exception.hpp>
0028 #include <boost/thread/exceptions.hpp>
0029 #include <boost/assert/source_location.hpp>
0030 
0031 #if defined(BOOST_THREAD_POSIX) // This one can be defined by users, so it should go first
0032 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD
0033 #elif defined(BOOST_WINDOWS)
0034 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI
0035 #elif defined(BOOST_HAS_PTHREADS)
0036 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD
0037 #endif
0038 
0039 #if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI)
0040 
0041 #include <boost/log/detail/pause.hpp>
0042 #include <boost/winapi/thread.hpp>
0043 #include <boost/detail/interlocked.hpp>
0044 
0045 #if defined(__INTEL_COMPILER) || defined(_MSC_VER)
0046 #    if defined(__INTEL_COMPILER)
0047 #        define BOOST_LOG_COMPILER_BARRIER __memory_barrier()
0048 #    elif defined(__clang__) // clang-win also defines _MSC_VER
0049 #        define BOOST_LOG_COMPILER_BARRIER __atomic_signal_fence(__ATOMIC_SEQ_CST)
0050 #    else
0051 extern "C" void _ReadWriteBarrier(void);
0052 #        if defined(BOOST_MSVC)
0053 #            pragma intrinsic(_ReadWriteBarrier)
0054 #        endif
0055 #        define BOOST_LOG_COMPILER_BARRIER _ReadWriteBarrier()
0056 #    endif
0057 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
0058 #    define BOOST_LOG_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory")
0059 #endif
0060 
0061 #include <boost/log/detail/header.hpp>
0062 
0063 namespace boost {
0064 
0065 BOOST_LOG_OPEN_NAMESPACE
0066 
0067 namespace aux {
0068 
0069 //! A mutex that performs spinning or thread yielding in case of contention
0070 class adaptive_mutex
0071 {
0072 private:
0073     enum state
0074     {
0075         initial_pause = 2,
0076         max_pause = 16
0077     };
0078 
0079     long m_State;
0080 
0081 public:
0082     adaptive_mutex() : m_State(0) {}
0083 
0084     bool try_lock()
0085     {
0086         return (BOOST_INTERLOCKED_COMPARE_EXCHANGE(&m_State, 1L, 0L) == 0L);
0087     }
0088 
0089     void lock()
0090     {
0091 #if defined(BOOST_LOG_AUX_PAUSE)
0092         unsigned int pause_count = initial_pause;
0093 #endif
0094         while (!try_lock())
0095         {
0096 #if defined(BOOST_LOG_AUX_PAUSE)
0097             if (pause_count < max_pause)
0098             {
0099                 for (unsigned int i = 0; i < pause_count; ++i)
0100                 {
0101                     BOOST_LOG_AUX_PAUSE;
0102                 }
0103                 pause_count += pause_count;
0104             }
0105             else
0106             {
0107                 // Restart spinning after waking up this thread
0108                 pause_count = initial_pause;
0109                 boost::winapi::SwitchToThread();
0110             }
0111 #else
0112             boost::winapi::SwitchToThread();
0113 #endif
0114         }
0115     }
0116 
0117     void unlock()
0118     {
0119 #if (defined(_M_IX86) || defined(_M_AMD64)) && defined(BOOST_LOG_COMPILER_BARRIER)
0120         BOOST_LOG_COMPILER_BARRIER;
0121         m_State = 0L;
0122         BOOST_LOG_COMPILER_BARRIER;
0123 #else
0124         BOOST_INTERLOCKED_EXCHANGE(&m_State, 0L);
0125 #endif
0126     }
0127 
0128     //  Non-copyable
0129     BOOST_DELETED_FUNCTION(adaptive_mutex(adaptive_mutex const&))
0130     BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&))
0131 };
0132 
0133 #undef BOOST_LOG_AUX_PAUSE
0134 #undef BOOST_LOG_COMPILER_BARRIER
0135 
0136 } // namespace aux
0137 
0138 BOOST_LOG_CLOSE_NAMESPACE // namespace log
0139 
0140 } // namespace boost
0141 
0142 #include <boost/log/detail/footer.hpp>
0143 
0144 #elif defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD)
0145 
0146 #include <pthread.h>
0147 #include <boost/assert.hpp>
0148 #include <boost/log/detail/header.hpp>
0149 
0150 #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)
0151 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP
0152 #endif
0153 
0154 namespace boost {
0155 
0156 BOOST_LOG_OPEN_NAMESPACE
0157 
0158 namespace aux {
0159 
0160 //! A mutex that performs spinning or thread yielding in case of contention
0161 class adaptive_mutex
0162 {
0163 private:
0164     pthread_mutex_t m_State;
0165 
0166 public:
0167     adaptive_mutex()
0168     {
0169 #if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP)
0170         pthread_mutexattr_t attrs;
0171         pthread_mutexattr_init(&attrs);
0172         pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_ADAPTIVE_NP);
0173 
0174         const int err = pthread_mutex_init(&m_State, &attrs);
0175         pthread_mutexattr_destroy(&attrs);
0176 #else
0177         const int err = pthread_mutex_init(&m_State, NULL);
0178 #endif
0179         if (BOOST_UNLIKELY(err != 0))
0180             throw_exception< thread_resource_error >(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__);
0181     }
0182 
0183     ~adaptive_mutex()
0184     {
0185         BOOST_VERIFY(pthread_mutex_destroy(&m_State) == 0);
0186     }
0187 
0188     bool try_lock()
0189     {
0190         const int err = pthread_mutex_trylock(&m_State);
0191         if (err == 0)
0192             return true;
0193         if (BOOST_UNLIKELY(err != EBUSY))
0194             throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::try_lock()", __FILE__, __LINE__);
0195         return false;
0196     }
0197 
0198     void lock()
0199     {
0200         const int err = pthread_mutex_lock(&m_State);
0201         if (BOOST_UNLIKELY(err != 0))
0202             throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__);
0203     }
0204 
0205     void unlock()
0206     {
0207         BOOST_VERIFY(pthread_mutex_unlock(&m_State) == 0);
0208     }
0209 
0210     //  Non-copyable
0211     BOOST_DELETED_FUNCTION(adaptive_mutex(adaptive_mutex const&))
0212     BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&))
0213 
0214 private:
0215     template< typename ExceptionT >
0216     static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_exception(int err, const char* descr, const char* func, const char* file, int line)
0217     {
0218         boost::throw_exception(ExceptionT(err, descr), boost::source_location(file, line, func));
0219     }
0220 };
0221 
0222 } // namespace aux
0223 
0224 BOOST_LOG_CLOSE_NAMESPACE // namespace log
0225 
0226 } // namespace boost
0227 
0228 #include <boost/log/detail/footer.hpp>
0229 
0230 #endif
0231 
0232 #endif // BOOST_LOG_NO_THREADS
0233 
0234 #endif // BOOST_LOG_DETAIL_ADAPTIVE_MUTEX_HPP_INCLUDED_