• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 using namespace boost::placeholders;
33 
34 class execution_monitor
35 {
36 public:
execution_monitor(int secs)37     execution_monitor(int secs)
38         : done(false), m_secs(secs) { }
start()39     void start()
40     {
41         boost::mutex::scoped_lock lock(mutex);
42         done = false;
43     }
finish()44     void finish()
45     {
46         boost::mutex::scoped_lock lock(mutex);
47         done = true;
48         cond.notify_one();
49     }
wait()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(lock, timeout))
56                 break;
57         }
58         return done;
59     }
60 
61 private:
62     boost::mutex mutex;
63     boost::condition cond;
64     bool done;
65     int m_secs;
66 };
67 
68 template <typename F>
69 class indirect_adapter
70 {
71 public:
indirect_adapter(F func,execution_monitor & monitor)72     indirect_adapter(F func, execution_monitor& monitor)
73         : m_func(func), m_monitor(monitor) { }
operator ()() const74     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 
89 private:
90     F m_func;
91     execution_monitor& m_monitor;
92     void operator=(indirect_adapter&);
93 };
94 
95 template <typename F>
timed_test(F func,int secs)96 void 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 
105 template <typename M>
106 struct test_lock
107 {
108     typedef M mutex_type;
109     typedef typename boost::unique_lock<M> lock_type;
110 
operator ()test_lock111     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 
141 template <typename M>
142 struct test_trylock
143 {
144     typedef M mutex_type;
145     typedef typename boost::unique_lock<M> lock_type;
146 
operator ()test_trylock147     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 
185 template<typename Mutex>
186 struct 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 
test_lock_exclusiontest_lock_exclusion196     test_lock_exclusion():
197         done(false),locked(false)
198     {}
199 
locking_threadtest_lock_exclusion200     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 
is_donetest_lock_exclusion210     bool is_done() const
211     {
212         return done;
213     }
214 
215     typedef test_lock_exclusion<Mutex> this_type;
216 
do_testtest_lock_exclusion217     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 
operator ()test_lock_exclusion255     void operator()()
256     {
257         do_test(&this_type::locking_thread);
258     }
259 };
260 
261 
do_test_mutex()262 void 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 
test_mutex()272 void test_mutex()
273 {
274     timed_test(&do_test_mutex, 3);
275 }
276 
do_test_dummy_mutex()277 void do_test_dummy_mutex()
278 {
279     test_lock<boost::signals2::dummy_mutex>()();
280     test_trylock<boost::signals2::dummy_mutex>()();
281 }
282 
test_dummy_mutex()283 void test_dummy_mutex()
284 {
285     timed_test(&do_test_dummy_mutex, 2);
286 }
287 
BOOST_AUTO_TEST_CASE(test_main)288 BOOST_AUTO_TEST_CASE(test_main)
289 {
290     test_mutex();
291     test_dummy_mutex();
292 }
293