]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/interprocess/test/condition_test_template.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / interprocess / test / condition_test_template.hpp
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
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:
45 binder(const F& f, const T& p)
46 : func(f), param(p) { }
47 void operator()() const { func(param); }
48
49 private:
50 F func;
51 T param;
52 };
53
54 template <typename F, typename T>
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 {
63 condition_test_data() : notified(0), awoken(0) { }
64
65 ~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>
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 {
88 cond_predicate(int& var, int val) : _var(var), _val(val) { }
89
90 bool operator()() { return _var == _val; }
91
92 int& _var;
93 int _val;
94 };
95
96 template <class Condition, class Mutex>
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>
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>
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>
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 {
269 condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex)
270 : cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex)
271 {}
272
273 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>
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>
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>
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