f298fb8b46c143d3a9c43da5829b5893454de33b
[platform/upstream/boost.git] / libs / interprocess / test / mutex_test_template.hpp
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
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
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
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
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
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          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
140    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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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