]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/test/strand.cpp
5 // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
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)
16 // Test that header file is self-contained.
17 #include <boost/asio/strand.hpp>
20 #include <boost/asio/executor.hpp>
21 #include <boost/asio/io_context.hpp>
22 #include <boost/asio/dispatch.hpp>
23 #include <boost/asio/post.hpp>
24 #include <boost/asio/detail/thread.hpp>
25 #include "unit_test.hpp"
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)
33 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
34 # include <boost/bind/bind.hpp>
35 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
36 # include <functional>
37 #endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
39 using namespace boost::asio
;
41 #if defined(BOOST_ASIO_HAS_BOOST_BIND)
42 namespace bindns
= boost
;
43 #else // defined(BOOST_ASIO_HAS_BOOST_BIND)
44 namespace bindns
= std
;
47 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
48 typedef deadline_timer timer
;
49 namespace chronons
= boost::posix_time
;
50 #elif defined(BOOST_ASIO_HAS_CHRONO)
51 typedef steady_timer timer
;
52 namespace chronons
= boost::asio::chrono
;
53 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
55 void increment(int* count
)
60 void increment_without_lock(strand
<io_context::executor_type
>* s
, int* count
)
62 BOOST_ASIO_CHECK(!s
->running_in_this_thread());
64 int original_count
= *count
;
66 dispatch(*s
, bindns::bind(increment
, count
));
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);
73 void increment_with_lock(strand
<io_context::executor_type
>* s
, int* count
)
75 BOOST_ASIO_CHECK(s
->running_in_this_thread());
77 int original_count
= *count
;
79 dispatch(*s
, bindns::bind(increment
, count
));
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);
86 void sleep_increment(io_context
* ioc
, int* count
)
88 timer
t(*ioc
, chronons::seconds(2));
94 void increment_by_a(int* count
, int a
)
99 void increment_by_a_b(int* count
, int a
, int b
)
104 void increment_by_a_b_c(int* count
, int a
, int b
, int c
)
106 (*count
) += a
+ b
+ c
;
109 void increment_by_a_b_c_d(int* count
, int a
, int b
, int c
, int d
)
111 (*count
) += a
+ b
+ c
+ d
;
114 void start_sleep_increments(io_context
* ioc
,
115 strand
<io_context::executor_type
>* s
, int* count
)
117 // Give all threads a chance to start.
118 timer
t(*ioc
, chronons::seconds(2));
121 // Start three increments.
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
));
127 void throw_exception()
132 void io_context_run(io_context
* ioc
)
140 strand
<io_context::executor_type
> s
= make_strand(ioc
);
143 post(ioc
, bindns::bind(increment_without_lock
, &s
, &count
));
145 // No handlers can be called until run() is called.
146 BOOST_ASIO_CHECK(count
== 0);
150 // The run() call will not return until all work has finished.
151 BOOST_ASIO_CHECK(count
== 1);
155 post(s
, bindns::bind(increment_with_lock
, &s
, &count
));
157 // No handlers can be called until run() is called.
158 BOOST_ASIO_CHECK(count
== 0);
162 // The run() call will not return until all work has finished.
163 BOOST_ASIO_CHECK(count
== 1);
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
));
171 // Check all events run one after another even though there are two threads.
172 timer
timer1(ioc
, chronons::seconds(3));
174 BOOST_ASIO_CHECK(count
== 0);
175 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
176 timer1
.expires_at(timer1
.expires_at() + chronons::seconds(2));
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)
181 BOOST_ASIO_CHECK(count
== 1);
182 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
183 timer1
.expires_at(timer1
.expires_at() + chronons::seconds(2));
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)
188 BOOST_ASIO_CHECK(count
== 2);
193 // The run() calls will not return until all work has finished.
194 BOOST_ASIO_CHECK(count
== 3);
197 int exception_count
= 0;
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
));
205 // No handlers can be called until run() is called.
206 BOOST_ASIO_CHECK(count
== 0);
207 BOOST_ASIO_CHECK(exception_count
== 0);
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);
229 // Check for clean shutdown when handlers posted through an orphaned strand
232 strand
<io_context::executor_type
> s2
= make_strand(ioc
.get_executor());
233 post(s2
, bindns::bind(increment
, &count
));
234 post(s2
, bindns::bind(increment
, &count
));
235 post(s2
, bindns::bind(increment
, &count
));
238 // No handlers can be called until run() is called.
239 BOOST_ASIO_CHECK(count
== 0);
242 void strand_conversion_test()
245 strand
<io_context::executor_type
> s1
= make_strand(ioc
);
247 // Converting constructors.
249 strand
<executor
> s2(s1
);
250 strand
<executor
> s3
= strand
<io_context::executor_type
>(s1
);
252 // Converting assignment.
255 s3
= strand
<io_context::executor_type
>(s1
);
258 void strand_query_test()
261 strand
<io_context::executor_type
> s1
= make_strand(ioc
);
264 &boost::asio::query(s1
, boost::asio::execution::context
)
268 boost::asio::query(s1
, boost::asio::execution::blocking
)
269 == boost::asio::execution::blocking
.possibly
);
272 boost::asio::query(s1
, boost::asio::execution::blocking
.possibly
)
273 == boost::asio::execution::blocking
.possibly
);
276 boost::asio::query(s1
, boost::asio::execution::outstanding_work
)
277 == boost::asio::execution::outstanding_work
.untracked
);
280 boost::asio::query(s1
, boost::asio::execution::outstanding_work
.untracked
)
281 == boost::asio::execution::outstanding_work
.untracked
);
284 boost::asio::query(s1
, boost::asio::execution::relationship
)
285 == boost::asio::execution::relationship
.fork
);
288 boost::asio::query(s1
, boost::asio::execution::relationship
.fork
)
289 == boost::asio::execution::relationship
.fork
);
292 boost::asio::query(s1
, boost::asio::execution::mapping
)
293 == boost::asio::execution::mapping
.thread
);
296 boost::asio::query(s1
, boost::asio::execution::allocator
)
297 == std::allocator
<void>());
300 void strand_execute_test()
303 strand
<io_context::executor_type
> s1
= make_strand(ioc
);
306 boost::asio::execution::execute(s1
, bindns::bind(increment
, &count
));
308 // No handlers can be called until run() is called.
309 BOOST_ASIO_CHECK(!ioc
.stopped());
310 BOOST_ASIO_CHECK(count
== 0);
314 // The run() call will not return until all work has finished.
315 BOOST_ASIO_CHECK(ioc
.stopped());
316 BOOST_ASIO_CHECK(count
== 1);
320 boost::asio::execution::execute(
321 boost::asio::require(s1
, boost::asio::execution::blocking
.possibly
),
322 bindns::bind(increment
, &count
));
324 // No handlers can be called until run() is called.
325 BOOST_ASIO_CHECK(!ioc
.stopped());
326 BOOST_ASIO_CHECK(count
== 0);
330 // The run() call will not return until all work has finished.
331 BOOST_ASIO_CHECK(ioc
.stopped());
332 BOOST_ASIO_CHECK(count
== 1);
336 boost::asio::execution::execute(
337 boost::asio::require(s1
, boost::asio::execution::blocking
.never
),
338 bindns::bind(increment
, &count
));
340 // No handlers can be called until run() is called.
341 BOOST_ASIO_CHECK(!ioc
.stopped());
342 BOOST_ASIO_CHECK(count
== 0);
346 // The run() call will not return until all work has finished.
347 BOOST_ASIO_CHECK(ioc
.stopped());
348 BOOST_ASIO_CHECK(count
== 1);
352 BOOST_ASIO_CHECK(!ioc
.stopped());
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
));
360 // No handlers can be called until run() is called.
361 BOOST_ASIO_CHECK(!ioc
.stopped());
362 BOOST_ASIO_CHECK(count
== 0);
366 // The run() call will not return until all work has finished.
367 BOOST_ASIO_CHECK(ioc
.stopped());
368 BOOST_ASIO_CHECK(count
== 1);
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
));
378 // No handlers can be called until run() is called.
379 BOOST_ASIO_CHECK(!ioc
.stopped());
380 BOOST_ASIO_CHECK(count
== 0);
384 // The run() call will not return until all work has finished.
385 BOOST_ASIO_CHECK(ioc
.stopped());
386 BOOST_ASIO_CHECK(count
== 1);
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
));
397 // No handlers can be called until run() is called.
398 BOOST_ASIO_CHECK(!ioc
.stopped());
399 BOOST_ASIO_CHECK(count
== 0);
403 // The run() call will not return until all work has finished.
404 BOOST_ASIO_CHECK(ioc
.stopped());
405 BOOST_ASIO_CHECK(count
== 1);
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
));
416 // No handlers can be called until run() is called.
417 BOOST_ASIO_CHECK(!ioc
.stopped());
418 BOOST_ASIO_CHECK(count
== 0);
422 // The run() call will not return until all work has finished.
423 BOOST_ASIO_CHECK(ioc
.stopped());
424 BOOST_ASIO_CHECK(count
== 1);
428 boost::asio::execution::execute(
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
));
437 // No handlers can be called until run() is called.
438 BOOST_ASIO_CHECK(!ioc
.stopped());
439 BOOST_ASIO_CHECK(count
== 0);
443 // The run() call will not return until all work has finished.
444 BOOST_ASIO_CHECK(ioc
.stopped());
445 BOOST_ASIO_CHECK(count
== 1);
449 boost::asio::execution::execute(
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
));
458 // No handlers can be called until run() is called.
459 BOOST_ASIO_CHECK(!ioc
.stopped());
460 BOOST_ASIO_CHECK(count
== 0);
464 // The run() call will not return until all work has finished.
465 BOOST_ASIO_CHECK(ioc
.stopped());
466 BOOST_ASIO_CHECK(count
== 1);
469 BOOST_ASIO_TEST_SUITE
472 BOOST_ASIO_TEST_CASE(strand_test
)
473 BOOST_ASIO_COMPILE_TEST_CASE(strand_conversion_test
)
474 BOOST_ASIO_TEST_CASE(strand_query_test
)
475 BOOST_ASIO_TEST_CASE(strand_execute_test
)