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