1 //
2 // detail/conditionally_enabled_mutex.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
12 #define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 #include <boost/asio/detail/mutex.hpp>
20 #include <boost/asio/detail/noncopyable.hpp>
21 #include <boost/asio/detail/scoped_lock.hpp>
22 
23 #include <boost/asio/detail/push_options.hpp>
24 
25 namespace boost {
26 namespace asio {
27 namespace detail {
28 
29 // Mutex adapter used to conditionally enable or disable locking.
30 class conditionally_enabled_mutex
31   : private noncopyable
32 {
33 public:
34   // Helper class to lock and unlock a mutex automatically.
35   class scoped_lock
36     : private noncopyable
37   {
38   public:
39     // Tag type used to distinguish constructors.
40     enum adopt_lock_t { adopt_lock };
41 
42     // Constructor adopts a lock that is already held.
scoped_lock(conditionally_enabled_mutex & m,adopt_lock_t)43     scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t)
44       : mutex_(m),
45         locked_(m.enabled_)
46     {
47     }
48 
49     // Constructor acquires the lock.
scoped_lock(conditionally_enabled_mutex & m)50     explicit scoped_lock(conditionally_enabled_mutex& m)
51       : mutex_(m)
52     {
53       if (m.enabled_)
54       {
55         mutex_.mutex_.lock();
56         locked_ = true;
57       }
58       else
59         locked_ = false;
60     }
61 
62     // Destructor releases the lock.
~scoped_lock()63     ~scoped_lock()
64     {
65       if (locked_)
66         mutex_.mutex_.unlock();
67     }
68 
69     // Explicitly acquire the lock.
lock()70     void lock()
71     {
72       if (mutex_.enabled_ && !locked_)
73       {
74         mutex_.mutex_.lock();
75         locked_ = true;
76       }
77     }
78 
79     // Explicitly release the lock.
unlock()80     void unlock()
81     {
82       if (locked_)
83       {
84         mutex_.unlock();
85         locked_ = false;
86       }
87     }
88 
89     // Test whether the lock is held.
locked() const90     bool locked() const
91     {
92       return locked_;
93     }
94 
95     // Get the underlying mutex.
mutex()96     boost::asio::detail::mutex& mutex()
97     {
98       return mutex_.mutex_;
99     }
100 
101   private:
102     friend class conditionally_enabled_event;
103     conditionally_enabled_mutex& mutex_;
104     bool locked_;
105   };
106 
107   // Constructor.
conditionally_enabled_mutex(bool enabled)108   explicit conditionally_enabled_mutex(bool enabled)
109     : enabled_(enabled)
110   {
111   }
112 
113   // Destructor.
~conditionally_enabled_mutex()114   ~conditionally_enabled_mutex()
115   {
116   }
117 
118   // Determine whether locking is enabled.
enabled() const119   bool enabled() const
120   {
121     return enabled_;
122   }
123 
124   // Lock the mutex.
lock()125   void lock()
126   {
127     if (enabled_)
128       mutex_.lock();
129   }
130 
131   // Unlock the mutex.
unlock()132   void unlock()
133   {
134     if (enabled_)
135       mutex_.unlock();
136   }
137 
138 private:
139   friend class scoped_lock;
140   friend class conditionally_enabled_event;
141   boost::asio::detail::mutex mutex_;
142   const bool enabled_;
143 };
144 
145 } // namespace detail
146 } // namespace asio
147 } // namespace boost
148 
149 #include <boost/asio/detail/pop_options.hpp>
150 
151 #endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
152