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/interprocess/sync/sharable_lock.hpp>
30#include <boost/interprocess/sync/scoped_lock.hpp>
31#include <iostream>
32#include <cassert>
33#include "util.hpp"
34#include <typeinfo>
35
36namespace boost { namespace interprocess { namespace test {
37
38template<typename SM>
39void 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_ms(ms: unsigned(3*BaseMs));
44 shared_val += 10;
45 pdata->m_value = shared_val;
46}
47
48template<typename SM>
49void 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_msecs){
54 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(pdata->m_msecs));
55 }
56 pdata->m_value = shared_val;
57}
58
59template<typename SM>
60void 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_ms(ms: unsigned(3*BaseMs));
66 shared_val += 10;
67 pdata->m_value = shared_val;
68 }
69}
70
71template<typename SM>
72void 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_msecs){
78 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(pdata->m_msecs));
79 }
80 pdata->m_value = shared_val;
81 }
82}
83
84template<typename SM>
85void test_plain_sharable_mutex()
86{
87 {
88 shared_val = 0;
89 SM mtx;
90 data<SM> e1(1);
91 data<SM> e2(2);
92 data<SM> s1(1);
93 data<SM> s2(2);
94
95 // Writer one launches, holds the lock for 3*BaseMs seconds.
96 boost::interprocess::ipcdetail::OS_thread_t tw1;
97 boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(plain_exclusive, &e1, mtx));
98
99 //Give time to e1 to grab the mutex
100 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
101
102 // Writer two launches, tries to grab the lock, "clearly"
103 // after Writer one will already be holding it.
104 boost::interprocess::ipcdetail::OS_thread_t tw2;
105 boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(plain_exclusive, &e2, mtx));
106
107 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
108
109 // Readers launche, "clearly" after writer two, and "clearly"
110 // while writer 1 still holds the lock
111 boost::interprocess::ipcdetail::OS_thread_t thr1;
112 boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(plain_shared,&s1, mtx));
113 boost::interprocess::ipcdetail::OS_thread_t thr2;
114 boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(plain_shared,&s2, mtx));
115
116 boost::interprocess::ipcdetail::thread_join(thread: thr2);
117 boost::interprocess::ipcdetail::thread_join(thread: thr1);
118 boost::interprocess::ipcdetail::thread_join(thread: tw2);
119 boost::interprocess::ipcdetail::thread_join(thread: tw1);
120
121 //We can only assure that the writer will be first
122 BOOST_INTERPROCESS_CHECK(e1.m_value == 10);
123 //A that we will execute all
124 BOOST_INTERPROCESS_CHECK(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20);
125 }
126
127 {
128 shared_val = 0;
129 SM mtx;
130
131 data<SM> s1(1, 3);
132 data<SM> s2(2, 3);
133 data<SM> e1(1);
134 data<SM> e2(2);
135
136 //We launch 2 readers, that will block for 3*BaseTime seconds
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 //Make sure they try to hold the sharable lock
143 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
144
145 // We launch two writers, that should block until the readers end
146 boost::interprocess::ipcdetail::OS_thread_t tw1;
147 boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(plain_exclusive,&e1, mtx));
148
149 boost::interprocess::ipcdetail::OS_thread_t tw2;
150 boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(plain_exclusive,&e2, mtx));
151
152 boost::interprocess::ipcdetail::thread_join(thread: tw2);
153 boost::interprocess::ipcdetail::thread_join(thread: tw1);
154 boost::interprocess::ipcdetail::thread_join(thread: thr2);
155 boost::interprocess::ipcdetail::thread_join(thread: thr1);
156
157 //We can only assure that the shared will finish first...
158 BOOST_INTERPROCESS_CHECK(s1.m_value == 0 || s2.m_value == 0);
159 //...and writers will be mutually excluded after readers
160 BOOST_INTERPROCESS_CHECK((e1.m_value == 10 && e2.m_value == 20) ||
161 (e1.m_value == 20 && e2.m_value == 10) );
162 }
163}
164
165template<typename SM>
166void test_try_sharable_mutex()
167{
168 SM mtx;
169
170 data<SM> s1(1);
171 data<SM> e1(2);
172 data<SM> e2(3);
173
174 // We start with some specialized tests for "try" behavior
175 shared_val = 0;
176
177 // Writer one launches, holds the lock for 3*BaseMs seconds.
178 boost::interprocess::ipcdetail::OS_thread_t tw1;
179 boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(try_exclusive,&e1,mtx));
180
181 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
182
183 // Reader one launches, "clearly" after writer #1 holds the lock
184 // and before it releases the lock.
185 boost::interprocess::ipcdetail::OS_thread_t thr1;
186 boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(try_shared,&s1,mtx));
187
188 // Writer two launches in the same timeframe.
189 boost::interprocess::ipcdetail::OS_thread_t tw2;
190 boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(try_exclusive,&e2,mtx));
191
192 boost::interprocess::ipcdetail::thread_join(thread: tw2);
193 boost::interprocess::ipcdetail::thread_join(thread: thr1);
194 boost::interprocess::ipcdetail::thread_join(thread: tw1);
195
196 BOOST_INTERPROCESS_CHECK(e1.m_value == 10);
197 BOOST_INTERPROCESS_CHECK(s1.m_value == -1); // Try would return w/o waiting
198 BOOST_INTERPROCESS_CHECK(e2.m_value == -1); // Try would return w/o waiting
199}
200
201template<typename SM>
202void timed_exclusive(void *arg, SM &sm)
203{
204 data<SM> *pdata = static_cast<data<SM>*>(arg);
205 boost::interprocess::scoped_lock<SM>
206 l (sm, boost::interprocess::defer_lock);
207
208 bool r = false;
209 if(pdata->m_flags == (int)TimedLock){
210 r = l.timed_lock(std_systemclock_delay_ms(msecs: unsigned(pdata->m_msecs)));
211 }
212 else if (pdata->m_flags == (int)TryLockUntil) {
213 r = l.try_lock_until(ptime_delay_ms(msecs: unsigned(pdata->m_msecs)));
214 }
215 else if (pdata->m_flags == (int)TryLockFor) {
216 r = l.try_lock_for(boost_systemclock_ms(msecs: unsigned(pdata->m_msecs)));
217 }
218
219 if (r){
220 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(3*BaseMs));
221 shared_val += 10;
222 pdata->m_value = shared_val;
223 }
224}
225
226template<typename SM>
227void timed_shared(void *arg, SM &sm)
228{
229 data<SM> *pdata = static_cast<data<SM>*>(arg);
230 boost::interprocess::sharable_lock<SM>
231 l(sm, boost::interprocess::defer_lock);
232
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(3*BaseMs));
246 pdata->m_value = shared_val;
247 }
248}
249
250template<typename SM>
251void test_timed_sharable_mutex()
252{
253 for (int flag = 0; flag != (int)ETimedLockFlagsMax; ++flag)
254 {
255 SM mtx;
256 data<SM> e1(3, 3*BaseMs, flag);
257 data<SM> e2(4, 1*BaseMs, flag);
258 data<SM> s1(1, 1*BaseMs, flag);
259 data<SM> s2(2, 3*BaseMs, flag);
260
261 // We begin with some specialized tests for "timed" behavior
262
263 shared_val = 0;
264
265 // Writer one will hold the lock for 3*BaseMs seconds.
266 boost::interprocess::ipcdetail::OS_thread_t tw1;
267 boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter<SM>(timed_exclusive,&e1,mtx));
268
269 boost::interprocess::ipcdetail::thread_sleep_ms(ms: unsigned(1*BaseMs));
270 // Writer two will "clearly" try for the lock after the readers
271 // have tried for it. Writer will wait up 1*BaseMs seconds for the lock.
272 // This write will fail.
273 boost::interprocess::ipcdetail::OS_thread_t tw2;
274 boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter<SM>(timed_exclusive,&e2,mtx));
275
276 // Readers one and two will "clearly" try for the lock after writer
277 // one already holds it. 1st reader will wait 1*BaseMs seconds, and will fail
278 // to get the lock. 2nd reader will wait 3*BaseMs seconds, and will get
279 // the lock.
280
281 boost::interprocess::ipcdetail::OS_thread_t thr1;
282 boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter<SM>(timed_shared,&s1,mtx));
283
284 boost::interprocess::ipcdetail::OS_thread_t thr2;
285 boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter<SM>(timed_shared,&s2,mtx));
286
287 boost::interprocess::ipcdetail::thread_join(thread: thr2);
288 boost::interprocess::ipcdetail::thread_join(thread: thr1);
289 boost::interprocess::ipcdetail::thread_join(thread: tw2);
290 boost::interprocess::ipcdetail::thread_join(thread: tw1);
291
292 BOOST_INTERPROCESS_CHECK(e1.m_value == 10);
293 BOOST_INTERPROCESS_CHECK(e2.m_value == -1);
294 BOOST_INTERPROCESS_CHECK(s1.m_value == -1);
295 BOOST_INTERPROCESS_CHECK(s2.m_value == 10);
296 }
297}
298
299template<typename SM>
300void test_all_sharable_mutex()
301{
302 std::cout << "test_plain_sharable_mutex<" << typeid(SM).name() << ">" << std::endl;
303 test_plain_sharable_mutex<SM>();
304
305 std::cout << "test_try_sharable_mutex<" << typeid(SM).name() << ">" << std::endl;
306 test_try_sharable_mutex<SM>();
307
308 std::cout << "test_timed_sharable_mutex<" << typeid(SM).name() << ">" << std::endl;
309 test_timed_sharable_mutex<SM>();
310}
311
312
313}}} //namespace boost { namespace interprocess { namespace test {
314
315#include <boost/interprocess/detail/config_end.hpp>
316
317#endif //#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER
318

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