1// Copyright (C) 2001-2003
2// William E. Kempf
3//
4// Copyright Frank Mori Hess 2009
5//
6// Use, modification and
7// distribution is subject to the Boost Software License, Version
8// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9// http://www.boost.org/LICENSE_1_0.txt)
10
11// This is a simplified/modified version of libs/thread/test/test_mutex.cpp
12// added to test boost::signals2::mutex.
13// For more information, see http://www.boost.org
14
15// Note boost/test/minimal.hpp can cause windows.h to get included, which
16// can screw up our checks of _WIN32_WINNT if it is included
17// after boost/signals2/mutex.hpp. Frank Hess 2009-03-07.
18// We now use boost/test/included/unit_test.hpp, not sure if above still
19// applies, but might as well leave the include where it is.
20#define BOOST_TEST_MODULE mutex_test
21#include <boost/test/included/unit_test.hpp>
22
23#include <boost/bind/bind.hpp>
24#include <boost/signals2/dummy_mutex.hpp>
25#include <boost/signals2/mutex.hpp>
26#include <boost/thread/locks.hpp>
27#include <boost/thread/mutex.hpp>
28#include <boost/thread/thread.hpp>
29#include <boost/thread/thread_time.hpp>
30#include <boost/thread/condition.hpp>
31
32using namespace boost::placeholders;
33
34class execution_monitor
35{
36public:
37 execution_monitor(int secs)
38 : done(false), m_secs(secs) { }
39 void start()
40 {
41 boost::mutex::scoped_lock lock(mutex);
42 done = false;
43 }
44 void finish()
45 {
46 boost::mutex::scoped_lock lock(mutex);
47 done = true;
48 cond.notify_one();
49 }
50 bool wait()
51 {
52 boost::posix_time::time_duration timeout = boost::posix_time::seconds(m_secs);
53 boost::mutex::scoped_lock lock(mutex);
54 while (!done) {
55 if (!cond.timed_wait(m&: lock, wait_duration: timeout))
56 break;
57 }
58 return done;
59 }
60
61private:
62 boost::mutex mutex;
63 boost::condition cond;
64 bool done;
65 int m_secs;
66};
67
68template <typename F>
69class indirect_adapter
70{
71public:
72 indirect_adapter(F func, execution_monitor& monitor)
73 : m_func(func), m_monitor(monitor) { }
74 void operator()() const
75 {
76 try
77 {
78 boost::thread thrd(m_func);
79 thrd.join();
80 }
81 catch (...)
82 {
83 m_monitor.finish();
84 throw;
85 }
86 m_monitor.finish();
87 }
88
89private:
90 F m_func;
91 execution_monitor& m_monitor;
92 void operator=(indirect_adapter&);
93};
94
95template <typename F>
96void timed_test(F func, int secs)
97{
98 execution_monitor monitor(secs);
99 indirect_adapter<F> ifunc(func, monitor);
100 monitor.start();
101 boost::thread thrd(ifunc);
102 BOOST_REQUIRE(monitor.wait()); // Timed test didn't complete in time, possible deadlock
103}
104
105template <typename M>
106struct test_lock
107{
108 typedef M mutex_type;
109 typedef typename boost::unique_lock<M> lock_type;
110
111 void operator()()
112 {
113 mutex_type mutex;
114 boost::condition condition;
115
116 // Test the lock's constructors.
117 {
118 lock_type lock(mutex, boost::defer_lock);
119 BOOST_CHECK(!lock);
120 }
121 lock_type lock(mutex);
122 BOOST_CHECK(lock ? true : false);
123
124 // Construct a fast time out.
125 boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100);
126
127 // Test the lock and the mutex with condition variables.
128 // No one is going to notify this condition variable. We expect to
129 // time out.
130 BOOST_CHECK(!condition.timed_wait(lock, timeout));
131 BOOST_CHECK(lock ? true : false);
132
133 // Test the lock and unlock methods.
134 lock.unlock();
135 BOOST_CHECK(!lock);
136 lock.lock();
137 BOOST_CHECK(lock ? true : false);
138 }
139};
140
141template <typename M>
142struct test_trylock
143{
144 typedef M mutex_type;
145 typedef typename boost::unique_lock<M> lock_type;
146
147 void operator()()
148 {
149 mutex_type mutex;
150 boost::condition condition;
151
152 // Test the lock's constructors.
153 {
154 lock_type lock(mutex, boost::try_to_lock);
155 BOOST_CHECK(lock ? true : false);
156 }
157 {
158 lock_type lock(mutex, boost::defer_lock);
159 BOOST_CHECK(!lock);
160 }
161 lock_type lock(mutex, boost::try_to_lock);
162 BOOST_CHECK(lock ? true : false);
163
164 // Construct a fast time out.
165 boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100);
166
167 // Test the lock and the mutex with condition variables.
168 // No one is going to notify this condition variable. We expect to
169 // time out.
170 BOOST_CHECK(!condition.timed_wait(lock, timeout));
171 BOOST_CHECK(lock ? true : false);
172
173 // Test the lock, unlock and trylock methods.
174 lock.unlock();
175 BOOST_CHECK(!lock);
176 lock.lock();
177 BOOST_CHECK(lock ? true : false);
178 lock.unlock();
179 BOOST_CHECK(!lock);
180 BOOST_CHECK(lock.try_lock());
181 BOOST_CHECK(lock ? true : false);
182 }
183};
184
185template<typename Mutex>
186struct test_lock_exclusion
187{
188 typedef boost::unique_lock<Mutex> Lock;
189
190 Mutex m;
191 boost::mutex done_mutex;
192 bool done;
193 bool locked;
194 boost::condition_variable done_cond;
195
196 test_lock_exclusion():
197 done(false),locked(false)
198 {}
199
200 void locking_thread()
201 {
202 Lock lock(m);
203
204 boost::lock_guard<boost::mutex> lk(done_mutex);
205 locked=lock.owns_lock();
206 done=true;
207 done_cond.notify_one();
208 }
209
210 bool is_done() const
211 {
212 return done;
213 }
214
215 typedef test_lock_exclusion<Mutex> this_type;
216
217 void do_test(void (this_type::*test_func)())
218 {
219 Lock lock(m);
220
221 {
222 boost::lock_guard<boost::mutex> lk(done_mutex);
223 locked=false;
224 }
225
226 done=false;
227
228 boost::thread t(test_func,this);
229
230 try
231 {
232 {
233 boost::mutex::scoped_lock lk(done_mutex);
234 BOOST_CHECK(!done_cond.timed_wait(lk, boost::posix_time::seconds(1),
235 boost::bind(&this_type::is_done,this)));
236 }
237 lock.unlock();
238 {
239 boost::mutex::scoped_lock lk(done_mutex);
240 BOOST_CHECK(done_cond.timed_wait(lk, boost::posix_time::seconds(1),
241 boost::bind(&this_type::is_done,this)));
242 }
243 t.join();
244 BOOST_CHECK(locked);
245 }
246 catch(...)
247 {
248 lock.unlock();
249 t.join();
250 throw;
251 }
252 }
253
254
255 void operator()()
256 {
257 do_test(test_func: &this_type::locking_thread);
258 }
259};
260
261
262void do_test_mutex()
263{
264 test_lock<boost::signals2::mutex>()();
265// try_lock not supported on old versions of windows
266#if !defined(BOOST_HAS_WINTHREADS) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400))
267 test_trylock<boost::signals2::mutex>()();
268#endif
269 test_lock_exclusion<boost::signals2::mutex>()();
270}
271
272void test_mutex()
273{
274 timed_test(func: &do_test_mutex, secs: 3);
275}
276
277void do_test_dummy_mutex()
278{
279 test_lock<boost::signals2::dummy_mutex>()();
280 test_trylock<boost::signals2::dummy_mutex>()();
281}
282
283void test_dummy_mutex()
284{
285 timed_test(func: &do_test_dummy_mutex, secs: 2);
286}
287
288BOOST_AUTO_TEST_CASE(test_main)
289{
290 test_mutex();
291 test_dummy_mutex();
292}
293

source code of boost/libs/signals2/test/mutex_test.cpp