1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2004-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 // Copyright (C) 2001-2003
11 // William E. Kempf
12 //
13 // Permission to use, copy, modify, distribute and sell this software
14 // and its documentation for any purpose is hereby granted without fee,
15 // provided that the above copyright notice appear in all copies and
16 // that both that copyright notice and this permission notice appear
17 // in supporting documentation. William E. Kempf makes no representations
18 // about the suitability of this software for any purpose.
19 // It is provided "as is" without express or implied warranty.
20
21 #ifndef BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER
22 #define BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER
23
24 #include <boost/interprocess/detail/config_begin.hpp>
25 #include <boost/interprocess/exceptions.hpp>
26 #include "boost_interprocess_check.hpp"
27 #include "util.hpp"
28 #include <boost/interprocess/detail/os_thread_functions.hpp>
29 #include <boost/interprocess/sync/scoped_lock.hpp>
30 #include <boost/date_time/posix_time/posix_time_types.hpp>
31 #include <iostream>
32
33 namespace boost { namespace interprocess { namespace test {
34
35 template <typename M>
36 struct test_lock
37 {
38 typedef M mutex_type;
39 typedef boost::interprocess::scoped_lock<mutex_type> lock_type;
40
41
operator ()boost::interprocess::test::test_lock42 void operator()()
43 {
44 mutex_type interprocess_mutex;
45
46 // Test the lock's constructors.
47 {
48 lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
49 BOOST_INTERPROCESS_CHECK(!lock);
50 }
51 lock_type lock(interprocess_mutex);
52 BOOST_INTERPROCESS_CHECK(lock ? true : false);
53
54 // Test the lock and unlock methods.
55 lock.unlock();
56 BOOST_INTERPROCESS_CHECK(!lock);
57 lock.lock();
58 BOOST_INTERPROCESS_CHECK(lock ? true : false);
59 }
60 };
61
62 template <typename M>
63 struct test_trylock
64 {
65 typedef M mutex_type;
66 typedef boost::interprocess::scoped_lock<mutex_type> try_to_lock_type;
67
operator ()boost::interprocess::test::test_trylock68 void operator()()
69 {
70 mutex_type interprocess_mutex;
71
72 // Test the lock's constructors.
73 {
74 try_to_lock_type lock(interprocess_mutex, boost::interprocess::try_to_lock);
75 BOOST_INTERPROCESS_CHECK(lock ? true : false);
76 }
77 {
78 try_to_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
79 BOOST_INTERPROCESS_CHECK(!lock);
80 }
81 try_to_lock_type lock(interprocess_mutex);
82 BOOST_INTERPROCESS_CHECK(lock ? true : false);
83
84 // Test the lock, unlock and trylock methods.
85 lock.unlock();
86 BOOST_INTERPROCESS_CHECK(!lock);
87 lock.lock();
88 BOOST_INTERPROCESS_CHECK(lock ? true : false);
89 lock.unlock();
90 BOOST_INTERPROCESS_CHECK(!lock);
91 BOOST_INTERPROCESS_CHECK(lock.try_lock());
92 BOOST_INTERPROCESS_CHECK(lock ? true : false);
93 }
94 };
95
96 template <typename M>
97 struct test_timedlock
98 {
99 typedef M mutex_type;
100 typedef boost::interprocess::scoped_lock<mutex_type> timed_lock_type;
101
operator ()boost::interprocess::test::test_timedlock102 void operator()()
103 {
104 mutex_type interprocess_mutex;
105
106 // Test the lock's constructors.
107 {
108 // Construct and initialize an ptime for a fast time out.
109 boost::posix_time::ptime pt = delay(1*BaseSeconds, 0);
110
111 timed_lock_type lock(interprocess_mutex, pt);
112 BOOST_INTERPROCESS_CHECK(lock ? true : false);
113 }
114 {
115 timed_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
116 BOOST_INTERPROCESS_CHECK(!lock);
117 }
118 timed_lock_type lock(interprocess_mutex);
119 BOOST_INTERPROCESS_CHECK(lock ? true : false);
120
121 // Test the lock, unlock and timedlock methods.
122 lock.unlock();
123 BOOST_INTERPROCESS_CHECK(!lock);
124 lock.lock();
125 BOOST_INTERPROCESS_CHECK(lock ? true : false);
126 lock.unlock();
127 BOOST_INTERPROCESS_CHECK(!lock);
128 boost::posix_time::ptime pt = delay(3*BaseSeconds, 0);
129 BOOST_INTERPROCESS_CHECK(lock.timed_lock(pt));
130 BOOST_INTERPROCESS_CHECK(lock ? true : false);
131 }
132 };
133
134 template <typename M>
135 struct test_recursive_lock
136 {
137 typedef M mutex_type;
138 typedef boost::interprocess::scoped_lock<mutex_type> lock_type;
139
operator ()boost::interprocess::test::test_recursive_lock140 void operator()()
141 {
142 mutex_type mx;
143 {
144 lock_type lock1(mx);
145 lock_type lock2(mx);
146 }
147 {
148 lock_type lock1(mx, defer_lock);
149 lock_type lock2(mx, defer_lock);
150 }
151 {
152 lock_type lock1(mx, try_to_lock);
153 lock_type lock2(mx, try_to_lock);
154 }
155 {
156 //This should always lock
157 boost::posix_time::ptime pt = delay(2*BaseSeconds);
158 lock_type lock1(mx, pt);
159 lock_type lock2(mx, pt);
160 }
161 }
162 };
163
164 // plain_exclusive exercises the "infinite" lock for each
165 // read_write_mutex type.
166
167 template<typename M>
lock_and_sleep(void * arg,M & sm)168 void lock_and_sleep(void *arg, M &sm)
169 {
170 data<M> *pdata = static_cast<data<M>*>(arg);
171 boost::interprocess::scoped_lock<M> l(sm);
172 if(pdata->m_secs){
173 boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs));
174 }
175 else{
176 boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
177 }
178
179 ++shared_val;
180 pdata->m_value = shared_val;
181 }
182
183 template<typename M>
lock_and_catch_errors(void * arg,M & sm)184 void lock_and_catch_errors(void *arg, M &sm)
185 {
186 data<M> *pdata = static_cast<data<M>*>(arg);
187 try
188 {
189 boost::interprocess::scoped_lock<M> l(sm);
190 if(pdata->m_secs){
191 boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs));
192 }
193 else{
194 boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
195 }
196 ++shared_val;
197 pdata->m_value = shared_val;
198 }
199 catch(interprocess_exception const & e)
200 {
201 pdata->m_error = e.get_error_code();
202 }
203 }
204
205 template<typename M>
try_lock_and_sleep(void * arg,M & sm)206 void try_lock_and_sleep(void *arg, M &sm)
207 {
208 data<M> *pdata = static_cast<data<M>*>(arg);
209 boost::interprocess::scoped_lock<M> l(sm, boost::interprocess::defer_lock);
210 if (l.try_lock()){
211 boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
212 ++shared_val;
213 pdata->m_value = shared_val;
214 }
215 }
216
217 template<typename M>
timed_lock_and_sleep(void * arg,M & sm)218 void timed_lock_and_sleep(void *arg, M &sm)
219 {
220 data<M> *pdata = static_cast<data<M>*>(arg);
221 boost::posix_time::ptime pt(delay(pdata->m_secs));
222 boost::interprocess::scoped_lock<M>
223 l (sm, boost::interprocess::defer_lock);
224 if (l.timed_lock(pt)){
225 boost::interprocess::ipcdetail::thread_sleep((1000*2*BaseSeconds));
226 ++shared_val;
227 pdata->m_value = shared_val;
228 }
229 }
230
231 template<typename M>
test_mutex_lock()232 void test_mutex_lock()
233 {
234 shared_val = 0;
235
236 M mtx;
237
238 data<M> d1(1);
239 data<M> d2(2);
240
241 // Locker one launches, holds the lock for 2*BaseSeconds seconds.
242 boost::interprocess::ipcdetail::OS_thread_t tm1;
243 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx));
244
245 //Wait 1*BaseSeconds
246 boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
247
248 // Locker two launches, but it won't hold the lock for 2*BaseSeconds seconds.
249 boost::interprocess::ipcdetail::OS_thread_t tm2;
250 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_sleep, &d2, mtx));
251
252 //Wait completion
253
254 boost::interprocess::ipcdetail::thread_join(tm1);
255 boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
256 boost::interprocess::ipcdetail::thread_join(tm2);
257
258 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
259 BOOST_INTERPROCESS_CHECK(d2.m_value == 2);
260 }
261
262 template<typename M>
test_mutex_lock_timeout()263 void test_mutex_lock_timeout()
264 {
265 shared_val = 0;
266
267 M mtx;
268
269 int wait_time_s = BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS / 1000;
270 if (wait_time_s == 0 )
271 wait_time_s = 1;
272
273 data<M> d1(1, wait_time_s * 3);
274 data<M> d2(2, wait_time_s * 2);
275
276 // Locker one launches, and holds the lock for wait_time_s * 2 seconds.
277 boost::interprocess::ipcdetail::OS_thread_t tm1;
278 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx));
279
280 //Wait 1*BaseSeconds
281 boost::interprocess::ipcdetail::thread_sleep((1000*wait_time_s));
282
283 // Locker two launches, and attempts to hold the lock for wait_time_s * 2 seconds.
284 boost::interprocess::ipcdetail::OS_thread_t tm2;
285 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_catch_errors, &d2, mtx));
286
287 //Wait completion
288 boost::interprocess::ipcdetail::thread_join(tm1);
289 boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
290 boost::interprocess::ipcdetail::thread_join(tm2);
291
292 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
293 BOOST_INTERPROCESS_CHECK(d2.m_value == -1);
294 BOOST_INTERPROCESS_CHECK(d1.m_error == no_error);
295 BOOST_INTERPROCESS_CHECK(d2.m_error == boost::interprocess::timeout_when_locking_error);
296 }
297
298 template<typename M>
test_mutex_try_lock()299 void test_mutex_try_lock()
300 {
301 shared_val = 0;
302
303 M mtx;
304
305 data<M> d1(1);
306 data<M> d2(2);
307
308 // Locker one launches, holds the lock for 2*BaseSeconds seconds.
309 boost::interprocess::ipcdetail::OS_thread_t tm1;
310 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&try_lock_and_sleep, &d1, mtx));
311
312 //Wait 1*BaseSeconds
313 boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
314
315 // Locker two launches, but it should fail acquiring the lock
316 boost::interprocess::ipcdetail::OS_thread_t tm2;
317 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&try_lock_and_sleep, &d2, mtx));
318
319 //Wait completion
320 boost::interprocess::ipcdetail::thread_join(tm1);
321 boost::interprocess::ipcdetail::thread_join(tm2);
322
323 //Only the first should succeed locking
324 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
325 BOOST_INTERPROCESS_CHECK(d2.m_value == -1);
326 }
327
328 template<typename M>
test_mutex_timed_lock()329 void test_mutex_timed_lock()
330
331 {
332 shared_val = 0;
333
334 M mtx, m2;
335
336 data<M> d1(1, 2*BaseSeconds);
337 data<M> d2(2, 2*BaseSeconds);
338
339 // Locker one launches, holds the lock for 2*BaseSeconds seconds.
340 boost::interprocess::ipcdetail::OS_thread_t tm1;
341 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&timed_lock_and_sleep, &d1, mtx));
342
343 //Wait 1*BaseSeconds
344 boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
345
346 // Locker two launches, holds the lock for 2*BaseSeconds seconds.
347 boost::interprocess::ipcdetail::OS_thread_t tm2;
348 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&timed_lock_and_sleep, &d2, mtx));
349
350 //Wait completion
351 boost::interprocess::ipcdetail::thread_join(tm1);
352 boost::interprocess::ipcdetail::thread_join(tm2);
353
354 //Both should succeed locking
355 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
356 BOOST_INTERPROCESS_CHECK(d2.m_value == 2);
357 }
358
359 template <typename M>
test_all_lock()360 inline void test_all_lock()
361 {
362 //Now generic interprocess_mutex tests
363 std::cout << "test_lock<" << typeid(M).name() << ">" << std::endl;
364 test_lock<M>()();
365 std::cout << "test_trylock<" << typeid(M).name() << ">" << std::endl;
366 test_trylock<M>()();
367 std::cout << "test_timedlock<" << typeid(M).name() << ">" << std::endl;
368 test_timedlock<M>()();
369 }
370
371 template <typename M>
test_all_recursive_lock()372 inline void test_all_recursive_lock()
373 {
374 //Now generic interprocess_mutex tests
375 std::cout << "test_recursive_lock<" << typeid(M).name() << ">" << std::endl;
376 test_recursive_lock<M>()();
377 }
378
379 template<typename M>
test_all_mutex()380 void test_all_mutex()
381 {
382 std::cout << "test_mutex_lock<" << typeid(M).name() << ">" << std::endl;
383 test_mutex_lock<M>();
384 std::cout << "test_mutex_try_lock<" << typeid(M).name() << ">" << std::endl;
385 test_mutex_try_lock<M>();
386 std::cout << "test_mutex_timed_lock<" << typeid(M).name() << ">" << std::endl;
387 test_mutex_timed_lock<M>();
388 }
389
390 }}} //namespace boost { namespace interprocess { namespace test {
391
392 #include <boost/interprocess/detail/config_end.hpp>
393
394 #endif //BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER
395