]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/test/system_timer.cpp
bump version to 15.2.11-pve1
[ceph.git] / ceph / src / boost / libs / asio / test / system_timer.cpp
CommitLineData
7c673cae
FG
1//
2// system_timer.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// Prevent link dependency on the Boost.System library.
17#if !defined(BOOST_SYSTEM_NO_DEPRECATED)
18#define BOOST_SYSTEM_NO_DEPRECATED
19#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED)
20
21// Test that header file is self-contained.
22#include <boost/asio/system_timer.hpp>
23
24#include "unit_test.hpp"
25
26#if defined(BOOST_ASIO_HAS_STD_CHRONO)
27
b32b8144
FG
28#include <boost/asio/executor_work_guard.hpp>
29#include <boost/asio/io_context.hpp>
7c673cae
FG
30#include <boost/asio/detail/thread.hpp>
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
38#if defined(BOOST_ASIO_HAS_BOOST_BIND)
39namespace bindns = boost;
40#else // defined(BOOST_ASIO_HAS_BOOST_BIND)
41namespace bindns = std;
42#endif // defined(BOOST_ASIO_HAS_BOOST_BIND)
43
7c673cae
FG
44void increment(int* count)
45{
46 ++(*count);
47}
48
49void decrement_to_zero(boost::asio::system_timer* t, int* count)
50{
51 if (*count > 0)
52 {
53 --(*count);
54
55 int before_value = *count;
56
b32b8144 57 t->expires_at(t->expiry() + boost::asio::chrono::seconds(1));
7c673cae
FG
58 t->async_wait(bindns::bind(decrement_to_zero, t, count));
59
60 // Completion cannot nest, so count value should remain unchanged.
61 BOOST_ASIO_CHECK(*count == before_value);
62 }
63}
64
65void increment_if_not_cancelled(int* count,
66 const boost::system::error_code& ec)
67{
68 if (!ec)
69 ++(*count);
70}
71
72void cancel_timer(boost::asio::system_timer* t)
73{
74 std::size_t num_cancelled = t->cancel();
75 BOOST_ASIO_CHECK(num_cancelled == 1);
76}
77
78void cancel_one_timer(boost::asio::system_timer* t)
79{
80 std::size_t num_cancelled = t->cancel_one();
81 BOOST_ASIO_CHECK(num_cancelled == 1);
82}
83
84boost::asio::system_timer::time_point now()
85{
86 return boost::asio::system_timer::clock_type::now();
87}
88
89void system_timer_test()
90{
b32b8144
FG
91 using boost::asio::chrono::seconds;
92 using boost::asio::chrono::microseconds;
7c673cae
FG
93#if !defined(BOOST_ASIO_HAS_BOOST_BIND)
94 using std::placeholders::_1;
95 using std::placeholders::_2;
96#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND)
97
b32b8144 98 boost::asio::io_context ioc;
92f5a8d4 99 const boost::asio::io_context::executor_type ioc_ex = ioc.get_executor();
7c673cae
FG
100 int count = 0;
101
102 boost::asio::system_timer::time_point start = now();
103
b32b8144 104 boost::asio::system_timer t1(ioc, seconds(1));
7c673cae
FG
105 t1.wait();
106
107 // The timer must block until after its expiry time.
108 boost::asio::system_timer::time_point end = now();
109 boost::asio::system_timer::time_point expected_end = start + seconds(1);
110 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
111
112 start = now();
113
92f5a8d4 114 boost::asio::system_timer t2(ioc_ex, seconds(1) + microseconds(500000));
7c673cae
FG
115 t2.wait();
116
117 // The timer must block until after its expiry time.
118 end = now();
119 expected_end = start + seconds(1) + microseconds(500000);
120 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
121
b32b8144 122 t2.expires_at(t2.expiry() + seconds(1));
7c673cae
FG
123 t2.wait();
124
125 // The timer must block until after its expiry time.
126 end = now();
127 expected_end += seconds(1);
128 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
129
130 start = now();
131
b32b8144 132 t2.expires_after(seconds(1) + microseconds(200000));
7c673cae
FG
133 t2.wait();
134
135 // The timer must block until after its expiry time.
136 end = now();
137 expected_end = start + seconds(1) + microseconds(200000);
138 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
139
140 start = now();
141
b32b8144 142 boost::asio::system_timer t3(ioc, seconds(5));
7c673cae
FG
143 t3.async_wait(bindns::bind(increment, &count));
144
145 // No completions can be delivered 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 operations have finished, and
151 // this should not be until after the timer's expiry time.
152 BOOST_ASIO_CHECK(count == 1);
153 end = now();
154 expected_end = start + seconds(1);
155 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
156
157 count = 3;
158 start = now();
159
b32b8144 160 boost::asio::system_timer t4(ioc, seconds(1));
7c673cae
FG
161 t4.async_wait(bindns::bind(decrement_to_zero, &t4, &count));
162
163 // No completions can be delivered until run() is called.
164 BOOST_ASIO_CHECK(count == 3);
165
b32b8144
FG
166 ioc.restart();
167 ioc.run();
7c673cae
FG
168
169 // The run() call will not return until all operations have finished, and
170 // this should not be until after the timer's final expiry time.
171 BOOST_ASIO_CHECK(count == 0);
172 end = now();
173 expected_end = start + seconds(3);
174 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
175
176 count = 0;
177 start = now();
178
b32b8144 179 boost::asio::system_timer t5(ioc, seconds(10));
7c673cae 180 t5.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
b32b8144 181 boost::asio::system_timer t6(ioc, seconds(1));
7c673cae
FG
182 t6.async_wait(bindns::bind(cancel_timer, &t5));
183
184 // No completions can be delivered until run() is called.
185 BOOST_ASIO_CHECK(count == 0);
186
b32b8144
FG
187 ioc.restart();
188 ioc.run();
7c673cae
FG
189
190 // The timer should have been cancelled, so count should not have changed.
191 // The total run time should not have been much more than 1 second (and
192 // certainly far less than 10 seconds).
193 BOOST_ASIO_CHECK(count == 0);
194 end = now();
195 expected_end = start + seconds(2);
196 BOOST_ASIO_CHECK(end < expected_end);
197
198 // Wait on the timer again without cancelling it. This time the asynchronous
199 // wait should run to completion and increment the counter.
200 t5.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
201
b32b8144
FG
202 ioc.restart();
203 ioc.run();
7c673cae
FG
204
205 // The timer should not have been cancelled, so count should have changed.
206 // The total time since the timer was created should be more than 10 seconds.
207 BOOST_ASIO_CHECK(count == 1);
208 end = now();
209 expected_end = start + seconds(10);
210 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
211
212 count = 0;
213 start = now();
214
215 // Start two waits on a timer, one of which will be cancelled. The one
216 // which is not cancelled should still run to completion and increment the
217 // counter.
b32b8144 218 boost::asio::system_timer t7(ioc, seconds(3));
7c673cae
FG
219 t7.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
220 t7.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
b32b8144 221 boost::asio::system_timer t8(ioc, seconds(1));
7c673cae
FG
222 t8.async_wait(bindns::bind(cancel_one_timer, &t7));
223
b32b8144
FG
224 ioc.restart();
225 ioc.run();
7c673cae
FG
226
227 // One of the waits should not have been cancelled, so count should have
228 // changed. The total time since the timer was created should be more than 3
229 // seconds.
230 BOOST_ASIO_CHECK(count == 1);
231 end = now();
232 expected_end = start + seconds(3);
233 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
234}
235
b32b8144 236struct timer_handler
7c673cae 237{
b32b8144
FG
238 timer_handler() {}
239 void operator()(const boost::system::error_code&) {}
240#if defined(BOOST_ASIO_HAS_MOVE)
241 timer_handler(timer_handler&&) {}
242private:
243 timer_handler(const timer_handler&);
244#endif // defined(BOOST_ASIO_HAS_MOVE)
245};
7c673cae
FG
246
247void system_timer_cancel_test()
248{
b32b8144 249 static boost::asio::io_context io_context;
7c673cae
FG
250 struct timer
251 {
252 boost::asio::system_timer t;
b32b8144 253 timer() : t(io_context)
7c673cae
FG
254 {
255 t.expires_at((boost::asio::system_timer::time_point::max)());
256 }
257 } timers[50];
258
b32b8144
FG
259 timers[2].t.async_wait(timer_handler());
260 timers[41].t.async_wait(timer_handler());
7c673cae 261 for (int i = 10; i < 20; ++i)
b32b8144 262 timers[i].t.async_wait(timer_handler());
7c673cae
FG
263
264 BOOST_ASIO_CHECK(timers[2].t.cancel() == 1);
265 BOOST_ASIO_CHECK(timers[41].t.cancel() == 1);
266 for (int i = 10; i < 20; ++i)
267 BOOST_ASIO_CHECK(timers[i].t.cancel() == 1);
268}
269
270struct custom_allocation_timer_handler
271{
272 custom_allocation_timer_handler(int* count) : count_(count) {}
273 void operator()(const boost::system::error_code&) {}
274 int* count_;
275};
276
277void* asio_handler_allocate(std::size_t size,
278 custom_allocation_timer_handler* handler)
279{
280 ++(*handler->count_);
281 return ::operator new(size);
282}
283
284void asio_handler_deallocate(void* pointer, std::size_t,
285 custom_allocation_timer_handler* handler)
286{
287 --(*handler->count_);
288 ::operator delete(pointer);
289}
290
291void system_timer_custom_allocation_test()
292{
b32b8144 293 static boost::asio::io_context io_context;
7c673cae
FG
294 struct timer
295 {
296 boost::asio::system_timer t;
b32b8144 297 timer() : t(io_context) {}
7c673cae
FG
298 } timers[100];
299
300 int allocation_count = 0;
301
302 for (int i = 0; i < 50; ++i)
303 {
304 timers[i].t.expires_at((boost::asio::system_timer::time_point::max)());
305 timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
306 }
307
308 for (int i = 50; i < 100; ++i)
309 {
310 timers[i].t.expires_at((boost::asio::system_timer::time_point::min)());
311 timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
312 }
313
314 for (int i = 0; i < 50; ++i)
315 timers[i].t.cancel();
316
b32b8144 317 io_context.run();
7c673cae
FG
318
319 BOOST_ASIO_CHECK(allocation_count == 0);
320}
321
b32b8144 322void io_context_run(boost::asio::io_context* ioc)
7c673cae 323{
b32b8144 324 ioc->run();
7c673cae
FG
325}
326
327void system_timer_thread_test()
328{
b32b8144
FG
329 boost::asio::io_context ioc;
330 boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work
331 = boost::asio::make_work_guard(ioc);
332 boost::asio::system_timer t1(ioc);
333 boost::asio::system_timer t2(ioc);
7c673cae
FG
334 int count = 0;
335
b32b8144 336 boost::asio::detail::thread th(bindns::bind(io_context_run, &ioc));
7c673cae 337
b32b8144 338 t2.expires_after(boost::asio::chrono::seconds(2));
7c673cae
FG
339 t2.wait();
340
b32b8144 341 t1.expires_after(boost::asio::chrono::seconds(2));
7c673cae
FG
342 t1.async_wait(bindns::bind(increment, &count));
343
b32b8144 344 t2.expires_after(boost::asio::chrono::seconds(4));
7c673cae
FG
345 t2.wait();
346
b32b8144 347 ioc.stop();
7c673cae
FG
348 th.join();
349
350 BOOST_ASIO_CHECK(count == 1);
351}
352
b32b8144
FG
353#if defined(BOOST_ASIO_HAS_MOVE)
354boost::asio::system_timer make_timer(boost::asio::io_context& ioc, int* count)
355{
356 boost::asio::system_timer t(ioc);
357 t.expires_after(boost::asio::chrono::seconds(1));
358 t.async_wait(bindns::bind(increment, count));
359 return t;
360}
361#endif
362
363void system_timer_move_test()
364{
365#if defined(BOOST_ASIO_HAS_MOVE)
366 boost::asio::io_context io_context1;
367 boost::asio::io_context io_context2;
368 int count = 0;
369
370 boost::asio::system_timer t1 = make_timer(io_context1, &count);
371 boost::asio::system_timer t2 = make_timer(io_context2, &count);
372 boost::asio::system_timer t3 = std::move(t1);
373
374 t2 = std::move(t1);
375
376 io_context2.run();
377
378 BOOST_ASIO_CHECK(count == 1);
379
380 io_context1.run();
381
382 BOOST_ASIO_CHECK(count == 2);
383#endif // defined(BOOST_ASIO_HAS_MOVE)
384}
385
7c673cae
FG
386BOOST_ASIO_TEST_SUITE
387(
388 "system_timer",
389 BOOST_ASIO_TEST_CASE(system_timer_test)
390 BOOST_ASIO_TEST_CASE(system_timer_cancel_test)
391 BOOST_ASIO_TEST_CASE(system_timer_custom_allocation_test)
392 BOOST_ASIO_TEST_CASE(system_timer_thread_test)
b32b8144 393 BOOST_ASIO_TEST_CASE(system_timer_move_test)
7c673cae
FG
394)
395#else // defined(BOOST_ASIO_HAS_STD_CHRONO)
396BOOST_ASIO_TEST_SUITE
397(
398 "system_timer",
399 BOOST_ASIO_TEST_CASE(null_test)
400)
401#endif // defined(BOOST_ASIO_HAS_STD_CHRONO)