1 // Copyright (C) 2001-2003
2 // William E. Kempf
3 //
4 // Permission to use, copy, modify, distribute and sell this software
5 // and its documentation for any purpose is hereby granted without fee,
6 // provided that the above copyright notice appear in all copies and
7 // that both that copyright notice and this permission notice appear
8 // in supporting documentation.  William E. Kempf makes no representations
9 // about the suitability of this software for any purpose.
10 // It is provided "as is" without express or implied warranty.
11 
12 #ifndef BOOST_XLOCK_WEK070601_HPP
13 #define BOOST_XLOCK_WEK070601_HPP
14 
15 #include <boost/thread/detail/config.hpp>
16 
17 #include <boost/utility.hpp>
18 #include <boost/thread/exceptions.hpp>
19 
20 namespace boost {
21 
22 class condition;
23 struct xtime;
24 
25 namespace detail { namespace thread {
26 
27 template <typename Mutex>
28 class lock_ops : private noncopyable
29 {
30 private:
lock_ops()31     lock_ops() { }
32 
33 public:
34     typedef typename Mutex::cv_state lock_state;
35 
lock(Mutex & m)36     static void lock(Mutex& m)
37     {
38         m.do_lock();
39     }
trylock(Mutex & m)40     static bool trylock(Mutex& m)
41     {
42         return m.do_trylock();
43     }
timedlock(Mutex & m,const xtime & xt)44     static bool timedlock(Mutex& m, const xtime& xt)
45     {
46         return m.do_timedlock(xt);
47     }
unlock(Mutex & m)48     static void unlock(Mutex& m)
49     {
50         m.do_unlock();
51     }
lock(Mutex & m,lock_state & state)52     static void lock(Mutex& m, lock_state& state)
53     {
54         m.do_lock(state);
55     }
unlock(Mutex & m,lock_state & state)56     static void unlock(Mutex& m, lock_state& state)
57     {
58         m.do_unlock(state);
59     }
60 };
61 
62 template <typename Mutex>
63 class scoped_lock : private noncopyable
64 {
65 public:
66     typedef Mutex mutex_type;
67 
scoped_lock(Mutex & mx,bool initially_locked=true)68     explicit scoped_lock(Mutex& mx, bool initially_locked=true)
69         : m_mutex(mx), m_locked(false)
70     {
71         if (initially_locked) lock();
72     }
~scoped_lock()73     ~scoped_lock()
74     {
75         if (m_locked) unlock();
76     }
77 
lock()78     void lock()
79     {
80         if (m_locked) throw lock_error();
81         lock_ops<Mutex>::lock(m_mutex);
82         m_locked = true;
83     }
unlock()84     void unlock()
85     {
86         if (!m_locked) throw lock_error();
87         lock_ops<Mutex>::unlock(m_mutex);
88         m_locked = false;
89     }
90 
locked() const91     bool locked() const { return m_locked; }
operator const void*() const92     operator const void*() const { return m_locked ? this : 0; }
93 
94 private:
95     friend class boost::condition;
96 
97     Mutex& m_mutex;
98     bool m_locked;
99 };
100 
101 template <typename TryMutex>
102 class scoped_try_lock : private noncopyable
103 {
104 public:
105     typedef TryMutex mutex_type;
106 
scoped_try_lock(TryMutex & mx)107     explicit scoped_try_lock(TryMutex& mx)
108         : m_mutex(mx), m_locked(false)
109     {
110         try_lock();
111     }
scoped_try_lock(TryMutex & mx,bool initially_locked)112     scoped_try_lock(TryMutex& mx, bool initially_locked)
113         : m_mutex(mx), m_locked(false)
114     {
115         if (initially_locked) lock();
116     }
~scoped_try_lock()117     ~scoped_try_lock()
118     {
119         if (m_locked) unlock();
120     }
121 
lock()122     void lock()
123     {
124         if (m_locked) throw lock_error();
125         lock_ops<TryMutex>::lock(m_mutex);
126         m_locked = true;
127     }
try_lock()128     bool try_lock()
129     {
130         if (m_locked) throw lock_error();
131         return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
132     }
unlock()133     void unlock()
134     {
135         if (!m_locked) throw lock_error();
136         lock_ops<TryMutex>::unlock(m_mutex);
137         m_locked = false;
138     }
139 
locked() const140     bool locked() const { return m_locked; }
operator const void*() const141     operator const void*() const { return m_locked ? this : 0; }
142 
143 private:
144     friend class boost::condition;
145 
146     TryMutex& m_mutex;
147     bool m_locked;
148 };
149 
150 template <typename TimedMutex>
151 class scoped_timed_lock : private noncopyable
152 {
153 public:
154     typedef TimedMutex mutex_type;
155 
scoped_timed_lock(TimedMutex & mx,const xtime & xt)156     scoped_timed_lock(TimedMutex& mx, const xtime& xt)
157         : m_mutex(mx), m_locked(false)
158     {
159         timed_lock(xt);
160     }
scoped_timed_lock(TimedMutex & mx,bool initially_locked)161     scoped_timed_lock(TimedMutex& mx, bool initially_locked)
162         : m_mutex(mx), m_locked(false)
163     {
164         if (initially_locked) lock();
165     }
~scoped_timed_lock()166     ~scoped_timed_lock()
167     {
168         if (m_locked) unlock();
169     }
170 
lock()171     void lock()
172     {
173         if (m_locked) throw lock_error();
174         lock_ops<TimedMutex>::lock(m_mutex);
175         m_locked = true;
176     }
try_lock()177     bool try_lock()
178     {
179         if (m_locked) throw lock_error();
180         return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
181     }
timed_lock(const xtime & xt)182     bool timed_lock(const xtime& xt)
183     {
184         if (m_locked) throw lock_error();
185         return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
186     }
unlock()187     void unlock()
188     {
189         if (!m_locked) throw lock_error();
190         lock_ops<TimedMutex>::unlock(m_mutex);
191         m_locked = false;
192     }
193 
locked() const194     bool locked() const { return m_locked; }
operator const void*() const195     operator const void*() const { return m_locked ? this : 0; }
196 
197 private:
198     friend class boost::condition;
199 
200     TimedMutex& m_mutex;
201     bool m_locked;
202 };
203 
204 } // namespace thread
205 } // namespace detail
206 } // namespace boost
207 
208 #endif // BOOST_XLOCK_WEK070601_HPP
209 
210 // Change Log:
211 //    8 Feb 01  WEKEMPF Initial version.
212 //   22 May 01  WEKEMPF Modified to use xtime for time outs.
213 //   30 Jul 01  WEKEMPF Moved lock types into boost::detail::thread. Renamed
214 //                      some types. Added locked() methods.
215