1 // Copyright (C) 2001-2003
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 //////////////////////////////////////////////////////////////////////////////
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)
17 // See http://www.boost.org/libs/interprocess for documentation.
19 //////////////////////////////////////////////////////////////////////////////
20 #ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
21 #define BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
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 <boost/date_time/posix_time/posix_time_types.hpp>
32 namespace interprocess{
35 boost::posix_time::ptime ptime_delay(int secs)
37 return microsec_clock::universal_time() +
38 boost::posix_time::time_duration(0, 0, secs);
41 template <typename F, typename T>
45 binder(const F& f, const T& p)
46 : func(f), param(p) { }
47 void operator()() const { func(param); }
54 template <typename F, typename T>
55 binder<F, T> bind_function(F func, T param)
57 return binder<F, T>(func, param);
60 template <class Condition, class Mutex>
61 struct condition_test_data
63 condition_test_data() : notified(0), awoken(0) { }
65 ~condition_test_data()
74 template <class Condition, class Mutex>
75 void condition_test_thread(condition_test_data<Condition, Mutex>* data)
77 boost::interprocess::scoped_lock<Mutex>
79 BOOST_INTERPROCESS_CHECK(lock ? true : false);
80 while (!(data->notified > 0))
81 data->condition.wait(lock);
82 BOOST_INTERPROCESS_CHECK(lock ? true : false);
88 cond_predicate(int& var, int val) : _var(var), _val(val) { }
90 bool operator()() { return _var == _val; }
96 template <class Condition, class Mutex>
97 void condition_test_waits(condition_test_data<Condition, Mutex>* data)
99 boost::interprocess::scoped_lock<Mutex>
101 BOOST_INTERPROCESS_CHECK(lock ? true : false);
104 while (data->notified != 1)
105 data->condition.wait(lock);
106 BOOST_INTERPROCESS_CHECK(lock ? true : false);
107 BOOST_INTERPROCESS_CHECK(data->notified == 1);
109 data->condition.notify_one();
111 // Test predicate wait.
112 data->condition.wait(lock, cond_predicate(data->notified, 2));
113 BOOST_INTERPROCESS_CHECK(lock ? true : false);
114 BOOST_INTERPROCESS_CHECK(data->notified == 2);
116 data->condition.notify_one();
119 while (data->notified != 3)
120 data->condition.timed_wait(lock, ptime_delay(5));
121 BOOST_INTERPROCESS_CHECK(lock ? true : false);
122 BOOST_INTERPROCESS_CHECK(data->notified == 3);
124 data->condition.notify_one();
126 // Test predicate timed_wait.
127 cond_predicate pred(data->notified, 4);
128 bool ret = data->condition.timed_wait(lock, ptime_delay(5), pred);
129 BOOST_INTERPROCESS_CHECK(ret);(void)ret;
130 BOOST_INTERPROCESS_CHECK(lock ? true : false);
131 BOOST_INTERPROCESS_CHECK(pred());
132 BOOST_INTERPROCESS_CHECK(data->notified == 4);
134 data->condition.notify_one();
137 template <class Condition, class Mutex>
138 void do_test_condition_notify_one()
140 condition_test_data<Condition, Mutex> data;
142 boost::interprocess::ipcdetail::OS_thread_t thread;
143 boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_thread<Condition, Mutex>, &data));
144 //Make sure thread is blocked
145 boost::interprocess::ipcdetail::thread_sleep(1000);
147 boost::interprocess::scoped_lock<Mutex>
149 BOOST_INTERPROCESS_CHECK(lock ? true : false);
151 data.condition.notify_one();
154 boost::interprocess::ipcdetail::thread_join(thread);
155 BOOST_INTERPROCESS_CHECK(data.awoken == 1);
158 template <class Condition, class Mutex>
159 void do_test_condition_notify_all()
161 const int NUMTHREADS = 3;
163 boost::interprocess::ipcdetail::OS_thread_t thgroup[NUMTHREADS];
164 condition_test_data<Condition, Mutex> data;
166 for(int i = 0; i< NUMTHREADS; ++i){
167 boost::interprocess::ipcdetail::thread_launch(thgroup[i], bind_function(&condition_test_thread<Condition, Mutex>, &data));
170 //Make sure all threads are blocked
171 boost::interprocess::ipcdetail::thread_sleep(1000);
173 boost::interprocess::scoped_lock<Mutex>
175 BOOST_INTERPROCESS_CHECK(lock ? true : false);
178 data.condition.notify_all();
180 for(int i = 0; i< NUMTHREADS; ++i){
181 boost::interprocess::ipcdetail::thread_join(thgroup[i]);
183 BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS);
186 template <class Condition, class Mutex>
187 void do_test_condition_waits()
189 condition_test_data<Condition, Mutex> data;
190 boost::interprocess::ipcdetail::OS_thread_t thread;
191 boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_waits<Condition, Mutex>, &data));
194 boost::interprocess::scoped_lock<Mutex>
196 BOOST_INTERPROCESS_CHECK(lock ? true : false);
198 boost::interprocess::ipcdetail::thread_sleep(1000);
200 data.condition.notify_one();
201 while (data.awoken != 1)
202 data.condition.wait(lock);
203 BOOST_INTERPROCESS_CHECK(lock ? true : false);
204 BOOST_INTERPROCESS_CHECK(data.awoken == 1);
206 boost::interprocess::ipcdetail::thread_sleep(1000);
208 data.condition.notify_one();
209 while (data.awoken != 2)
210 data.condition.wait(lock);
211 BOOST_INTERPROCESS_CHECK(lock ? true : false);
212 BOOST_INTERPROCESS_CHECK(data.awoken == 2);
214 boost::interprocess::ipcdetail::thread_sleep(1000);
216 data.condition.notify_one();
217 while (data.awoken != 3)
218 data.condition.wait(lock);
219 BOOST_INTERPROCESS_CHECK(lock ? true : false);
220 BOOST_INTERPROCESS_CHECK(data.awoken == 3);
222 boost::interprocess::ipcdetail::thread_sleep(1000);
224 data.condition.notify_one();
225 while (data.awoken != 4)
226 data.condition.wait(lock);
227 BOOST_INTERPROCESS_CHECK(lock ? true : false);
228 BOOST_INTERPROCESS_CHECK(data.awoken == 4);
231 boost::interprocess::ipcdetail::thread_join(thread);
232 BOOST_INTERPROCESS_CHECK(data.awoken == 4);
235 //Message queue simulation test
236 template <class Condition>
237 inline Condition &cond_empty()
239 static Condition cond_empty;
243 template <class Condition>
244 inline Condition &cond_full()
246 static Condition cond_full;
251 template <class Mutex>
252 inline Mutex &mutex()
258 static volatile int count = 0;
259 static volatile int waiting_readers = 0;
260 static volatile int waiting_writer = 0;
261 const int queue_size = 3;
262 const int thread_factor = 10;
263 const int NumThreads = thread_factor*queue_size;
265 //Function that removes items from queue
266 template <class Condition, class Mutex>
267 struct condition_func
269 condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex)
270 : cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex)
275 boost::interprocess::scoped_lock<Mutex>lock(mutex_);
278 cond_empty_.wait(lock);
283 cond_full_.notify_one();
285 Condition &cond_full_;
286 Condition &cond_empty_;
291 template <class Condition, class Mutex>
292 void do_test_condition_queue_notify_one(void)
294 //Force mutex and condition creation
295 Condition cond_empty;
299 //Create threads that will decrease count
301 //Initialize counters
306 boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads];
307 for(int i = 0; i< NumThreads; ++i){
308 condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
309 boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
312 //Add 20 elements one by one in the queue simulation
313 //The sender will block if it fills the queue
314 for(int i = 0; i < NumThreads; ++i){
315 boost::interprocess::scoped_lock<Mutex> lock(mutex);
316 while(count == queue_size){
318 cond_full.wait(lock);
324 cond_empty.notify_one();
326 for(int i = 0; i< NumThreads; ++i){
327 boost::interprocess::ipcdetail::thread_join(thgroup[i]);
329 BOOST_INTERPROCESS_CHECK(count == 0);
330 BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
331 BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
336 template <class Condition, class Mutex>
337 void do_test_condition_queue_notify_all(void)
339 //Force mutex and condition creation
340 Condition cond_empty;
344 //Create threads that will decrease count
346 //Initialize counters
351 boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads];
352 for(int i = 0; i< NumThreads; ++i){
353 condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
354 boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
357 //Fill queue to the max size and notify all several times
358 for(int i = 0; i < NumThreads; ++i){
359 boost::interprocess::scoped_lock<Mutex>lock(mutex);
360 while(count == queue_size){
362 cond_full.wait(lock);
368 cond_empty.notify_all();
370 for(int i = 0; i< NumThreads; ++i){
371 boost::interprocess::ipcdetail::thread_join(thgroup[i]);
373 BOOST_INTERPROCESS_CHECK(count == 0);
374 BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
375 BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
379 template <class Condition, class Mutex>
380 bool do_test_condition()
382 std::cout << "do_test_condition_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
383 do_test_condition_notify_one<Condition, Mutex>();
384 std::cout << "do_test_condition_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
385 do_test_condition_notify_all<Condition, Mutex>();
386 std::cout << "do_test_condition_waits<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
387 do_test_condition_waits<Condition, Mutex>();
388 std::cout << "do_test_condition_queue_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
389 do_test_condition_queue_notify_one<Condition, Mutex>();
390 std::cout << "do_test_condition_queue_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
391 do_test_condition_queue_notify_all<Condition, Mutex>();
396 } //namespace interprocess{
399 #include <boost/interprocess/detail/config_end.hpp>
401 #endif //#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP