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 <typeinfo>
31#include <iostream>
32
33namespace boost { namespace interprocess { namespace test {
34
35template <typename M>
36struct test_lock
37{
38 typedef M mutex_type;
39 typedef boost::interprocess::scoped_lock<mutex_type> lock_type;
40
41
42 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
62template <typename M>
63struct test_trylock
64{
65 typedef M mutex_type;
66 typedef boost::interprocess::scoped_lock<mutex_type> try_to_lock_type;
67
68 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
96template <typename M>
97struct test_timedlock
98{
99 typedef M mutex_type;
100 typedef boost::interprocess::scoped_lock<mutex_type> timed_lock_type;
101
102 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 timed_lock_type lock(interprocess_mutex, ptime_delay_ms(msecs: unsigned(1*BaseMs)));
110 BOOST_INTERPROCESS_CHECK(lock ? true : false);
111 }
112 {
113 timed_lock_type lock(interprocess_mutex, boost::interprocess::defer_lock);
114 BOOST_INTERPROCESS_CHECK(!lock);
115 }
116 timed_lock_type lock(interprocess_mutex);
117 BOOST_INTERPROCESS_CHECK(lock ? true : false);
118
119 // Test the lock, unlock and timedlock methods.
120 lock.unlock();
121 BOOST_INTERPROCESS_CHECK(!lock);
122 lock.lock();
123 BOOST_INTERPROCESS_CHECK(lock ? true : false);
124 lock.unlock();
125 BOOST_INTERPROCESS_CHECK(!lock);
126 BOOST_INTERPROCESS_CHECK(lock.timed_lock(boost_systemclock_delay_ms(1*BaseMs)));
127 BOOST_INTERPROCESS_CHECK(lock ? true : false);
128 }
129};
130
131template <class Lock, class Mutex, class TimePoint>
132void lock_twice_timed(Mutex& mx, const TimePoint& pt)
133{
134 Lock lock1(mx, pt);
135 Lock lock2(mx, pt);
136}
137
138template <typename M>
139struct test_recursive_lock
140{
141 typedef M mutex_type;
142 typedef boost::interprocess::scoped_lock<mutex_type> lock_type;
143
144 void operator()()
145 {
146 mutex_type mx;
147 {
148 lock_type lock1(mx);
149 lock_type lock2(mx);
150 }
151 {
152 lock_type lock1(mx, defer_lock);
153 lock_type lock2(mx, defer_lock);
154 }
155 {
156 lock_type lock1(mx, try_to_lock);
157 lock_type lock2(mx, try_to_lock);
158 }
159 {
160 //This should always lock
161 lock_twice_timed<lock_type>(mx, ptime_delay_ms(msecs: 2*BaseMs));
162 }
163 {
164 //This should always lock
165 lock_twice_timed<lock_type>(mx, boost_systemclock_delay_ms(msecs: 2*BaseMs));
166 }
167 {
168 //This should always lock
169 lock_twice_timed<lock_type>(mx, std_systemclock_delay_ms(msecs: 2*BaseMs));
170 }
171 }
172};
173
174// plain_exclusive exercises the "infinite" lock for each
175// read_write_mutex type.
176
177template<typename M>
178void lock_and_sleep(void *arg, M &sm)
179{
180 data<M> *pdata = static_cast<data<M>*>(arg);
181 boost::interprocess::scoped_lock<M> l(sm);
182 if(pdata->m_msecs){
183 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(pdata->m_msecs));
184 }
185 else{
186 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(2*BaseMs));
187 }
188
189 ++shared_val;
190 pdata->m_value = shared_val;
191}
192
193template<typename M>
194void lock_and_catch_errors(void *arg, M &sm)
195{
196 BOOST_TRY
197 {
198 lock_and_sleep(arg, sm);
199 }
200 BOOST_CATCH(interprocess_exception const & e)
201 {
202 data<M>* pdata = static_cast<data<M>*>(arg);
203 pdata->m_error = e.get_error_code();
204 } BOOST_CATCH_END
205}
206
207template<typename M>
208void try_lock_and_sleep(void *arg, M &sm)
209{
210 data<M> *pdata = static_cast<data<M>*>(arg);
211 boost::interprocess::scoped_lock<M> l(sm, boost::interprocess::defer_lock);
212 if (l.try_lock()){
213 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(2*BaseMs));
214 ++shared_val;
215 pdata->m_value = shared_val;
216 }
217}
218
219enum ETimedLockFlags
220{
221 TimedLock = 0,
222 TryLockUntil = 1,
223 TryLockFor = 2,
224 ETimedLockFlagsMax
225};
226
227template<typename M>
228void timed_lock_and_sleep(void *arg, M &sm)
229{
230 data<M> *pdata = static_cast<data<M>*>(arg);
231 boost::interprocess::scoped_lock<M>
232 l (sm, boost::interprocess::defer_lock);
233 bool r = false;
234 if(pdata->m_flags == (int)TimedLock){
235 r = l.timed_lock(std_systemclock_delay_ms(msecs: unsigned(pdata->m_msecs)));
236 }
237 else if (pdata->m_flags == (int)TryLockUntil) {
238 r = l.try_lock_until(ptime_delay_ms(msecs: unsigned(pdata->m_msecs)));
239 }
240 else if (pdata->m_flags == (int)TryLockFor) {
241 r = l.try_lock_for(boost_systemclock_ms(msecs: unsigned(pdata->m_msecs)));
242 }
243
244 if (r){
245 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(2*BaseMs));
246 ++shared_val;
247 pdata->m_value = shared_val;
248 }
249}
250
251template<typename M>
252void test_mutex_lock()
253{
254 shared_val = 0;
255
256 M mtx;
257
258 data<M> d1(1);
259 data<M> d2(2);
260
261 // Locker one launches, holds the lock for 2*BaseMs seconds.
262 boost::interprocess::ipcdetail::OS_thread_t tm1;
263 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx));
264
265 //Wait 1*BaseMs
266 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
267
268 // Locker two launches, but it won't hold the lock for 2*BaseMs seconds.
269 boost::interprocess::ipcdetail::OS_thread_t tm2;
270 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_sleep, &d2, mtx));
271
272 //Wait completion
273 boost::interprocess::ipcdetail::thread_join(thread: tm1);
274 boost::interprocess::ipcdetail::thread_join(thread: tm2);
275
276 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
277 BOOST_INTERPROCESS_CHECK(d2.m_value == 2);
278}
279
280template<typename M>
281void test_mutex_lock_timeout()
282{
283 shared_val = 0;
284
285 M mtx;
286
287 unsigned wait_time_ms = BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS;
288
289 data<M> d1(1, (int)wait_time_ms * 3);
290 data<M> d2(2, (int)wait_time_ms * 1);
291
292 // Locker one launches, and holds the lock for wait_time_ms * 3.
293 boost::interprocess::ipcdetail::OS_thread_t tm1;
294 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&lock_and_sleep, &d1, mtx));
295
296 //Wait until tm1 acquires the lock
297 boost::interprocess::ipcdetail::thread_sleep_ms(ms: wait_time_ms);
298
299 // Locker two launches, and attempts to hold the lock for wait_time_ms * 2.
300 boost::interprocess::ipcdetail::OS_thread_t tm2;
301 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&lock_and_catch_errors, &d2, mtx));
302
303 //Wait completion
304 boost::interprocess::ipcdetail::thread_join(thread: tm2);
305 boost::interprocess::ipcdetail::thread_join(thread: tm1);
306
307 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
308 BOOST_INTERPROCESS_CHECK(d2.m_value == -1);
309 BOOST_INTERPROCESS_CHECK(d1.m_error == no_error);
310 BOOST_INTERPROCESS_CHECK(d2.m_error == boost::interprocess::timeout_when_locking_error);
311}
312
313template<typename M>
314void test_mutex_try_lock()
315{
316 shared_val = 0;
317
318 M mtx;
319
320 data<M> d1(1);
321 data<M> d2(2);
322
323 // Locker one launches, holds the lock for 2*BaseMs seconds.
324 boost::interprocess::ipcdetail::OS_thread_t tm1;
325 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&try_lock_and_sleep, &d1, mtx));
326
327 //Wait 1*BaseMs
328 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
329
330 // Locker two launches, but it should fail acquiring the lock
331 boost::interprocess::ipcdetail::OS_thread_t tm2;
332 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&try_lock_and_sleep, &d2, mtx));
333
334 //Wait completion
335 boost::interprocess::ipcdetail::thread_join(thread: tm1);
336 boost::interprocess::ipcdetail::thread_join(thread: tm2);
337
338 //Only the first should succeed locking
339 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
340 BOOST_INTERPROCESS_CHECK(d2.m_value == -1);
341}
342
343template<typename M>
344void test_mutex_timed_lock()
345{
346 for (int flag = 0; flag != (int)ETimedLockFlagsMax; ++flag)
347 {
348 //int flag = 2;
349 shared_val = 0;
350
351 M mtx, m2;
352
353 data<M> d1(1, 2*BaseMs, flag);
354 data<M> d2(2, 2*BaseMs, flag);
355
356 // Locker one launches, holds the lock for 2*BaseMs seconds.
357 boost::interprocess::ipcdetail::OS_thread_t tm1;
358 boost::interprocess::ipcdetail::thread_launch(tm1, thread_adapter<M>(&timed_lock_and_sleep, &d1, mtx));
359
360 //Wait 1*BaseMs
361 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
362
363 // Locker two launches, holds the lock for 2*BaseMs seconds.
364 boost::interprocess::ipcdetail::OS_thread_t tm2;
365 boost::interprocess::ipcdetail::thread_launch(tm2, thread_adapter<M>(&timed_lock_and_sleep, &d2, mtx));
366
367 //Wait completion
368 boost::interprocess::ipcdetail::thread_join(thread: tm1);
369 boost::interprocess::ipcdetail::thread_join(thread: tm2);
370
371 //Both should succeed locking
372 BOOST_INTERPROCESS_CHECK(d1.m_value == 1);
373 BOOST_INTERPROCESS_CHECK(d2.m_value == 2);
374 }
375}
376
377template <typename M>
378inline void test_all_lock()
379{
380 //Now generic interprocess_mutex tests
381 std::cout << "test_lock<" << typeid(M).name() << ">" << std::endl;
382 test_lock<M>()();
383 std::cout << "test_trylock<" << typeid(M).name() << ">" << std::endl;
384 test_trylock<M>()();
385 std::cout << "test_timedlock<" << typeid(M).name() << ">" << std::endl;
386 test_timedlock<M>()();
387}
388
389template <typename M>
390inline void test_all_recursive_lock()
391{
392 //Now generic interprocess_mutex tests
393 std::cout << "test_recursive_lock<" << typeid(M).name() << ">" << std::endl;
394 test_recursive_lock<M>()();
395}
396
397template<typename M>
398void test_all_mutex()
399{
400 std::cout << "test_mutex_lock<" << typeid(M).name() << ">" << std::endl;
401 test_mutex_lock<M>();
402 std::cout << "test_mutex_try_lock<" << typeid(M).name() << ">" << std::endl;
403 test_mutex_try_lock<M>();
404 std::cout << "test_mutex_timed_lock<" << typeid(M).name() << ">" << std::endl;
405 test_mutex_timed_lock<M>();
406}
407
408}}} //namespace boost { namespace interprocess { namespace test {
409
410#include <boost/interprocess/detail/config_end.hpp>
411
412#endif //BOOST_INTERPROCESS_TEST_MUTEX_TEST_TEMPLATE_HEADER
413

source code of boost/libs/interprocess/test/mutex_test_template.hpp