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   locks.hpp
9  * \author Andrey Semashev
10  * \date   30.05.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_LOCKS_HPP_INCLUDED_
17 #define BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_
18 
19 #include <boost/log/detail/config.hpp>
20 #include <boost/log/detail/header.hpp>
21 
22 #ifdef BOOST_HAS_PRAGMA_ONCE
23 #pragma once
24 #endif
25 
26 namespace boost {
27 
28 #ifndef BOOST_LOG_NO_THREADS
29 
30 // Forward declaration of Boost.Thread locks. Specified here to avoid including Boost.Thread,
31 // which would bring in many dependent headers, including a great deal of Boost.DateTime.
32 template< typename >
33 class lock_guard;
34 template< typename >
35 class shared_lock_guard;
36 template< typename >
37 class shared_lock;
38 template< typename >
39 class upgrade_lock;
40 template< typename >
41 class unique_lock;
42 
43 template< typename >
44 struct is_mutex_type;
45 
46 #endif // BOOST_LOG_NO_THREADS
47 
48 BOOST_LOG_OPEN_NAMESPACE
49 
50 //! An auxiliary pseudo-lock to express no locking requirements in logger features
51 template< typename MutexT >
52 class no_lock
53 {
54 public:
55     /*!
56      * Constructs the pseudo-lock. The mutex is not affected during the construction.
57      */
no_lock(MutexT &)58     explicit no_lock(MutexT&) {}
59 
60 private:
61     no_lock(no_lock const&);
62     no_lock& operator= (no_lock const&);
63 };
64 
65 namespace aux {
66 
67 #ifndef BOOST_LOG_NO_THREADS
68 
69 //! A trait to detect if the mutex supports exclusive locking
70 template< typename MutexT >
71 struct is_exclusively_lockable
72 {
73     typedef char true_type;
74     struct false_type { char t[2]; };
75 
76     template< typename T >
77     static true_type check_lockable(T*, void (T::*)() = &T::lock, void (T::*)() = &T::unlock);
78     static false_type check_lockable(void*);
79 
80     enum value_t { value = sizeof(check_lockable((MutexT*)NULL)) == sizeof(true_type) };
81 };
82 
83 //! A trait to detect if the mutex supports shared locking
84 template< typename MutexT >
85 struct is_shared_lockable
86 {
87     typedef char true_type;
88     struct false_type { char t[2]; };
89 
90     template< typename T >
91     static true_type check_shared_lockable(T*, void (T::*)() = &T::lock_shared, void (T::*)() = &T::unlock_shared);
92     static false_type check_shared_lockable(void*);
93 
94     enum value_t { value = sizeof(check_shared_lockable((MutexT*)NULL)) == sizeof(true_type) };
95 };
96 
97 //! A scope guard that automatically unlocks the mutex on destruction
98 template< typename MutexT >
99 struct exclusive_auto_unlocker
100 {
exclusive_auto_unlockerboost::aux::exclusive_auto_unlocker101     explicit exclusive_auto_unlocker(MutexT& m) BOOST_NOEXCEPT : m_Mutex(m)
102     {
103     }
~exclusive_auto_unlockerboost::aux::exclusive_auto_unlocker104     ~exclusive_auto_unlocker()
105     {
106         m_Mutex.unlock();
107     }
108 
109     BOOST_DELETED_FUNCTION(exclusive_auto_unlocker(exclusive_auto_unlocker const&))
110     BOOST_DELETED_FUNCTION(exclusive_auto_unlocker& operator= (exclusive_auto_unlocker const&))
111 
112 protected:
113     MutexT& m_Mutex;
114 };
115 
116 //! An analogue to the minimalistic \c lock_guard template. Defined here to avoid including Boost.Thread.
117 template< typename MutexT >
118 struct exclusive_lock_guard
119 {
exclusive_lock_guardboost::aux::exclusive_lock_guard120     explicit exclusive_lock_guard(MutexT& m) : m_Mutex(m)
121     {
122         m.lock();
123     }
~exclusive_lock_guardboost::aux::exclusive_lock_guard124     ~exclusive_lock_guard()
125     {
126         m_Mutex.unlock();
127     }
128 
129     BOOST_DELETED_FUNCTION(exclusive_lock_guard(exclusive_lock_guard const&))
130     BOOST_DELETED_FUNCTION(exclusive_lock_guard& operator= (exclusive_lock_guard const&))
131 
132 private:
133     MutexT& m_Mutex;
134 };
135 
136 //! An analogue to the minimalistic \c lock_guard template that locks \c shared_mutex with shared ownership.
137 template< typename MutexT >
138 struct shared_lock_guard
139 {
shared_lock_guardboost::aux::shared_lock_guard140     explicit shared_lock_guard(MutexT& m) : m_Mutex(m)
141     {
142         m.lock_shared();
143     }
~shared_lock_guardboost::aux::shared_lock_guard144     ~shared_lock_guard()
145     {
146         m_Mutex.unlock_shared();
147     }
148 
149     BOOST_DELETED_FUNCTION(shared_lock_guard(shared_lock_guard const&))
150     BOOST_DELETED_FUNCTION(shared_lock_guard& operator= (shared_lock_guard const&))
151 
152 private:
153     MutexT& m_Mutex;
154 };
155 
156 //! A deadlock-safe lock type that exclusively locks two mutexes
157 template< typename MutexT1, typename MutexT2 >
158 class multiple_unique_lock2
159 {
160 public:
multiple_unique_lock2(MutexT1 & m1,MutexT2 & m2)161     multiple_unique_lock2(MutexT1& m1, MutexT2& m2) :
162         m_p1(&m1),
163         m_p2(&m2)
164     {
165         // Yes, it's not conforming, but it works
166         // and it doesn't require to #include <functional>
167         if (static_cast< void* >(m_p1) < static_cast< void* >(m_p2))
168         {
169             m_p1->lock();
170             m_p2->lock();
171         }
172         else
173         {
174             m_p2->lock();
175             m_p1->lock();
176         }
177     }
~multiple_unique_lock2()178     ~multiple_unique_lock2()
179     {
180         m_p2->unlock();
181         m_p1->unlock();
182     }
183 
184 private:
185     MutexT1* m_p1;
186     MutexT2* m_p2;
187 };
188 
189 #endif // BOOST_LOG_NO_THREADS
190 
191 } // namespace aux
192 
193 BOOST_LOG_CLOSE_NAMESPACE // namespace log
194 
195 } // namespace boost
196 
197 #include <boost/log/detail/footer.hpp>
198 
199 #endif // BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_
200