• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <boost/date_time/posix_time/posix_time_types.hpp>
29 #include <iostream>
30 
31 namespace boost{
32 namespace interprocess{
33 namespace test {
34 
ptime_delay(int secs)35 boost::posix_time::ptime ptime_delay(int secs)
36 {
37    return   microsec_clock::universal_time() +
38             boost::posix_time::time_duration(0, 0, secs);
39 }
40 
41 template <typename F, typename T>
42 class binder
43 {
44 public:
binder(const F & f,const T & p)45     binder(const F& f, const T& p)
46         : func(f), param(p) { }
operator ()() const47     void operator()() const { func(param); }
48 
49 private:
50     F func;
51     T param;
52 };
53 
54 template <typename F, typename T>
bind_function(F func,T param)55 binder<F, T> bind_function(F func, T param)
56 {
57     return binder<F, T>(func, param);
58 }
59 
60 template <class Condition, class Mutex>
61 struct condition_test_data
62 {
condition_test_databoost::interprocess::test::condition_test_data63    condition_test_data() : notified(0), awoken(0) { }
64 
~condition_test_databoost::interprocess::test::condition_test_data65    ~condition_test_data()
66    {}
67 
68    Mutex      mutex;
69    Condition  condition;
70    int notified;
71    int awoken;
72 };
73 
74 template <class Condition, class Mutex>
condition_test_thread(condition_test_data<Condition,Mutex> * data)75 void condition_test_thread(condition_test_data<Condition, Mutex>* data)
76 {
77     boost::interprocess::scoped_lock<Mutex>
78       lock(data->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);
83     data->awoken++;
84 }
85 
86 struct cond_predicate
87 {
cond_predicateboost::interprocess::test::cond_predicate88     cond_predicate(int& var, int val) : _var(var), _val(val) { }
89 
operator ()boost::interprocess::test::cond_predicate90     bool operator()() { return _var == _val; }
91 
92     int& _var;
93     int _val;
94 };
95 
96 template <class Condition, class Mutex>
condition_test_waits(condition_test_data<Condition,Mutex> * data)97 void condition_test_waits(condition_test_data<Condition, Mutex>* data)
98 {
99     boost::interprocess::scoped_lock<Mutex>
100       lock(data->mutex);
101     BOOST_INTERPROCESS_CHECK(lock ? true : false);
102 
103     // Test wait.
104     while (data->notified != 1)
105         data->condition.wait(lock);
106     BOOST_INTERPROCESS_CHECK(lock ? true : false);
107     BOOST_INTERPROCESS_CHECK(data->notified == 1);
108     data->awoken++;
109     data->condition.notify_one();
110 
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);
115     data->awoken++;
116     data->condition.notify_one();
117 
118     // Test timed_wait.
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);
123     data->awoken++;
124     data->condition.notify_one();
125 
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);
133     data->awoken++;
134     data->condition.notify_one();
135 }
136 
137 template <class Condition, class Mutex>
do_test_condition_notify_one()138 void do_test_condition_notify_one()
139 {
140    condition_test_data<Condition, Mutex> data;
141 
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);
146    {
147       boost::interprocess::scoped_lock<Mutex>
148          lock(data.mutex);
149       BOOST_INTERPROCESS_CHECK(lock ? true : false);
150       data.notified++;
151       data.condition.notify_one();
152    }
153 
154    boost::interprocess::ipcdetail::thread_join(thread);
155    BOOST_INTERPROCESS_CHECK(data.awoken == 1);
156 }
157 
158 template <class Condition, class Mutex>
do_test_condition_notify_all()159 void do_test_condition_notify_all()
160 {
161    const int NUMTHREADS = 3;
162 
163    boost::interprocess::ipcdetail::OS_thread_t thgroup[NUMTHREADS];
164    condition_test_data<Condition, Mutex> data;
165 
166    for(int i = 0; i< NUMTHREADS; ++i){
167       boost::interprocess::ipcdetail::thread_launch(thgroup[i], bind_function(&condition_test_thread<Condition, Mutex>, &data));
168    }
169 
170    //Make sure all threads are blocked
171    boost::interprocess::ipcdetail::thread_sleep(1000);
172    {
173       boost::interprocess::scoped_lock<Mutex>
174          lock(data.mutex);
175       BOOST_INTERPROCESS_CHECK(lock ? true : false);
176       data.notified++;
177    }
178    data.condition.notify_all();
179 
180    for(int i = 0; i< NUMTHREADS; ++i){
181       boost::interprocess::ipcdetail::thread_join(thgroup[i]);
182    }
183    BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS);
184 }
185 
186 template <class Condition, class Mutex>
do_test_condition_waits()187 void do_test_condition_waits()
188 {
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));
192 
193    {
194       boost::interprocess::scoped_lock<Mutex>
195          lock(data.mutex);
196       BOOST_INTERPROCESS_CHECK(lock ? true : false);
197 
198       boost::interprocess::ipcdetail::thread_sleep(1000);
199       data.notified++;
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);
205 
206       boost::interprocess::ipcdetail::thread_sleep(1000);
207       data.notified++;
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);
213 
214       boost::interprocess::ipcdetail::thread_sleep(1000);
215       data.notified++;
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);
221 
222       boost::interprocess::ipcdetail::thread_sleep(1000);
223       data.notified++;
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);
229    }
230 
231    boost::interprocess::ipcdetail::thread_join(thread);
232    BOOST_INTERPROCESS_CHECK(data.awoken == 4);
233 }
234 /*
235 //Message queue simulation test
236 template <class Condition>
237 inline Condition &cond_empty()
238 {
239    static Condition cond_empty;
240    return cond_empty;
241 }
242 
243 template <class Condition>
244 inline Condition &cond_full()
245 {
246    static Condition cond_full;
247    return cond_full;
248 }
249 
250 
251 template <class Mutex>
252 inline Mutex &mutex()
253 {
254    static Mutex mut;
255    return mut;
256 }
257 */
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;
264 
265 //Function that removes items from queue
266 template <class Condition, class Mutex>
267 struct condition_func
268 {
condition_funcboost::interprocess::test::condition_func269    condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex)
270       :  cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex)
271    {}
272 
operator ()boost::interprocess::test::condition_func273    void operator()()
274    {
275       boost::interprocess::scoped_lock<Mutex>lock(mutex_);
276       while(count == 0){
277          ++waiting_readers;
278          cond_empty_.wait(lock);
279          --waiting_readers;
280       }
281       --count;
282       if(waiting_writer)
283          cond_full_.notify_one();
284    }
285    Condition &cond_full_;
286    Condition &cond_empty_;
287    Mutex     &mutex_;
288 };
289 
290 //Queue functions
291 template <class Condition, class Mutex>
do_test_condition_queue_notify_one(void)292 void do_test_condition_queue_notify_one(void)
293 {
294    //Force mutex and condition creation
295    Condition cond_empty;
296    Condition cond_full;
297    Mutex mutex;
298 
299    //Create threads that will decrease count
300    {
301       //Initialize counters
302       count = 0;
303       waiting_readers = 0;
304       waiting_writer  = 0;
305 
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);
310       }
311 
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){
317             ++waiting_writer;
318             cond_full.wait(lock);
319             --waiting_writer;
320          }
321          count++;
322 
323          if(waiting_readers)
324             cond_empty.notify_one();
325       }
326       for(int i = 0; i< NumThreads; ++i){
327          boost::interprocess::ipcdetail::thread_join(thgroup[i]);
328       }
329       BOOST_INTERPROCESS_CHECK(count == 0);
330       BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
331       BOOST_INTERPROCESS_CHECK(waiting_writer  == 0);
332    }
333 }
334 
335 //Queue functions
336 template <class Condition, class Mutex>
do_test_condition_queue_notify_all(void)337 void do_test_condition_queue_notify_all(void)
338 {
339    //Force mutex and condition creation
340    Condition cond_empty;
341    Condition cond_full;
342    Mutex mutex;
343 
344    //Create threads that will decrease count
345    {
346       //Initialize counters
347       count = 0;
348       waiting_readers = 0;
349       waiting_writer  = 0;
350 
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);
355       }
356 
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){
361             ++waiting_writer;
362             cond_full.wait(lock);
363             --waiting_writer;
364          }
365          count++;
366 
367          if(waiting_readers)
368             cond_empty.notify_all();
369       }
370       for(int i = 0; i< NumThreads; ++i){
371          boost::interprocess::ipcdetail::thread_join(thgroup[i]);
372       }
373       BOOST_INTERPROCESS_CHECK(count == 0);
374       BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
375       BOOST_INTERPROCESS_CHECK(waiting_writer  == 0);
376    }
377 }
378 
379 template <class Condition, class Mutex>
do_test_condition()380 bool do_test_condition()
381 {
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>();
392    return true;
393 }
394 
395 }  //namespace test
396 }  //namespace interprocess{
397 }  //namespace boost{
398 
399 #include <boost/interprocess/detail/config_end.hpp>
400 
401 #endif   //#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
402