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