]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/test/strand.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / asio / test / strand.cpp
CommitLineData
7c673cae
FG
1//
2// strand.cpp
3// ~~~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 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.
17#include <boost/asio/strand.hpp>
18
19#include <sstream>
f67539c2 20#include <boost/asio/executor.hpp>
b32b8144
FG
21#include <boost/asio/io_context.hpp>
22#include <boost/asio/dispatch.hpp>
23#include <boost/asio/post.hpp>
7c673cae
FG
24#include <boost/asio/detail/thread.hpp>
25#include "unit_test.hpp"
26
27#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
28# include <boost/asio/deadline_timer.hpp>
29#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
30# include <boost/asio/steady_timer.hpp>
31#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
32
33#if defined(BOOST_ASIO_HAS_BOOST_BIND)
f67539c2 34# include <boost/bind/bind.hpp>
7c673cae
FG
35#else // defined(BOOST_ASIO_HAS_BOOST_BIND)
36# include <functional>
37#endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
38
39using namespace boost::asio;
40
41#if defined(BOOST_ASIO_HAS_BOOST_BIND)
42namespace bindns = boost;
43#else // defined(BOOST_ASIO_HAS_BOOST_BIND)
44namespace bindns = std;
45#endif
46
47#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
48typedef deadline_timer timer;
49namespace chronons = boost::posix_time;
b32b8144 50#elif defined(BOOST_ASIO_HAS_CHRONO)
7c673cae 51typedef steady_timer timer;
b32b8144 52namespace chronons = boost::asio::chrono;
7c673cae
FG
53#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
54
55void increment(int* count)
56{
57 ++(*count);
58}
59
92f5a8d4 60void increment_without_lock(strand<io_context::executor_type>* s, int* count)
7c673cae
FG
61{
62 BOOST_ASIO_CHECK(!s->running_in_this_thread());
63
64 int original_count = *count;
65
b32b8144 66 dispatch(*s, bindns::bind(increment, count));
7c673cae
FG
67
68 // No other functions are currently executing through the locking dispatcher,
69 // so the previous call to dispatch should have successfully nested.
70 BOOST_ASIO_CHECK(*count == original_count + 1);
71}
72
92f5a8d4 73void increment_with_lock(strand<io_context::executor_type>* s, int* count)
7c673cae
FG
74{
75 BOOST_ASIO_CHECK(s->running_in_this_thread());
76
77 int original_count = *count;
78
b32b8144 79 dispatch(*s, bindns::bind(increment, count));
7c673cae
FG
80
81 // The current function already holds the strand's lock, so the
82 // previous call to dispatch should have successfully nested.
83 BOOST_ASIO_CHECK(*count == original_count + 1);
84}
85
b32b8144 86void sleep_increment(io_context* ioc, int* count)
7c673cae 87{
b32b8144 88 timer t(*ioc, chronons::seconds(2));
7c673cae
FG
89 t.wait();
90
91 ++(*count);
92}
93
b32b8144
FG
94void increment_by_a(int* count, int a)
95{
96 (*count) += a;
97}
98
99void increment_by_a_b(int* count, int a, int b)
100{
101 (*count) += a + b;
102}
103
104void increment_by_a_b_c(int* count, int a, int b, int c)
105{
106 (*count) += a + b + c;
107}
108
109void increment_by_a_b_c_d(int* count, int a, int b, int c, int d)
110{
111 (*count) += a + b + c + d;
112}
113
92f5a8d4
TL
114void start_sleep_increments(io_context* ioc,
115 strand<io_context::executor_type>* s, int* count)
7c673cae
FG
116{
117 // Give all threads a chance to start.
b32b8144 118 timer t(*ioc, chronons::seconds(2));
7c673cae
FG
119 t.wait();
120
121 // Start three increments.
b32b8144
FG
122 post(*s, bindns::bind(sleep_increment, ioc, count));
123 post(*s, bindns::bind(sleep_increment, ioc, count));
124 post(*s, bindns::bind(sleep_increment, ioc, count));
7c673cae
FG
125}
126
127void throw_exception()
128{
129 throw 1;
130}
131
b32b8144 132void io_context_run(io_context* ioc)
7c673cae 133{
b32b8144 134 ioc->run();
7c673cae
FG
135}
136
137void strand_test()
138{
b32b8144 139 io_context ioc;
92f5a8d4 140 strand<io_context::executor_type> s = make_strand(ioc);
7c673cae
FG
141 int count = 0;
142
b32b8144 143 post(ioc, bindns::bind(increment_without_lock, &s, &count));
7c673cae
FG
144
145 // No handlers can be called until run() is called.
146 BOOST_ASIO_CHECK(count == 0);
147
b32b8144 148 ioc.run();
7c673cae
FG
149
150 // The run() call will not return until all work has finished.
151 BOOST_ASIO_CHECK(count == 1);
152
153 count = 0;
b32b8144
FG
154 ioc.restart();
155 post(s, bindns::bind(increment_with_lock, &s, &count));
7c673cae
FG
156
157 // No handlers can be called until run() is called.
158 BOOST_ASIO_CHECK(count == 0);
159
b32b8144 160 ioc.run();
7c673cae
FG
161
162 // The run() call will not return until all work has finished.
163 BOOST_ASIO_CHECK(count == 1);
164
165 count = 0;
b32b8144
FG
166 ioc.restart();
167 post(ioc, bindns::bind(start_sleep_increments, &ioc, &s, &count));
168 boost::asio::detail::thread thread1(bindns::bind(io_context_run, &ioc));
169 boost::asio::detail::thread thread2(bindns::bind(io_context_run, &ioc));
7c673cae
FG
170
171 // Check all events run one after another even though there are two threads.
b32b8144 172 timer timer1(ioc, chronons::seconds(3));
7c673cae
FG
173 timer1.wait();
174 BOOST_ASIO_CHECK(count == 0);
b32b8144 175#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae 176 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
b32b8144
FG
177#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
178 timer1.expires_at(timer1.expiry() + chronons::seconds(2));
179#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae
FG
180 timer1.wait();
181 BOOST_ASIO_CHECK(count == 1);
b32b8144 182#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae 183 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
b32b8144
FG
184#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
185 timer1.expires_at(timer1.expiry() + chronons::seconds(2));
186#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae
FG
187 timer1.wait();
188 BOOST_ASIO_CHECK(count == 2);
189
190 thread1.join();
191 thread2.join();
192
193 // The run() calls will not return until all work has finished.
194 BOOST_ASIO_CHECK(count == 3);
195
196 count = 0;
197 int exception_count = 0;
b32b8144
FG
198 ioc.restart();
199 post(s, throw_exception);
200 post(s, bindns::bind(increment, &count));
201 post(s, bindns::bind(increment, &count));
202 post(s, throw_exception);
203 post(s, bindns::bind(increment, &count));
7c673cae
FG
204
205 // No handlers can be called until run() is called.
206 BOOST_ASIO_CHECK(count == 0);
207 BOOST_ASIO_CHECK(exception_count == 0);
208
209 for (;;)
210 {
211 try
212 {
b32b8144 213 ioc.run();
7c673cae
FG
214 break;
215 }
216 catch (int)
217 {
218 ++exception_count;
219 }
220 }
221
222 // The run() calls will not return until all work has finished.
223 BOOST_ASIO_CHECK(count == 3);
224 BOOST_ASIO_CHECK(exception_count == 2);
225
226 count = 0;
b32b8144 227 ioc.restart();
7c673cae
FG
228
229 // Check for clean shutdown when handlers posted through an orphaned strand
230 // are abandoned.
231 {
92f5a8d4 232 strand<io_context::executor_type> s2 = make_strand(ioc.get_executor());
b32b8144
FG
233 post(s2, bindns::bind(increment, &count));
234 post(s2, bindns::bind(increment, &count));
235 post(s2, bindns::bind(increment, &count));
7c673cae
FG
236 }
237
238 // No handlers can be called until run() is called.
239 BOOST_ASIO_CHECK(count == 0);
240}
241
f67539c2
TL
242void strand_conversion_test()
243{
244 io_context ioc;
245 strand<io_context::executor_type> s1 = make_strand(ioc);
246
247 // Converting constructors.
248
249 strand<executor> s2(s1);
250 strand<executor> s3 = strand<io_context::executor_type>(s1);
251
252 // Converting assignment.
253
254 s3 = s1;
255 s3 = strand<io_context::executor_type>(s1);
256}
257
20effc67
TL
258void strand_query_test()
259{
260 io_context ioc;
261 strand<io_context::executor_type> s1 = make_strand(ioc);
262
263 BOOST_ASIO_CHECK(
264 &boost::asio::query(s1, boost::asio::execution::context)
265 == &ioc);
266
267 BOOST_ASIO_CHECK(
268 boost::asio::query(s1, boost::asio::execution::blocking)
269 == boost::asio::execution::blocking.possibly);
270
271 BOOST_ASIO_CHECK(
272 boost::asio::query(s1, boost::asio::execution::blocking.possibly)
273 == boost::asio::execution::blocking.possibly);
274
275 BOOST_ASIO_CHECK(
276 boost::asio::query(s1, boost::asio::execution::outstanding_work)
277 == boost::asio::execution::outstanding_work.untracked);
278
279 BOOST_ASIO_CHECK(
280 boost::asio::query(s1, boost::asio::execution::outstanding_work.untracked)
281 == boost::asio::execution::outstanding_work.untracked);
282
283 BOOST_ASIO_CHECK(
284 boost::asio::query(s1, boost::asio::execution::relationship)
285 == boost::asio::execution::relationship.fork);
286
287 BOOST_ASIO_CHECK(
288 boost::asio::query(s1, boost::asio::execution::relationship.fork)
289 == boost::asio::execution::relationship.fork);
290
291 BOOST_ASIO_CHECK(
292 boost::asio::query(s1, boost::asio::execution::mapping)
293 == boost::asio::execution::mapping.thread);
294
295 BOOST_ASIO_CHECK(
296 boost::asio::query(s1, boost::asio::execution::allocator)
297 == std::allocator<void>());
298}
299
300void strand_execute_test()
301{
302 io_context ioc;
303 strand<io_context::executor_type> s1 = make_strand(ioc);
304 int count = 0;
305
306 boost::asio::execution::execute(s1, bindns::bind(increment, &count));
307
308 // No handlers can be called until run() is called.
309 BOOST_ASIO_CHECK(!ioc.stopped());
310 BOOST_ASIO_CHECK(count == 0);
311
312 ioc.run();
313
314 // The run() call will not return until all work has finished.
315 BOOST_ASIO_CHECK(ioc.stopped());
316 BOOST_ASIO_CHECK(count == 1);
317
318 count = 0;
319 ioc.restart();
320 boost::asio::execution::execute(
321 boost::asio::require(s1, boost::asio::execution::blocking.possibly),
322 bindns::bind(increment, &count));
323
324 // No handlers can be called until run() is called.
325 BOOST_ASIO_CHECK(!ioc.stopped());
326 BOOST_ASIO_CHECK(count == 0);
327
328 ioc.run();
329
330 // The run() call will not return until all work has finished.
331 BOOST_ASIO_CHECK(ioc.stopped());
332 BOOST_ASIO_CHECK(count == 1);
333
334 count = 0;
335 ioc.restart();
336 boost::asio::execution::execute(
337 boost::asio::require(s1, boost::asio::execution::blocking.never),
338 bindns::bind(increment, &count));
339
340 // No handlers can be called until run() is called.
341 BOOST_ASIO_CHECK(!ioc.stopped());
342 BOOST_ASIO_CHECK(count == 0);
343
344 ioc.run();
345
346 // The run() call will not return until all work has finished.
347 BOOST_ASIO_CHECK(ioc.stopped());
348 BOOST_ASIO_CHECK(count == 1);
349
350 count = 0;
351 ioc.restart();
352 BOOST_ASIO_CHECK(!ioc.stopped());
353
354 boost::asio::execution::execute(
355 boost::asio::require(s1,
356 boost::asio::execution::blocking.never,
357 boost::asio::execution::outstanding_work.tracked),
358 bindns::bind(increment, &count));
359
360 // No handlers can be called until run() is called.
361 BOOST_ASIO_CHECK(!ioc.stopped());
362 BOOST_ASIO_CHECK(count == 0);
363
364 ioc.run();
365
366 // The run() call will not return until all work has finished.
367 BOOST_ASIO_CHECK(ioc.stopped());
368 BOOST_ASIO_CHECK(count == 1);
369
370 count = 0;
371 ioc.restart();
372 boost::asio::execution::execute(
373 boost::asio::require(s1,
374 boost::asio::execution::blocking.never,
375 boost::asio::execution::outstanding_work.untracked),
376 bindns::bind(increment, &count));
377
378 // No handlers can be called until run() is called.
379 BOOST_ASIO_CHECK(!ioc.stopped());
380 BOOST_ASIO_CHECK(count == 0);
381
382 ioc.run();
383
384 // The run() call will not return until all work has finished.
385 BOOST_ASIO_CHECK(ioc.stopped());
386 BOOST_ASIO_CHECK(count == 1);
387
388 count = 0;
389 ioc.restart();
390 boost::asio::execution::execute(
391 boost::asio::require(s1,
392 boost::asio::execution::blocking.never,
393 boost::asio::execution::outstanding_work.untracked,
394 boost::asio::execution::relationship.fork),
395 bindns::bind(increment, &count));
396
397 // No handlers can be called until run() is called.
398 BOOST_ASIO_CHECK(!ioc.stopped());
399 BOOST_ASIO_CHECK(count == 0);
400
401 ioc.run();
402
403 // The run() call will not return until all work has finished.
404 BOOST_ASIO_CHECK(ioc.stopped());
405 BOOST_ASIO_CHECK(count == 1);
406
407 count = 0;
408 ioc.restart();
409 boost::asio::execution::execute(
410 boost::asio::require(s1,
411 boost::asio::execution::blocking.never,
412 boost::asio::execution::outstanding_work.untracked,
413 boost::asio::execution::relationship.continuation),
414 bindns::bind(increment, &count));
415
416 // No handlers can be called until run() is called.
417 BOOST_ASIO_CHECK(!ioc.stopped());
418 BOOST_ASIO_CHECK(count == 0);
419
420 ioc.run();
421
422 // The run() call will not return until all work has finished.
423 BOOST_ASIO_CHECK(ioc.stopped());
424 BOOST_ASIO_CHECK(count == 1);
425
426 count = 0;
427 ioc.restart();
428 boost::asio::execution::execute(
429 boost::asio::prefer(
430 boost::asio::require(s1,
431 boost::asio::execution::blocking.never,
432 boost::asio::execution::outstanding_work.untracked,
433 boost::asio::execution::relationship.continuation),
434 boost::asio::execution::allocator(std::allocator<void>())),
435 bindns::bind(increment, &count));
436
437 // No handlers can be called until run() is called.
438 BOOST_ASIO_CHECK(!ioc.stopped());
439 BOOST_ASIO_CHECK(count == 0);
440
441 ioc.run();
442
443 // The run() call will not return until all work has finished.
444 BOOST_ASIO_CHECK(ioc.stopped());
445 BOOST_ASIO_CHECK(count == 1);
446
447 count = 0;
448 ioc.restart();
449 boost::asio::execution::execute(
450 boost::asio::prefer(
451 boost::asio::require(s1,
452 boost::asio::execution::blocking.never,
453 boost::asio::execution::outstanding_work.untracked,
454 boost::asio::execution::relationship.continuation),
455 boost::asio::execution::allocator),
456 bindns::bind(increment, &count));
457
458 // No handlers can be called until run() is called.
459 BOOST_ASIO_CHECK(!ioc.stopped());
460 BOOST_ASIO_CHECK(count == 0);
461
462 ioc.run();
463
464 // The run() call will not return until all work has finished.
465 BOOST_ASIO_CHECK(ioc.stopped());
466 BOOST_ASIO_CHECK(count == 1);
467}
468
7c673cae
FG
469BOOST_ASIO_TEST_SUITE
470(
471 "strand",
472 BOOST_ASIO_TEST_CASE(strand_test)
f67539c2 473 BOOST_ASIO_COMPILE_TEST_CASE(strand_conversion_test)
20effc67
TL
474 BOOST_ASIO_TEST_CASE(strand_query_test)
475 BOOST_ASIO_TEST_CASE(strand_execute_test)
7c673cae 476)