1 // Copyright (C) 2001-2003
2 // William E. Kempf
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #define BOOST_THREAD_VERSION 2
8 #define BOOST_TEST_MODULE Boost.Threads: mutex test suite
9
10 #include <boost/thread/detail/config.hpp>
11
12 #include <boost/thread/mutex.hpp>
13 #include <boost/thread/lock_types.hpp>
14 #include <boost/thread/thread_only.hpp>
15 #include <boost/thread/recursive_mutex.hpp>
16 #include <boost/thread/thread_time.hpp>
17 #include <boost/thread/condition.hpp>
18
19 #define BOOST_TEST_MODULE Boost.Threads: mutex test suite
20
21 #include <boost/test/unit_test.hpp>
22
23 #define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
24 #include "./util.inl"
25
26 template <typename M>
27 struct test_lock
28 {
29 typedef M mutex_type;
30 typedef typename M::scoped_lock lock_type;
31
operator ()test_lock32 void operator()()
33 {
34 mutex_type mutex;
35 boost::condition condition;
36
37 // Test the lock's constructors.
38 {
39 lock_type lock(mutex, boost::defer_lock);
40 BOOST_CHECK(!lock);
41 }
42 lock_type lock(mutex);
43 BOOST_CHECK(lock ? true : false);
44
45 // Construct and initialize an xtime for a fast time out.
46 boost::xtime xt = delay(0, 100);
47
48 // Test the lock and the mutex with condition variables.
49 // No one is going to notify this condition variable. We expect to
50 // time out.
51 BOOST_CHECK(!condition.timed_wait(lock, xt));
52 BOOST_CHECK(lock ? true : false);
53
54 // Test the lock and unlock methods.
55 lock.unlock();
56 BOOST_CHECK(!lock);
57 lock.lock();
58 BOOST_CHECK(lock ? true : false);
59 }
60 };
61
62 template <typename M>
63 struct test_trylock
64 {
65 typedef M mutex_type;
66 typedef typename M::scoped_try_lock try_lock_type;
67
operator ()test_trylock68 void operator()()
69 {
70 mutex_type mutex;
71 boost::condition condition;
72
73 // Test the lock's constructors.
74 {
75 try_lock_type lock(mutex);
76 BOOST_CHECK(lock ? true : false);
77 }
78 {
79 try_lock_type lock(mutex, boost::defer_lock);
80 BOOST_CHECK(!lock);
81 }
82 try_lock_type lock(mutex);
83 BOOST_CHECK(lock ? true : false);
84
85 // Construct and initialize an xtime for a fast time out.
86 boost::xtime xt = delay(0, 100);
87
88 // Test the lock and the mutex with condition variables.
89 // No one is going to notify this condition variable. We expect to
90 // time out.
91 BOOST_CHECK(!condition.timed_wait(lock, xt));
92 BOOST_CHECK(lock ? true : false);
93
94 // Test the lock, unlock and trylock methods.
95 lock.unlock();
96 BOOST_CHECK(!lock);
97 lock.lock();
98 BOOST_CHECK(lock ? true : false);
99 lock.unlock();
100 BOOST_CHECK(!lock);
101 BOOST_CHECK(lock.try_lock());
102 BOOST_CHECK(lock ? true : false);
103 }
104 };
105
106 template<typename Mutex>
107 struct test_lock_times_out_if_other_thread_has_lock
108 {
109 typedef boost::unique_lock<Mutex> Lock;
110
111 Mutex m;
112 boost::mutex done_mutex;
113 bool done;
114 bool locked;
115 boost::condition_variable done_cond;
116
test_lock_times_out_if_other_thread_has_locktest_lock_times_out_if_other_thread_has_lock117 test_lock_times_out_if_other_thread_has_lock():
118 done(false),locked(false)
119 {}
120
locking_threadtest_lock_times_out_if_other_thread_has_lock121 void locking_thread()
122 {
123 Lock lock(m,boost::defer_lock);
124 lock.timed_lock(boost::posix_time::milliseconds(50));
125
126 boost::lock_guard<boost::mutex> lk(done_mutex);
127 locked=lock.owns_lock();
128 done=true;
129 done_cond.notify_one();
130 }
131
locking_thread_through_constructortest_lock_times_out_if_other_thread_has_lock132 void locking_thread_through_constructor()
133 {
134 Lock lock(m,boost::posix_time::milliseconds(50));
135
136 boost::lock_guard<boost::mutex> lk(done_mutex);
137 locked=lock.owns_lock();
138 done=true;
139 done_cond.notify_one();
140 }
141
is_donetest_lock_times_out_if_other_thread_has_lock142 bool is_done() const
143 {
144 return done;
145 }
146
147 typedef test_lock_times_out_if_other_thread_has_lock<Mutex> this_type;
148
do_testtest_lock_times_out_if_other_thread_has_lock149 void do_test(void (this_type::*test_func)())
150 {
151 Lock lock(m);
152
153 locked=false;
154 done=false;
155
156 boost::thread t(test_func,this);
157
158 try
159 {
160 {
161 boost::unique_lock<boost::mutex> lk(done_mutex);
162 BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
163 boost::bind(&this_type::is_done,this)));
164 BOOST_CHECK(!locked);
165 }
166
167 lock.unlock();
168 t.join();
169 }
170 catch(...)
171 {
172 lock.unlock();
173 t.join();
174 throw;
175 }
176 }
177
178
operator ()test_lock_times_out_if_other_thread_has_lock179 void operator()()
180 {
181 do_test(&this_type::locking_thread);
182 do_test(&this_type::locking_thread_through_constructor);
183 }
184 };
185
186 template <typename M>
187 struct test_timedlock
188 {
189 typedef M mutex_type;
190 typedef typename M::scoped_timed_lock timed_lock_type;
191
fake_predicatetest_timedlock192 static bool fake_predicate()
193 {
194 return false;
195 }
196
operator ()test_timedlock197 void operator()()
198 {
199 test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
200
201 mutex_type mutex;
202 boost::condition condition;
203
204 // Test the lock's constructors.
205 {
206 // Construct and initialize an xtime for a fast time out.
207 boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
208
209 timed_lock_type lock(mutex, xt);
210 BOOST_CHECK(lock ? true : false);
211 }
212 {
213 timed_lock_type lock(mutex, boost::defer_lock);
214 BOOST_CHECK(!lock);
215 }
216 timed_lock_type lock(mutex);
217 BOOST_CHECK(lock ? true : false);
218
219 // Construct and initialize an xtime for a fast time out.
220 boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100);
221
222 // Test the lock and the mutex with condition variables.
223 // No one is going to notify this condition variable. We expect to
224 // time out.
225 BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate));
226 BOOST_CHECK(lock ? true : false);
227
228 boost::system_time now=boost::get_system_time();
229 boost::posix_time::milliseconds const timeout_resolution(20);
230 BOOST_CHECK((timeout-timeout_resolution)<now);
231
232 // Test the lock, unlock and timedlock methods.
233 lock.unlock();
234 BOOST_CHECK(!lock);
235 lock.lock();
236 BOOST_CHECK(lock ? true : false);
237 lock.unlock();
238 BOOST_CHECK(!lock);
239 boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
240 BOOST_CHECK(lock.timed_lock(target));
241 BOOST_CHECK(lock ? true : false);
242 lock.unlock();
243 BOOST_CHECK(!lock);
244
245 BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
246 mutex.unlock();
247
248 BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
249 BOOST_CHECK(lock ? true : false);
250 lock.unlock();
251 BOOST_CHECK(!lock);
252
253 }
254 };
255
256 template <typename M>
257 struct test_recursive_lock
258 {
259 typedef M mutex_type;
260 typedef typename M::scoped_lock lock_type;
261
operator ()test_recursive_lock262 void operator()()
263 {
264 mutex_type mx;
265 lock_type lock1(mx);
266 lock_type lock2(mx);
267 }
268 };
269
270
do_test_mutex()271 void do_test_mutex()
272 {
273 test_lock<boost::mutex>()();
274 }
275
BOOST_AUTO_TEST_CASE(test_mutex)276 BOOST_AUTO_TEST_CASE(test_mutex)
277 {
278 timed_test(&do_test_mutex, 3);
279 }
280
do_test_try_mutex()281 void do_test_try_mutex()
282 {
283 test_lock<boost::try_mutex>()();
284 test_trylock<boost::try_mutex>()();
285 }
286
BOOST_AUTO_TEST_CASE(test_try_mutex)287 BOOST_AUTO_TEST_CASE(test_try_mutex)
288 {
289 timed_test(&do_test_try_mutex, 3);
290 }
291
do_test_timed_mutex()292 void do_test_timed_mutex()
293 {
294 test_lock<boost::timed_mutex>()();
295 test_trylock<boost::timed_mutex>()();
296 test_timedlock<boost::timed_mutex>()();
297 }
298
BOOST_AUTO_TEST_CASE(test_timed_mutex)299 BOOST_AUTO_TEST_CASE(test_timed_mutex)
300 {
301 timed_test(&do_test_timed_mutex, 3);
302 }
303
do_test_recursive_mutex()304 void do_test_recursive_mutex()
305 {
306 test_lock<boost::recursive_mutex>()();
307 test_recursive_lock<boost::recursive_mutex>()();
308 }
309
BOOST_AUTO_TEST_CASE(test_recursive_mutex)310 BOOST_AUTO_TEST_CASE(test_recursive_mutex)
311 {
312 timed_test(&do_test_recursive_mutex, 3);
313 }
314
do_test_recursive_try_mutex()315 void do_test_recursive_try_mutex()
316 {
317 test_lock<boost::recursive_try_mutex>()();
318 test_trylock<boost::recursive_try_mutex>()();
319 test_recursive_lock<boost::recursive_try_mutex>()();
320 }
321
BOOST_AUTO_TEST_CASE(test_recursive_try_mutex)322 BOOST_AUTO_TEST_CASE(test_recursive_try_mutex)
323 {
324 timed_test(&do_test_recursive_try_mutex, 3);
325 }
326
do_test_recursive_timed_mutex()327 void do_test_recursive_timed_mutex()
328 {
329 test_lock<boost::recursive_timed_mutex>()();
330 test_trylock<boost::recursive_timed_mutex>()();
331 test_timedlock<boost::recursive_timed_mutex>()();
332 test_recursive_lock<boost::recursive_timed_mutex>()();
333 }
334
BOOST_AUTO_TEST_CASE(test_recursive_timed_mutex)335 BOOST_AUTO_TEST_CASE(test_recursive_timed_mutex)
336 {
337 timed_test(&do_test_recursive_timed_mutex, 3);
338 }
339
340
341
342