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 | |
32 | 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(secs: 0, msecs: 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 | |
68 | 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(secs: 0, msecs: 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 | |
117 | test_lock_times_out_if_other_thread_has_lock(): |
118 | done(false),locked(false) |
119 | {} |
120 | |
121 | 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 | |
132 | 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 | |
142 | 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 | |
149 | 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 | |
179 | void operator()() |
180 | { |
181 | do_test(test_func: &this_type::locking_thread); |
182 | do_test(test_func: &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 | |
192 | static bool fake_predicate() |
193 | { |
194 | return false; |
195 | } |
196 | |
197 | 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 | |
262 | void operator()() |
263 | { |
264 | mutex_type mx; |
265 | lock_type lock1(mx); |
266 | lock_type lock2(mx); |
267 | } |
268 | }; |
269 | |
270 | |
271 | void do_test_mutex() |
272 | { |
273 | test_lock<boost::mutex>()(); |
274 | } |
275 | |
276 | BOOST_AUTO_TEST_CASE(test_mutex) |
277 | { |
278 | timed_test(func: &do_test_mutex, secs: 3); |
279 | } |
280 | |
281 | void do_test_try_mutex() |
282 | { |
283 | test_lock<boost::try_mutex>()(); |
284 | test_trylock<boost::try_mutex>()(); |
285 | } |
286 | |
287 | BOOST_AUTO_TEST_CASE(test_try_mutex) |
288 | { |
289 | timed_test(func: &do_test_try_mutex, secs: 3); |
290 | } |
291 | |
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 | |
299 | BOOST_AUTO_TEST_CASE(test_timed_mutex) |
300 | { |
301 | timed_test(func: &do_test_timed_mutex, secs: 3); |
302 | } |
303 | |
304 | void do_test_recursive_mutex() |
305 | { |
306 | test_lock<boost::recursive_mutex>()(); |
307 | test_recursive_lock<boost::recursive_mutex>()(); |
308 | } |
309 | |
310 | BOOST_AUTO_TEST_CASE(test_recursive_mutex) |
311 | { |
312 | timed_test(func: &do_test_recursive_mutex, secs: 3); |
313 | } |
314 | |
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 | |
322 | BOOST_AUTO_TEST_CASE(test_recursive_try_mutex) |
323 | { |
324 | timed_test(func: &do_test_recursive_try_mutex, secs: 3); |
325 | } |
326 | |
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 | |
335 | BOOST_AUTO_TEST_CASE(test_recursive_timed_mutex) |
336 | { |
337 | timed_test(func: &do_test_recursive_timed_mutex, secs: 3); |
338 | } |
339 | |
340 | |
341 | |
342 | |