Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/log/detail/adaptive_mutex.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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