Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / log / detail / adaptive_mutex.hpp
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   adaptive_mutex.hpp
9  * \author Andrey Semashev
10  * \date   01.08.2010
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15
16 #ifndef BOOST_LOG_DETAIL_ADAPTIVE_MUTEX_HPP_INCLUDED_
17 #define BOOST_LOG_DETAIL_ADAPTIVE_MUTEX_HPP_INCLUDED_
18
19 #include <boost/log/detail/config.hpp>
20
21 #ifdef BOOST_HAS_PRAGMA_ONCE
22 #pragma once
23 #endif
24
25 #ifndef BOOST_LOG_NO_THREADS
26
27 #include <boost/throw_exception.hpp>
28 #include <boost/thread/exceptions.hpp>
29
30 #if defined(BOOST_THREAD_POSIX) // This one can be defined by users, so it should go first
31 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD
32 #elif defined(BOOST_WINDOWS)
33 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI
34 #elif defined(BOOST_HAS_PTHREADS)
35 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD
36 #endif
37
38 #if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI)
39
40 #include <boost/log/detail/pause.hpp>
41 #include <boost/winapi/thread.hpp>
42 #include <boost/detail/interlocked.hpp>
43
44 #if defined(__INTEL_COMPILER) || defined(_MSC_VER)
45 #    if defined(__INTEL_COMPILER)
46 #        define BOOST_LOG_COMPILER_BARRIER __memory_barrier()
47 #    elif defined(__clang__) // clang-win also defines _MSC_VER
48 #        define BOOST_LOG_COMPILER_BARRIER __atomic_signal_fence(__ATOMIC_SEQ_CST)
49 #    else
50 extern "C" void _ReadWriteBarrier(void);
51 #        if defined(BOOST_MSVC)
52 #            pragma intrinsic(_ReadWriteBarrier)
53 #        endif
54 #        define BOOST_LOG_COMPILER_BARRIER _ReadWriteBarrier()
55 #    endif
56 #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
57 #    define BOOST_LOG_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory")
58 #endif
59
60 #include <boost/log/detail/header.hpp>
61
62 namespace boost {
63
64 BOOST_LOG_OPEN_NAMESPACE
65
66 namespace aux {
67
68 //! A mutex that performs spinning or thread yielding in case of contention
69 class adaptive_mutex
70 {
71 private:
72     enum state
73     {
74         initial_pause = 2,
75         max_pause = 16
76     };
77
78     long m_State;
79
80 public:
81     adaptive_mutex() : m_State(0) {}
82
83     bool try_lock()
84     {
85         return (BOOST_INTERLOCKED_COMPARE_EXCHANGE(&m_State, 1L, 0L) == 0L);
86     }
87
88     void lock()
89     {
90 #if defined(BOOST_LOG_AUX_PAUSE)
91         unsigned int pause_count = initial_pause;
92 #endif
93         while (!try_lock())
94         {
95 #if defined(BOOST_LOG_AUX_PAUSE)
96             if (pause_count < max_pause)
97             {
98                 for (unsigned int i = 0; i < pause_count; ++i)
99                 {
100                     BOOST_LOG_AUX_PAUSE;
101                 }
102                 pause_count += pause_count;
103             }
104             else
105             {
106                 // Restart spinning after waking up this thread
107                 pause_count = initial_pause;
108                 boost::winapi::SwitchToThread();
109             }
110 #else
111             boost::winapi::SwitchToThread();
112 #endif
113         }
114     }
115
116     void unlock()
117     {
118 #if (defined(_M_IX86) || defined(_M_AMD64)) && defined(BOOST_LOG_COMPILER_BARRIER)
119         BOOST_LOG_COMPILER_BARRIER;
120         m_State = 0L;
121         BOOST_LOG_COMPILER_BARRIER;
122 #else
123         BOOST_INTERLOCKED_EXCHANGE(&m_State, 0L);
124 #endif
125     }
126
127     //  Non-copyable
128     BOOST_DELETED_FUNCTION(adaptive_mutex(adaptive_mutex const&))
129     BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&))
130 };
131
132 #undef BOOST_LOG_AUX_PAUSE
133 #undef BOOST_LOG_COMPILER_BARRIER
134
135 } // namespace aux
136
137 BOOST_LOG_CLOSE_NAMESPACE // namespace log
138
139 } // namespace boost
140
141 #include <boost/log/detail/footer.hpp>
142
143 #elif defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD)
144
145 #include <pthread.h>
146 #include <boost/assert.hpp>
147 #include <boost/log/detail/header.hpp>
148
149 #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)
150 #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP
151 #endif
152
153 namespace boost {
154
155 BOOST_LOG_OPEN_NAMESPACE
156
157 namespace aux {
158
159 //! A mutex that performs spinning or thread yielding in case of contention
160 class adaptive_mutex
161 {
162 private:
163     pthread_mutex_t m_State;
164
165 public:
166     adaptive_mutex()
167     {
168 #if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP)
169         pthread_mutexattr_t attrs;
170         pthread_mutexattr_init(&attrs);
171         pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_ADAPTIVE_NP);
172
173         const int err = pthread_mutex_init(&m_State, &attrs);
174         pthread_mutexattr_destroy(&attrs);
175 #else
176         const int err = pthread_mutex_init(&m_State, NULL);
177 #endif
178         if (BOOST_UNLIKELY(err != 0))
179             throw_exception< thread_resource_error >(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__);
180     }
181
182     ~adaptive_mutex()
183     {
184         BOOST_VERIFY(pthread_mutex_destroy(&m_State) == 0);
185     }
186
187     bool try_lock()
188     {
189         const int err = pthread_mutex_trylock(&m_State);
190         if (err == 0)
191             return true;
192         if (BOOST_UNLIKELY(err != EBUSY))
193             throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::try_lock()", __FILE__, __LINE__);
194         return false;
195     }
196
197     void lock()
198     {
199         const int err = pthread_mutex_lock(&m_State);
200         if (BOOST_UNLIKELY(err != 0))
201             throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__);
202     }
203
204     void unlock()
205     {
206         BOOST_VERIFY(pthread_mutex_unlock(&m_State) == 0);
207     }
208
209     //  Non-copyable
210     BOOST_DELETED_FUNCTION(adaptive_mutex(adaptive_mutex const&))
211     BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&))
212
213 private:
214     template< typename ExceptionT >
215     static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_exception(int err, const char* descr, const char* func, const char* file, int line)
216     {
217 #if !defined(BOOST_EXCEPTION_DISABLE)
218         boost::exception_detail::throw_exception_(ExceptionT(err, descr), func, file, line);
219 #else
220         boost::throw_exception(ExceptionT(err, descr));
221 #endif
222     }
223 };
224
225 } // namespace aux
226
227 BOOST_LOG_CLOSE_NAMESPACE // namespace log
228
229 } // namespace boost
230
231 #include <boost/log/detail/footer.hpp>
232
233 #endif
234
235 #endif // BOOST_LOG_NO_THREADS
236
237 #endif // BOOST_LOG_DETAIL_ADAPTIVE_MUTEX_HPP_INCLUDED_