]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/test/io_service.cpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / asio / test / io_service.cpp
1 //
2 // io_service.cpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 // Disable autolinking for unit tests.
12 #if !defined(BOOST_ALL_NO_LIB)
13 #define BOOST_ALL_NO_LIB 1
14 #endif // !defined(BOOST_ALL_NO_LIB)
15
16 // Test that header file is self-contained.
17 #include <boost/asio/io_service.hpp>
18
19 #include <sstream>
20 #include <boost/asio/detail/thread.hpp>
21 #include "unit_test.hpp"
22
23 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
24 # include <boost/asio/deadline_timer.hpp>
25 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
26 # include <boost/asio/steady_timer.hpp>
27 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
28
29 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
30 # include <boost/bind.hpp>
31 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
32 # include <functional>
33 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
34
35 using namespace boost::asio;
36
37 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
38 namespace bindns = boost;
39 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
40 namespace bindns = std;
41 #endif
42
43 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
44 typedef deadline_timer timer;
45 namespace chronons = boost::posix_time;
46 #elif defined(BOOST_ASIO_HAS_STD_CHRONO)
47 typedef steady_timer timer;
48 namespace chronons = std::chrono;
49 #elif defined(BOOST_ASIO_HAS_BOOST_CHRONO)
50 typedef steady_timer timer;
51 namespace chronons = boost::chrono;
52 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
53
54 void increment(int* count)
55 {
56 ++(*count);
57 }
58
59 void decrement_to_zero(io_service* ios, int* count)
60 {
61 if (*count > 0)
62 {
63 --(*count);
64
65 int before_value = *count;
66 ios->post(bindns::bind(decrement_to_zero, ios, count));
67
68 // Handler execution cannot nest, so count value should remain unchanged.
69 BOOST_ASIO_CHECK(*count == before_value);
70 }
71 }
72
73 void nested_decrement_to_zero(io_service* ios, int* count)
74 {
75 if (*count > 0)
76 {
77 --(*count);
78
79 ios->dispatch(bindns::bind(nested_decrement_to_zero, ios, count));
80
81 // Handler execution is nested, so count value should now be zero.
82 BOOST_ASIO_CHECK(*count == 0);
83 }
84 }
85
86 void sleep_increment(io_service* ios, int* count)
87 {
88 timer t(*ios, chronons::seconds(2));
89 t.wait();
90
91 if (++(*count) < 3)
92 ios->post(bindns::bind(sleep_increment, ios, count));
93 }
94
95 void start_sleep_increments(io_service* ios, int* count)
96 {
97 // Give all threads a chance to start.
98 timer t(*ios, chronons::seconds(2));
99 t.wait();
100
101 // Start the first of three increments.
102 ios->post(bindns::bind(sleep_increment, ios, count));
103 }
104
105 void throw_exception()
106 {
107 throw 1;
108 }
109
110 void io_service_run(io_service* ios)
111 {
112 ios->run();
113 }
114
115 void io_service_test()
116 {
117 io_service ios;
118 int count = 0;
119
120 ios.post(bindns::bind(increment, &count));
121
122 // No handlers can be called until run() is called.
123 BOOST_ASIO_CHECK(!ios.stopped());
124 BOOST_ASIO_CHECK(count == 0);
125
126 ios.run();
127
128 // The run() call will not return until all work has finished.
129 BOOST_ASIO_CHECK(ios.stopped());
130 BOOST_ASIO_CHECK(count == 1);
131
132 count = 0;
133 ios.reset();
134 ios.post(bindns::bind(increment, &count));
135 ios.post(bindns::bind(increment, &count));
136 ios.post(bindns::bind(increment, &count));
137 ios.post(bindns::bind(increment, &count));
138 ios.post(bindns::bind(increment, &count));
139
140 // No handlers can be called until run() is called.
141 BOOST_ASIO_CHECK(!ios.stopped());
142 BOOST_ASIO_CHECK(count == 0);
143
144 ios.run();
145
146 // The run() call will not return until all work has finished.
147 BOOST_ASIO_CHECK(ios.stopped());
148 BOOST_ASIO_CHECK(count == 5);
149
150 count = 0;
151 ios.reset();
152 io_service::work* w = new io_service::work(ios);
153 ios.post(bindns::bind(&io_service::stop, &ios));
154 BOOST_ASIO_CHECK(!ios.stopped());
155 ios.run();
156
157 // The only operation executed should have been to stop run().
158 BOOST_ASIO_CHECK(ios.stopped());
159 BOOST_ASIO_CHECK(count == 0);
160
161 ios.reset();
162 ios.post(bindns::bind(increment, &count));
163 delete w;
164
165 // No handlers can be called until run() is called.
166 BOOST_ASIO_CHECK(!ios.stopped());
167 BOOST_ASIO_CHECK(count == 0);
168
169 ios.run();
170
171 // The run() call will not return until all work has finished.
172 BOOST_ASIO_CHECK(ios.stopped());
173 BOOST_ASIO_CHECK(count == 1);
174
175 count = 10;
176 ios.reset();
177 ios.post(bindns::bind(decrement_to_zero, &ios, &count));
178
179 // No handlers can be called until run() is called.
180 BOOST_ASIO_CHECK(!ios.stopped());
181 BOOST_ASIO_CHECK(count == 10);
182
183 ios.run();
184
185 // The run() call will not return until all work has finished.
186 BOOST_ASIO_CHECK(ios.stopped());
187 BOOST_ASIO_CHECK(count == 0);
188
189 count = 10;
190 ios.reset();
191 ios.post(bindns::bind(nested_decrement_to_zero, &ios, &count));
192
193 // No handlers can be called until run() is called.
194 BOOST_ASIO_CHECK(!ios.stopped());
195 BOOST_ASIO_CHECK(count == 10);
196
197 ios.run();
198
199 // The run() call will not return until all work has finished.
200 BOOST_ASIO_CHECK(ios.stopped());
201 BOOST_ASIO_CHECK(count == 0);
202
203 count = 10;
204 ios.reset();
205 ios.dispatch(bindns::bind(nested_decrement_to_zero, &ios, &count));
206
207 // No handlers can be called until run() is called, even though nested
208 // delivery was specifically allowed in the previous call.
209 BOOST_ASIO_CHECK(!ios.stopped());
210 BOOST_ASIO_CHECK(count == 10);
211
212 ios.run();
213
214 // The run() call will not return until all work has finished.
215 BOOST_ASIO_CHECK(ios.stopped());
216 BOOST_ASIO_CHECK(count == 0);
217
218 count = 0;
219 int count2 = 0;
220 ios.reset();
221 BOOST_ASIO_CHECK(!ios.stopped());
222 ios.post(bindns::bind(start_sleep_increments, &ios, &count));
223 ios.post(bindns::bind(start_sleep_increments, &ios, &count2));
224 boost::asio::detail::thread thread1(bindns::bind(io_service_run, &ios));
225 boost::asio::detail::thread thread2(bindns::bind(io_service_run, &ios));
226 thread1.join();
227 thread2.join();
228
229 // The run() calls will not return until all work has finished.
230 BOOST_ASIO_CHECK(ios.stopped());
231 BOOST_ASIO_CHECK(count == 3);
232 BOOST_ASIO_CHECK(count2 == 3);
233
234 count = 10;
235 io_service ios2;
236 ios.dispatch(ios2.wrap(bindns::bind(decrement_to_zero, &ios2, &count)));
237 ios.reset();
238 BOOST_ASIO_CHECK(!ios.stopped());
239 ios.run();
240
241 // No decrement_to_zero handlers can be called until run() is called on the
242 // second io_service object.
243 BOOST_ASIO_CHECK(ios.stopped());
244 BOOST_ASIO_CHECK(count == 10);
245
246 ios2.run();
247
248 // The run() call will not return until all work has finished.
249 BOOST_ASIO_CHECK(count == 0);
250
251 count = 0;
252 int exception_count = 0;
253 ios.reset();
254 ios.post(&throw_exception);
255 ios.post(bindns::bind(increment, &count));
256 ios.post(bindns::bind(increment, &count));
257 ios.post(&throw_exception);
258 ios.post(bindns::bind(increment, &count));
259
260 // No handlers can be called until run() is called.
261 BOOST_ASIO_CHECK(!ios.stopped());
262 BOOST_ASIO_CHECK(count == 0);
263 BOOST_ASIO_CHECK(exception_count == 0);
264
265 for (;;)
266 {
267 try
268 {
269 ios.run();
270 break;
271 }
272 catch (int)
273 {
274 ++exception_count;
275 }
276 }
277
278 // The run() calls will not return until all work has finished.
279 BOOST_ASIO_CHECK(ios.stopped());
280 BOOST_ASIO_CHECK(count == 3);
281 BOOST_ASIO_CHECK(exception_count == 2);
282 }
283
284 class test_service : public boost::asio::io_service::service
285 {
286 public:
287 static boost::asio::io_service::id id;
288 test_service(boost::asio::io_service& s)
289 : boost::asio::io_service::service(s) {}
290 private:
291 virtual void shutdown_service() {}
292 };
293
294 boost::asio::io_service::id test_service::id;
295
296 void io_service_service_test()
297 {
298 boost::asio::io_service ios1;
299 boost::asio::io_service ios2;
300 boost::asio::io_service ios3;
301
302 // Implicit service registration.
303
304 boost::asio::use_service<test_service>(ios1);
305
306 BOOST_ASIO_CHECK(boost::asio::has_service<test_service>(ios1));
307
308 test_service* svc1 = new test_service(ios1);
309 try
310 {
311 boost::asio::add_service(ios1, svc1);
312 BOOST_ASIO_ERROR("add_service did not throw");
313 }
314 catch (boost::asio::service_already_exists&)
315 {
316 }
317 delete svc1;
318
319 // Explicit service registration.
320
321 test_service* svc2 = new test_service(ios2);
322 boost::asio::add_service(ios2, svc2);
323
324 BOOST_ASIO_CHECK(boost::asio::has_service<test_service>(ios2));
325 BOOST_ASIO_CHECK(&boost::asio::use_service<test_service>(ios2) == svc2);
326
327 test_service* svc3 = new test_service(ios2);
328 try
329 {
330 boost::asio::add_service(ios2, svc3);
331 BOOST_ASIO_ERROR("add_service did not throw");
332 }
333 catch (boost::asio::service_already_exists&)
334 {
335 }
336 delete svc3;
337
338 // Explicit registration with invalid owner.
339
340 test_service* svc4 = new test_service(ios2);
341 try
342 {
343 boost::asio::add_service(ios3, svc4);
344 BOOST_ASIO_ERROR("add_service did not throw");
345 }
346 catch (boost::asio::invalid_service_owner&)
347 {
348 }
349 delete svc4;
350
351 BOOST_ASIO_CHECK(!boost::asio::has_service<test_service>(ios3));
352 }
353
354 BOOST_ASIO_TEST_SUITE
355 (
356 "io_service",
357 BOOST_ASIO_TEST_CASE(io_service_test)
358 BOOST_ASIO_TEST_CASE(io_service_service_test)
359 )