1 // Copyright (C) 2001-2003
2 // William E. Kempf
3 //
4 // Permission to use, copy, modify, distribute and sell this software
5 // and its documentation for any purpose is hereby granted without fee,
6 // provided that the above copyright notice appear in all copies and
7 // that both that copyright notice and this permission notice appear
8 // in supporting documentation.  William E. Kempf makes no representations
9 // about the suitability of this software for any purpose.
10 // It is provided "as is" without express or implied warranty.
11 //////////////////////////////////////////////////////////////////////////////
12 //
13 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
14 // Software License, Version 1.0. (See accompanying file
15 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
16 //
17 // See http://www.boost.org/libs/interprocess for documentation.
18 //
19 //////////////////////////////////////////////////////////////////////////////
20 
21 #ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER
22 #define BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER
23 
24 #include <boost/interprocess/detail/config_begin.hpp>
25 #include <boost/interprocess/detail/workaround.hpp>
26 
27 #include <boost/interprocess/detail/os_thread_functions.hpp>
28 #include "boost_interprocess_check.hpp"
29 #include <boost/date_time/posix_time/posix_time_types.hpp>
30 #include <boost/interprocess/sync/sharable_lock.hpp>
31 #include <boost/interprocess/sync/scoped_lock.hpp>
32 #include <iostream>
33 #include <cassert>
34 #include "util.hpp"
35 
36 namespace boost { namespace interprocess { namespace test {
37 
38 template<typename SM>
plain_exclusive(void * arg,SM & sm)39 void plain_exclusive(void *arg, SM &sm)
40 {
41    data<SM> *pdata = static_cast<data<SM>*>(arg);
42    boost::interprocess::scoped_lock<SM> l(sm);
43    boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds));
44    shared_val += 10;
45    pdata->m_value = shared_val;
46 }
47 
48 template<typename SM>
plain_shared(void * arg,SM & sm)49 void plain_shared(void *arg, SM &sm)
50 {
51    data<SM> *pdata = static_cast<data<SM>*>(arg);
52    boost::interprocess::sharable_lock<SM> l(sm);
53    if(pdata->m_secs){
54       boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds));
55    }
56    pdata->m_value = shared_val;
57 }
58 
59 template<typename SM>
try_exclusive(void * arg,SM & sm)60 void try_exclusive(void *arg, SM &sm)
61 {
62    data<SM> *pdata = static_cast<data<SM>*>(arg);
63    boost::interprocess::scoped_lock<SM> l(sm, boost::interprocess::defer_lock);
64    if (l.try_lock()){
65       boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds));
66       shared_val += 10;
67       pdata->m_value = shared_val;
68    }
69 }
70 
71 template<typename SM>
try_shared(void * arg,SM & sm)72 void try_shared(void *arg, SM &sm)
73 {
74    data<SM> *pdata = static_cast<data<SM>*>(arg);
75    boost::interprocess::sharable_lock<SM> l(sm, boost::interprocess::defer_lock);
76    if (l.try_lock()){
77       if(pdata->m_secs){
78          boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds));
79       }
80       pdata->m_value = shared_val;
81    }
82 }
83 
84 template<typename SM>
timed_exclusive(void * arg,SM & sm)85 void timed_exclusive(void *arg, SM &sm)
86 {
87    data<SM> *pdata = static_cast<data<SM>*>(arg);
88    boost::posix_time::ptime pt(delay(pdata->m_secs));
89    boost::interprocess::scoped_lock<SM>
90       l (sm, boost::interprocess::defer_lock);
91    if (l.timed_lock(pt)){
92       boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds));
93       shared_val += 10;
94       pdata->m_value = shared_val;
95    }
96 }
97 
98 template<typename SM>
timed_shared(void * arg,SM & sm)99 void timed_shared(void *arg, SM &sm)
100 {
101    data<SM> *pdata = static_cast<data<SM>*>(arg);
102    boost::posix_time::ptime pt(delay(pdata->m_secs));
103    boost::interprocess::sharable_lock<SM>
104       l(sm, boost::interprocess::defer_lock);
105    if (l.timed_lock(pt)){
106       if(pdata->m_secs){
107          boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds));
108       }
109       pdata->m_value = shared_val;
110    }
111 }
112 
113 template<typename SM>
test_plain_sharable_mutex()114 void test_plain_sharable_mutex()
115 {
116    {
117       shared_val = 0;
118       SM mtx;
119       data<SM> s1(1);
120       data<SM> s2(2);
121       data<SM> e1(1);
122       data<SM> e2(2);
123 
124       // Writer one launches, holds the lock for 3*BaseSeconds seconds.
125       boost::interprocess::ipcdetail::OS_thread_t tw1;
126       boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(plain_exclusive, &e1, mtx));
127 
128       // Writer two launches, tries to grab the lock, "clearly"
129       //  after Writer one will already be holding it.
130       boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
131       boost::interprocess::ipcdetail::OS_thread_t tw2;
132       boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(plain_exclusive, &e2, mtx));
133 
134       // Reader one launches, "clearly" after writer two, and "clearly"
135       //   while writer 1 still holds the lock
136       boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
137       boost::interprocess::ipcdetail::OS_thread_t thr1;
138       boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(plain_shared,&s1, mtx));
139       boost::interprocess::ipcdetail::OS_thread_t thr2;
140       boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(plain_shared,&s2, mtx));
141 
142       boost::interprocess::ipcdetail::thread_join(thr2);
143       boost::interprocess::ipcdetail::thread_join(thr1);
144       boost::interprocess::ipcdetail::thread_join(tw2);
145       boost::interprocess::ipcdetail::thread_join(tw1);
146 
147       //We can only assure that the writer will be first
148       BOOST_INTERPROCESS_CHECK(e1.m_value == 10);
149       //A that we will execute all
150       BOOST_INTERPROCESS_CHECK(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20);
151    }
152 
153    {
154       shared_val = 0;
155       SM mtx;
156 
157       data<SM> s1(1, 3);
158       data<SM> s2(2, 3);
159       data<SM> e1(1);
160       data<SM> e2(2);
161 
162       //We launch 2 readers, that will block for 3*BaseTime seconds
163       boost::interprocess::ipcdetail::OS_thread_t thr1;
164       boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(plain_shared,&s1, mtx));
165       boost::interprocess::ipcdetail::OS_thread_t thr2;
166       boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(plain_shared,&s2, mtx));
167 
168       //Make sure they try to hold the sharable lock
169       boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
170 
171       // We launch two writers, that should block until the readers end
172       boost::interprocess::ipcdetail::OS_thread_t tw1;
173       boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(plain_exclusive,&e1, mtx));
174 
175       boost::interprocess::ipcdetail::OS_thread_t tw2;
176       boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(plain_exclusive,&e2, mtx));
177 
178       boost::interprocess::ipcdetail::thread_join(thr2);
179       boost::interprocess::ipcdetail::thread_join(thr1);
180       boost::interprocess::ipcdetail::thread_join(tw2);
181       boost::interprocess::ipcdetail::thread_join(tw1);
182 
183       //We can only assure that the shared will finish first...
184       BOOST_INTERPROCESS_CHECK(s1.m_value == 0 || s2.m_value == 0);
185       //...and writers will be mutually excluded after readers
186       BOOST_INTERPROCESS_CHECK((e1.m_value == 10 && e2.m_value == 20) ||
187              (e1.m_value == 20 && e2.m_value == 10) );
188    }
189 }
190 
191 template<typename SM>
test_try_sharable_mutex()192 void test_try_sharable_mutex()
193 {
194    SM mtx;
195 
196    data<SM> s1(1);
197    data<SM> e1(2);
198    data<SM> e2(3);
199 
200    // We start with some specialized tests for "try" behavior
201 
202    shared_val = 0;
203 
204    // Writer one launches, holds the lock for 3*BaseSeconds seconds.
205    boost::interprocess::ipcdetail::OS_thread_t tw1;
206    boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(try_exclusive,&e1,mtx));
207 
208    // Reader one launches, "clearly" after writer #1 holds the lock
209    //   and before it releases the lock.
210    boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
211    boost::interprocess::ipcdetail::OS_thread_t thr1;
212    boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(try_shared,&s1,mtx));
213 
214    // Writer two launches in the same timeframe.
215    boost::interprocess::ipcdetail::OS_thread_t tw2;
216    boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(try_exclusive,&e2,mtx));
217 
218    boost::interprocess::ipcdetail::thread_join(tw2);
219    boost::interprocess::ipcdetail::thread_join(thr1);
220    boost::interprocess::ipcdetail::thread_join(tw1);
221 
222    BOOST_INTERPROCESS_CHECK(e1.m_value == 10);
223    BOOST_INTERPROCESS_CHECK(s1.m_value == -1);        // Try would return w/o waiting
224    BOOST_INTERPROCESS_CHECK(e2.m_value == -1);        // Try would return w/o waiting
225 }
226 
227 template<typename SM>
test_timed_sharable_mutex()228 void test_timed_sharable_mutex()
229 {
230    SM mtx;
231    data<SM> s1(1,1*BaseSeconds);
232    data<SM> s2(2,3*BaseSeconds);
233    data<SM> e1(3,3*BaseSeconds);
234    data<SM> e2(4,1*BaseSeconds);
235 
236    // We begin with some specialized tests for "timed" behavior
237 
238    shared_val = 0;
239 
240    // Writer one will hold the lock for 3*BaseSeconds seconds.
241    boost::interprocess::ipcdetail::OS_thread_t tw1;
242    boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(timed_exclusive,&e1,mtx));
243 
244    boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds));
245    // Writer two will "clearly" try for the lock after the readers
246    //  have tried for it.  Writer will wait up 1*BaseSeconds seconds for the lock.
247    //  This write will fail.
248    boost::interprocess::ipcdetail::OS_thread_t tw2;
249    boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(timed_exclusive,&e2,mtx));
250 
251    // Readers one and two will "clearly" try for the lock after writer
252    //   one already holds it.  1st reader will wait 1*BaseSeconds seconds, and will fail
253    //   to get the lock.  2nd reader will wait 3*BaseSeconds seconds, and will get
254    //   the lock.
255 
256    boost::interprocess::ipcdetail::OS_thread_t thr1;
257    boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(timed_shared,&s1,mtx));
258 
259    boost::interprocess::ipcdetail::OS_thread_t thr2;
260    boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(timed_shared,&s2,mtx));
261 
262    boost::interprocess::ipcdetail::thread_join(tw1);
263    boost::interprocess::ipcdetail::thread_join(thr1);
264    boost::interprocess::ipcdetail::thread_join(thr2);
265    boost::interprocess::ipcdetail::thread_join(tw2);
266 
267    BOOST_INTERPROCESS_CHECK(e1.m_value == 10);
268    BOOST_INTERPROCESS_CHECK(s1.m_value == -1);
269    BOOST_INTERPROCESS_CHECK(s2.m_value == 10);
270    BOOST_INTERPROCESS_CHECK(e2.m_value == -1);
271 }
272 
273 template<typename SM>
test_all_sharable_mutex()274 void test_all_sharable_mutex()
275 {
276    std::cout << "test_plain_sharable_mutex<" << typeid(SM).name() << ">" << std::endl;
277    test_plain_sharable_mutex<SM>();
278 
279    std::cout << "test_try_sharable_mutex<" << typeid(SM).name() << ">" << std::endl;
280    test_try_sharable_mutex<SM>();
281 
282    std::cout << "test_timed_sharable_mutex<" << typeid(SM).name() << ">" << std::endl;
283    test_timed_sharable_mutex<SM>();
284 }
285 
286 
287 }}}   //namespace boost { namespace interprocess { namespace test {
288 
289 #include <boost/interprocess/detail/config_end.hpp>
290 
291 #endif   //#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER
292