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#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
21#define BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
22
23#include <boost/interprocess/detail/config_begin.hpp>
24#include <boost/interprocess/detail/workaround.hpp>
25#include <boost/interprocess/detail/os_thread_functions.hpp>
26#include "boost_interprocess_check.hpp"
27#include <boost/interprocess/sync/scoped_lock.hpp>
28#include "util.hpp"
29#include <iostream>
30#include <typeinfo>
31
32namespace boost{
33namespace interprocess{
34namespace test {
35
36template <typename F, typename T>
37class binder
38{
39public:
40 binder(const F& f, const T& p)
41 : func(f), param(p) { }
42 void operator()() const { func(param); }
43
44private:
45 F func;
46 T param;
47};
48
49template <typename F, typename T>
50binder<F, T> bind_function(F func, T param)
51{
52 return binder<F, T>(func, param);
53}
54
55template <class Condition, class Mutex>
56struct condition_test_data
57{
58 condition_test_data() : notified(0), awoken(0) { }
59
60 ~condition_test_data()
61 {}
62
63 Mutex mutex;
64 Condition condition;
65 int notified;
66 int awoken;
67};
68
69template <class Condition, class Mutex>
70void condition_test_thread(condition_test_data<Condition, Mutex>* data)
71{
72 boost::interprocess::scoped_lock<Mutex>
73 lock(data->mutex);
74 BOOST_INTERPROCESS_CHECK(lock ? true : false);
75 while (!(data->notified > 0))
76 data->condition.wait(lock);
77 BOOST_INTERPROCESS_CHECK(lock ? true : false);
78 data->awoken++;
79}
80
81struct cond_predicate
82{
83 cond_predicate(int& var, int val) : _var(var), _val(val) { }
84
85 bool operator()() { return _var == _val; }
86
87 int& _var;
88 int _val;
89};
90
91
92
93template <class Condition, class Mutex>
94void do_test_condition_notify_one()
95{
96 condition_test_data<Condition, Mutex> data;
97
98 boost::interprocess::ipcdetail::OS_thread_t thread;
99 boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_thread<Condition, Mutex>, &data));
100 //Make sure thread is blocked
101 boost::interprocess::ipcdetail::thread_sleep_ms(ms: 1*BaseMs);
102 {
103 boost::interprocess::scoped_lock<Mutex>
104 lock(data.mutex);
105 BOOST_INTERPROCESS_CHECK(lock ? true : false);
106 data.notified++;
107 data.condition.notify_one();
108 }
109
110 boost::interprocess::ipcdetail::thread_join(thread);
111 BOOST_INTERPROCESS_CHECK(data.awoken == 1);
112}
113
114template <class Condition, class Mutex>
115void do_test_condition_notify_all()
116{
117 const int NUMTHREADS = 3;
118
119 boost::interprocess::ipcdetail::OS_thread_t thgroup[std::size_t(NUMTHREADS)];
120 condition_test_data<Condition, Mutex> data;
121
122 for(int i = 0; i< NUMTHREADS; ++i){
123 boost::interprocess::ipcdetail::thread_launch(thgroup[i], bind_function(&condition_test_thread<Condition, Mutex>, &data));
124 }
125
126 //Make sure all threads are blocked
127 boost::interprocess::ipcdetail::thread_sleep_ms(ms: 1*BaseMs);
128 {
129 boost::interprocess::scoped_lock<Mutex>
130 lock(data.mutex);
131 BOOST_INTERPROCESS_CHECK(lock ? true : false);
132 data.notified++;
133 }
134 data.condition.notify_all();
135
136 for(int i = 0; i< NUMTHREADS; ++i){
137 boost::interprocess::ipcdetail::thread_join(thread: thgroup[i]);
138 }
139 BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS);
140}
141
142template <class Condition, class Mutex>
143void do_test_condition_waits_step( condition_test_data<Condition, Mutex> &data
144 , boost::interprocess::scoped_lock<Mutex> &lock
145 , int awoken)
146{
147 boost::interprocess::ipcdetail::thread_sleep_ms(ms: 1*BaseMs);
148 data.notified++;
149 data.condition.notify_one();
150 while (data.awoken != awoken)
151 data.condition.wait(lock);
152 BOOST_INTERPROCESS_CHECK(lock ? true : false);
153 BOOST_INTERPROCESS_CHECK(data.awoken == awoken);
154}
155
156template <class Condition, class Mutex>
157void condition_test_waits(condition_test_data<Condition, Mutex>* data)
158{
159 boost::interprocess::scoped_lock<Mutex>
160 lock(data->mutex);
161 BOOST_INTERPROCESS_CHECK(lock ? true : false);
162
163 // Test wait.
164 while (data->notified != 1)
165 data->condition.wait(lock);
166 BOOST_INTERPROCESS_CHECK(lock ? true : false);
167 BOOST_INTERPROCESS_CHECK(data->notified == 1);
168 data->awoken++;
169 data->condition.notify_one();
170
171 // Test predicate wait.
172 data->condition.wait(lock, cond_predicate(data->notified, 2));
173 BOOST_INTERPROCESS_CHECK(lock ? true : false);
174 BOOST_INTERPROCESS_CHECK(data->notified == 2);
175 data->awoken++;
176 data->condition.notify_one();
177
178 // Test timed_wait
179 while (data->notified != 3)
180 data->condition.timed_wait(lock, ptime_delay_ms(msecs: 5*BaseMs));
181 BOOST_INTERPROCESS_CHECK(lock ? true : false);
182 BOOST_INTERPROCESS_CHECK(data->notified == 3);
183 data->awoken++;
184 data->condition.notify_one();
185
186 // Test predicate timed_wait.
187 {
188 bool ret = data->condition.timed_wait(lock, boost_systemclock_delay_ms(msecs: 5*BaseMs), cond_predicate (data->notified, 4));
189 BOOST_INTERPROCESS_CHECK(ret);(void)ret;
190 BOOST_INTERPROCESS_CHECK(lock ? true : false);
191 BOOST_INTERPROCESS_CHECK(data->notified == 4);
192 data->awoken++;
193 data->condition.notify_one();
194 }
195
196 // Test timed_wait
197 while (data->notified != 5)
198 data->condition.timed_wait(lock, std_systemclock_delay_ms(msecs: 5*BaseMs));
199 BOOST_INTERPROCESS_CHECK(lock ? true : false);
200 BOOST_INTERPROCESS_CHECK(data->notified == 5);
201 data->awoken++;
202 data->condition.notify_one();
203
204 // Test wait_until
205 while (data->notified != 6)
206 data->condition.wait_until(lock, ptime_delay_ms(msecs: 5*BaseMs));
207 BOOST_INTERPROCESS_CHECK(lock ? true : false);
208 BOOST_INTERPROCESS_CHECK(data->notified == 6);
209 data->awoken++;
210 data->condition.notify_one();
211
212 // Test predicate wait_until.
213 {
214 bool ret = data->condition.wait_until(lock, boost_systemclock_delay_ms(msecs: 5*BaseMs), cond_predicate (data->notified, 7));
215 BOOST_INTERPROCESS_CHECK(ret);(void)ret;
216 BOOST_INTERPROCESS_CHECK(lock ? true : false);
217 BOOST_INTERPROCESS_CHECK(data->notified == 7);
218 data->awoken++;
219 data->condition.notify_one();
220 }
221
222 // Test wait_for
223 while (data->notified != 8)
224 data->condition.wait_for(lock, ptime_ms(msecs: 5*BaseMs));
225 BOOST_INTERPROCESS_CHECK(lock ? true : false);
226 BOOST_INTERPROCESS_CHECK(data->notified == 8);
227 data->awoken++;
228 data->condition.notify_one();
229
230 // Test predicate wait_for.
231 {
232 bool ret = data->condition.wait_for(lock, ptime_ms(msecs: 5*BaseMs), cond_predicate (data->notified, 9));
233 BOOST_INTERPROCESS_CHECK(ret);(void)ret;
234 BOOST_INTERPROCESS_CHECK(lock ? true : false);
235 BOOST_INTERPROCESS_CHECK(data->notified == 9);
236 data->awoken++;
237 data->condition.notify_one();
238 }
239
240 // Test wait_for
241 while (data->notified != 10)
242 data->condition.wait_for(lock, boost_systemclock_ms(msecs: 5*BaseMs));
243 BOOST_INTERPROCESS_CHECK(lock ? true : false);
244 BOOST_INTERPROCESS_CHECK(data->notified == 10);
245 data->awoken++;
246 data->condition.notify_one();
247
248 // Test predicate wait_for.
249 {
250 bool ret = data->condition.wait_for(lock, boost_systemclock_ms(msecs: 5*BaseMs), cond_predicate (data->notified, 11));
251 BOOST_INTERPROCESS_CHECK(ret);(void)ret;
252 BOOST_INTERPROCESS_CHECK(lock ? true : false);
253 BOOST_INTERPROCESS_CHECK(data->notified == 11);
254 data->awoken++;
255 data->condition.notify_one();
256 }
257
258 // Test wait_for
259 while (data->notified != 12)
260 data->condition.wait_for(lock, std_systemclock_ms(msecs: 5*BaseMs));
261 BOOST_INTERPROCESS_CHECK(lock ? true : false);
262 BOOST_INTERPROCESS_CHECK(data->notified == 12);
263 data->awoken++;
264 data->condition.notify_one();
265
266 // Test predicate wait_for.
267 {
268 bool ret = data->condition.wait_for(lock, std_systemclock_ms(msecs: 5*BaseMs), cond_predicate (data->notified, 13));
269 BOOST_INTERPROCESS_CHECK(ret);(void)ret;
270 BOOST_INTERPROCESS_CHECK(lock ? true : false);
271 BOOST_INTERPROCESS_CHECK(data->notified == 13);
272 data->awoken++;
273 data->condition.notify_one();
274 }
275}
276
277template <class Condition, class Mutex>
278void do_test_condition_waits()
279{
280 condition_test_data<Condition, Mutex> data;
281 boost::interprocess::ipcdetail::OS_thread_t thread;
282 boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_waits<Condition, Mutex>, &data));
283
284 {
285 boost::interprocess::scoped_lock<Mutex>
286 lock(data.mutex);
287 BOOST_INTERPROCESS_CHECK(lock ? true : false);
288
289 for(int i = 1; i <= 13; ++i)
290 do_test_condition_waits_step(data, lock, i);
291 }
292
293 boost::interprocess::ipcdetail::thread_join(thread);
294 BOOST_INTERPROCESS_CHECK(data.awoken == 13);
295}
296
297/*
298//Message queue simulation test
299template <class Condition>
300inline Condition &cond_empty()
301{
302 static Condition cond_empty;
303 return cond_empty;
304}
305
306template <class Condition>
307inline Condition &cond_full()
308{
309 static Condition cond_full;
310 return cond_full;
311}
312
313
314template <class Mutex>
315inline Mutex &mutex()
316{
317 static Mutex mut;
318 return mut;
319}
320*/
321static int count = 0;
322static int waiting_readers = 0;
323static int waiting_writer = 0;
324const int queue_size = 3;
325const int thread_factor = 10;
326const int NumThreads = thread_factor*queue_size;
327
328//Function that removes items from queue
329template <class Condition, class Mutex>
330struct condition_func
331{
332 condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex)
333 : cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex)
334 {}
335
336 void operator()()
337 {
338 boost::interprocess::scoped_lock<Mutex>lock(mutex_);
339 while(count == 0){
340 ++waiting_readers;
341 cond_empty_.wait(lock);
342 --waiting_readers;
343 }
344 --count;
345 if(waiting_writer)
346 cond_full_.notify_one();
347 }
348 Condition &cond_full_;
349 Condition &cond_empty_;
350 Mutex &mutex_;
351};
352
353//Queue functions
354template <class Condition, class Mutex>
355void do_test_condition_queue_notify_one(void)
356{
357 //Force mutex and condition creation
358 Condition cond_empty;
359 Condition cond_full;
360 Mutex mutex;
361
362 //Create threads that will decrease count
363 {
364 //Initialize counters
365 count = 0;
366 waiting_readers = 0;
367 waiting_writer = 0;
368
369 boost::interprocess::ipcdetail::OS_thread_t thgroup[std::size_t(NumThreads)];
370 for(int i = 0; i< NumThreads; ++i){
371 condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
372 boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
373 }
374
375 //Add 20 elements one by one in the queue simulation
376 //The sender will block if it fills the queue
377 for(int i = 0; i < NumThreads; ++i){
378 boost::interprocess::scoped_lock<Mutex> lock(mutex);
379 while(count == queue_size){
380 ++waiting_writer;
381 cond_full.wait(lock);
382 --waiting_writer;
383 }
384 count++;
385
386 if(waiting_readers)
387 cond_empty.notify_one();
388 }
389 for(int i = 0; i< NumThreads; ++i){
390 boost::interprocess::ipcdetail::thread_join(thread: thgroup[i]);
391 }
392 BOOST_INTERPROCESS_CHECK(count == 0);
393 BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
394 BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
395 }
396}
397
398//Queue functions
399template <class Condition, class Mutex>
400void do_test_condition_queue_notify_all(void)
401{
402 //Force mutex and condition creation
403 Condition cond_empty;
404 Condition cond_full;
405 Mutex mutex;
406
407 //Create threads that will decrease count
408 {
409 //Initialize counters
410 count = 0;
411 waiting_readers = 0;
412 waiting_writer = 0;
413
414 boost::interprocess::ipcdetail::OS_thread_t thgroup[std::size_t(NumThreads)];
415 for(int i = 0; i< NumThreads; ++i){
416 condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
417 boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
418 }
419
420 //Fill queue to the max size and notify all several times
421 for(int i = 0; i < NumThreads; ++i){
422 boost::interprocess::scoped_lock<Mutex>lock(mutex);
423 while(count == queue_size){
424 ++waiting_writer;
425 cond_full.wait(lock);
426 --waiting_writer;
427 }
428 count++;
429
430 if(waiting_readers)
431 cond_empty.notify_all();
432 }
433 for(int i = 0; i< NumThreads; ++i){
434 boost::interprocess::ipcdetail::thread_join(thread: thgroup[i]);
435 }
436 BOOST_INTERPROCESS_CHECK(count == 0);
437 BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
438 BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
439 }
440}
441
442template <class Condition, class Mutex>
443bool do_test_condition()
444{
445 std::cout << "do_test_condition_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
446 do_test_condition_notify_one<Condition, Mutex>();
447 std::cout << "do_test_condition_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
448 do_test_condition_notify_all<Condition, Mutex>();
449 std::cout << "do_test_condition_waits<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
450 do_test_condition_waits<Condition, Mutex>();
451 std::cout << "do_test_condition_queue_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
452 do_test_condition_queue_notify_one<Condition, Mutex>();
453 std::cout << "do_test_condition_queue_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
454 do_test_condition_queue_notify_all<Condition, Mutex>();
455 return true;
456}
457
458} //namespace test
459} //namespace interprocess{
460} //namespace boost{
461
462#include <boost/interprocess/detail/config_end.hpp>
463
464#endif //#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
465

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