]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/test/strand.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / asio / test / strand.cpp
CommitLineData
7c673cae
FG
1//
2// strand.cpp
3// ~~~~~~~~~~
4//
92f5a8d4 5// Copyright (c) 2003-2019 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>
b32b8144
FG
20#include <boost/asio/io_context.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)
33# include <boost/bind.hpp>
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
92f5a8d4 59void increment_without_lock(strand<io_context::executor_type>* s, int* count)
7c673cae
FG
60{
61 BOOST_ASIO_CHECK(!s->running_in_this_thread());
62
63 int original_count = *count;
64
b32b8144 65 dispatch(*s, bindns::bind(increment, count));
7c673cae
FG
66
67 // No other functions are currently executing through the locking dispatcher,
68 // so the previous call to dispatch should have successfully nested.
69 BOOST_ASIO_CHECK(*count == original_count + 1);
70}
71
92f5a8d4 72void increment_with_lock(strand<io_context::executor_type>* s, int* count)
7c673cae
FG
73{
74 BOOST_ASIO_CHECK(s->running_in_this_thread());
75
76 int original_count = *count;
77
b32b8144 78 dispatch(*s, bindns::bind(increment, count));
7c673cae
FG
79
80 // The current function already holds the strand's lock, so the
81 // previous call to dispatch should have successfully nested.
82 BOOST_ASIO_CHECK(*count == original_count + 1);
83}
84
b32b8144 85void sleep_increment(io_context* ioc, int* count)
7c673cae 86{
b32b8144 87 timer t(*ioc, chronons::seconds(2));
7c673cae
FG
88 t.wait();
89
90 ++(*count);
91}
92
b32b8144
FG
93void increment_by_a(int* count, int a)
94{
95 (*count) += a;
96}
97
98void increment_by_a_b(int* count, int a, int b)
99{
100 (*count) += a + b;
101}
102
103void increment_by_a_b_c(int* count, int a, int b, int c)
104{
105 (*count) += a + b + c;
106}
107
108void increment_by_a_b_c_d(int* count, int a, int b, int c, int d)
109{
110 (*count) += a + b + c + d;
111}
112
92f5a8d4
TL
113void start_sleep_increments(io_context* ioc,
114 strand<io_context::executor_type>* s, int* count)
7c673cae
FG
115{
116 // Give all threads a chance to start.
b32b8144 117 timer t(*ioc, chronons::seconds(2));
7c673cae
FG
118 t.wait();
119
120 // Start three increments.
b32b8144
FG
121 post(*s, bindns::bind(sleep_increment, ioc, count));
122 post(*s, bindns::bind(sleep_increment, ioc, count));
123 post(*s, bindns::bind(sleep_increment, ioc, count));
7c673cae
FG
124}
125
126void throw_exception()
127{
128 throw 1;
129}
130
b32b8144 131void io_context_run(io_context* ioc)
7c673cae 132{
b32b8144 133 ioc->run();
7c673cae
FG
134}
135
136void strand_test()
137{
b32b8144 138 io_context ioc;
92f5a8d4 139 strand<io_context::executor_type> s = make_strand(ioc);
7c673cae
FG
140 int count = 0;
141
b32b8144 142 post(ioc, bindns::bind(increment_without_lock, &s, &count));
7c673cae
FG
143
144 // No handlers can be called until run() is called.
145 BOOST_ASIO_CHECK(count == 0);
146
b32b8144 147 ioc.run();
7c673cae
FG
148
149 // The run() call will not return until all work has finished.
150 BOOST_ASIO_CHECK(count == 1);
151
152 count = 0;
b32b8144
FG
153 ioc.restart();
154 post(s, bindns::bind(increment_with_lock, &s, &count));
7c673cae
FG
155
156 // No handlers can be called until run() is called.
157 BOOST_ASIO_CHECK(count == 0);
158
b32b8144 159 ioc.run();
7c673cae
FG
160
161 // The run() call will not return until all work has finished.
162 BOOST_ASIO_CHECK(count == 1);
163
164 count = 0;
b32b8144
FG
165 ioc.restart();
166 post(ioc, bindns::bind(start_sleep_increments, &ioc, &s, &count));
167 boost::asio::detail::thread thread1(bindns::bind(io_context_run, &ioc));
168 boost::asio::detail::thread thread2(bindns::bind(io_context_run, &ioc));
7c673cae
FG
169
170 // Check all events run one after another even though there are two threads.
b32b8144 171 timer timer1(ioc, chronons::seconds(3));
7c673cae
FG
172 timer1.wait();
173 BOOST_ASIO_CHECK(count == 0);
b32b8144 174#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae 175 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
b32b8144
FG
176#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
177 timer1.expires_at(timer1.expiry() + chronons::seconds(2));
178#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae
FG
179 timer1.wait();
180 BOOST_ASIO_CHECK(count == 1);
b32b8144 181#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae 182 timer1.expires_at(timer1.expires_at() + chronons::seconds(2));
b32b8144
FG
183#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
184 timer1.expires_at(timer1.expiry() + chronons::seconds(2));
185#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
7c673cae
FG
186 timer1.wait();
187 BOOST_ASIO_CHECK(count == 2);
188
189 thread1.join();
190 thread2.join();
191
192 // The run() calls will not return until all work has finished.
193 BOOST_ASIO_CHECK(count == 3);
194
195 count = 0;
196 int exception_count = 0;
b32b8144
FG
197 ioc.restart();
198 post(s, throw_exception);
199 post(s, bindns::bind(increment, &count));
200 post(s, bindns::bind(increment, &count));
201 post(s, throw_exception);
202 post(s, bindns::bind(increment, &count));
7c673cae
FG
203
204 // No handlers can be called until run() is called.
205 BOOST_ASIO_CHECK(count == 0);
206 BOOST_ASIO_CHECK(exception_count == 0);
207
208 for (;;)
209 {
210 try
211 {
b32b8144 212 ioc.run();
7c673cae
FG
213 break;
214 }
215 catch (int)
216 {
217 ++exception_count;
218 }
219 }
220
221 // The run() calls will not return until all work has finished.
222 BOOST_ASIO_CHECK(count == 3);
223 BOOST_ASIO_CHECK(exception_count == 2);
224
225 count = 0;
b32b8144 226 ioc.restart();
7c673cae
FG
227
228 // Check for clean shutdown when handlers posted through an orphaned strand
229 // are abandoned.
230 {
92f5a8d4 231 strand<io_context::executor_type> s2 = make_strand(ioc.get_executor());
b32b8144
FG
232 post(s2, bindns::bind(increment, &count));
233 post(s2, bindns::bind(increment, &count));
234 post(s2, bindns::bind(increment, &count));
7c673cae
FG
235 }
236
237 // No handlers can be called until run() is called.
238 BOOST_ASIO_CHECK(count == 0);
239}
240
241BOOST_ASIO_TEST_SUITE
242(
243 "strand",
244 BOOST_ASIO_TEST_CASE(strand_test)
245)