]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/test/system_timer.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / asio / test / system_timer.cpp
CommitLineData
7c673cae
FG
1//
2// system_timer.cpp
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// 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)
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
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;
f67539c2
TL
93 using bindns::placeholders::_1;
94 using bindns::placeholders::_2;
7c673cae 95
b32b8144 96 boost::asio::io_context ioc;
92f5a8d4 97 const boost::asio::io_context::executor_type ioc_ex = ioc.get_executor();
7c673cae
FG
98 int count = 0;
99
100 boost::asio::system_timer::time_point start = now();
101
b32b8144 102 boost::asio::system_timer t1(ioc, seconds(1));
7c673cae
FG
103 t1.wait();
104
105 // The timer must block until after its expiry time.
106 boost::asio::system_timer::time_point end = now();
107 boost::asio::system_timer::time_point expected_end = start + seconds(1);
108 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
109
110 start = now();
111
92f5a8d4 112 boost::asio::system_timer t2(ioc_ex, seconds(1) + microseconds(500000));
7c673cae
FG
113 t2.wait();
114
115 // The timer must block until after its expiry time.
116 end = now();
117 expected_end = start + seconds(1) + microseconds(500000);
118 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
119
b32b8144 120 t2.expires_at(t2.expiry() + seconds(1));
7c673cae
FG
121 t2.wait();
122
123 // The timer must block until after its expiry time.
124 end = now();
125 expected_end += seconds(1);
126 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
127
128 start = now();
129
b32b8144 130 t2.expires_after(seconds(1) + microseconds(200000));
7c673cae
FG
131 t2.wait();
132
133 // The timer must block until after its expiry time.
134 end = now();
135 expected_end = start + seconds(1) + microseconds(200000);
136 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
137
138 start = now();
139
b32b8144 140 boost::asio::system_timer t3(ioc, seconds(5));
7c673cae
FG
141 t3.async_wait(bindns::bind(increment, &count));
142
143 // No completions can be delivered until run() is called.
144 BOOST_ASIO_CHECK(count == 0);
145
b32b8144 146 ioc.run();
7c673cae
FG
147
148 // The run() call will not return until all operations have finished, and
149 // this should not be until after the timer's expiry time.
150 BOOST_ASIO_CHECK(count == 1);
151 end = now();
152 expected_end = start + seconds(1);
153 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
154
155 count = 3;
156 start = now();
157
b32b8144 158 boost::asio::system_timer t4(ioc, seconds(1));
7c673cae
FG
159 t4.async_wait(bindns::bind(decrement_to_zero, &t4, &count));
160
161 // No completions can be delivered until run() is called.
162 BOOST_ASIO_CHECK(count == 3);
163
b32b8144
FG
164 ioc.restart();
165 ioc.run();
7c673cae
FG
166
167 // The run() call will not return until all operations have finished, and
168 // this should not be until after the timer's final expiry time.
169 BOOST_ASIO_CHECK(count == 0);
170 end = now();
171 expected_end = start + seconds(3);
172 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
173
174 count = 0;
175 start = now();
176
b32b8144 177 boost::asio::system_timer t5(ioc, seconds(10));
7c673cae 178 t5.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
b32b8144 179 boost::asio::system_timer t6(ioc, seconds(1));
7c673cae
FG
180 t6.async_wait(bindns::bind(cancel_timer, &t5));
181
182 // No completions can be delivered until run() is called.
183 BOOST_ASIO_CHECK(count == 0);
184
b32b8144
FG
185 ioc.restart();
186 ioc.run();
7c673cae
FG
187
188 // The timer should have been cancelled, so count should not have changed.
189 // The total run time should not have been much more than 1 second (and
190 // certainly far less than 10 seconds).
191 BOOST_ASIO_CHECK(count == 0);
192 end = now();
193 expected_end = start + seconds(2);
194 BOOST_ASIO_CHECK(end < expected_end);
195
196 // Wait on the timer again without cancelling it. This time the asynchronous
197 // wait should run to completion and increment the counter.
198 t5.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
199
b32b8144
FG
200 ioc.restart();
201 ioc.run();
7c673cae
FG
202
203 // The timer should not have been cancelled, so count should have changed.
204 // The total time since the timer was created should be more than 10 seconds.
205 BOOST_ASIO_CHECK(count == 1);
206 end = now();
207 expected_end = start + seconds(10);
208 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
209
210 count = 0;
211 start = now();
212
213 // Start two waits on a timer, one of which will be cancelled. The one
214 // which is not cancelled should still run to completion and increment the
215 // counter.
b32b8144 216 boost::asio::system_timer t7(ioc, seconds(3));
7c673cae
FG
217 t7.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
218 t7.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1));
b32b8144 219 boost::asio::system_timer t8(ioc, seconds(1));
7c673cae
FG
220 t8.async_wait(bindns::bind(cancel_one_timer, &t7));
221
b32b8144
FG
222 ioc.restart();
223 ioc.run();
7c673cae
FG
224
225 // One of the waits should not have been cancelled, so count should have
226 // changed. The total time since the timer was created should be more than 3
227 // seconds.
228 BOOST_ASIO_CHECK(count == 1);
229 end = now();
230 expected_end = start + seconds(3);
231 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
232}
233
b32b8144 234struct timer_handler
7c673cae 235{
b32b8144
FG
236 timer_handler() {}
237 void operator()(const boost::system::error_code&) {}
238#if defined(BOOST_ASIO_HAS_MOVE)
239 timer_handler(timer_handler&&) {}
240private:
241 timer_handler(const timer_handler&);
242#endif // defined(BOOST_ASIO_HAS_MOVE)
243};
7c673cae
FG
244
245void system_timer_cancel_test()
246{
b32b8144 247 static boost::asio::io_context io_context;
7c673cae
FG
248 struct timer
249 {
250 boost::asio::system_timer t;
b32b8144 251 timer() : t(io_context)
7c673cae
FG
252 {
253 t.expires_at((boost::asio::system_timer::time_point::max)());
254 }
255 } timers[50];
256
b32b8144
FG
257 timers[2].t.async_wait(timer_handler());
258 timers[41].t.async_wait(timer_handler());
7c673cae 259 for (int i = 10; i < 20; ++i)
b32b8144 260 timers[i].t.async_wait(timer_handler());
7c673cae
FG
261
262 BOOST_ASIO_CHECK(timers[2].t.cancel() == 1);
263 BOOST_ASIO_CHECK(timers[41].t.cancel() == 1);
264 for (int i = 10; i < 20; ++i)
265 BOOST_ASIO_CHECK(timers[i].t.cancel() == 1);
266}
267
268struct custom_allocation_timer_handler
269{
270 custom_allocation_timer_handler(int* count) : count_(count) {}
271 void operator()(const boost::system::error_code&) {}
272 int* count_;
7c673cae 273
20effc67
TL
274 template <typename T>
275 struct allocator
276 {
277 typedef size_t size_type;
278 typedef ptrdiff_t difference_type;
279 typedef T* pointer;
280 typedef const T* const_pointer;
281 typedef T& reference;
282 typedef const T& const_reference;
283 typedef T value_type;
284
285 template <typename U>
286 struct rebind
287 {
288 typedef allocator<U> other;
289 };
7c673cae 290
20effc67
TL
291 explicit allocator(int* count) BOOST_ASIO_NOEXCEPT
292 : count_(count)
293 {
294 }
295
296 allocator(const allocator& other) BOOST_ASIO_NOEXCEPT
297 : count_(other.count_)
298 {
299 }
300
301 template <typename U>
302 allocator(const allocator<U>& other) BOOST_ASIO_NOEXCEPT
303 : count_(other.count_)
304 {
305 }
306
307 pointer allocate(size_type n, const void* = 0)
308 {
309 ++(*count_);
310 return static_cast<T*>(::operator new(sizeof(T) * n));
311 }
312
313 void deallocate(pointer p, size_type)
314 {
315 --(*count_);
316 ::operator delete(p);
317 }
318
319 size_type max_size() const
320 {
321 return ~size_type(0);
322 }
323
324 void construct(pointer p, const T& v)
325 {
326 new (p) T(v);
327 }
328
329 void destroy(pointer p)
330 {
331 p->~T();
332 }
333
334 int* count_;
335 };
336
337 typedef allocator<int> allocator_type;
338
339 allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
340 {
341 return allocator_type(count_);
342 }
343};
7c673cae
FG
344
345void system_timer_custom_allocation_test()
346{
b32b8144 347 static boost::asio::io_context io_context;
7c673cae
FG
348 struct timer
349 {
350 boost::asio::system_timer t;
b32b8144 351 timer() : t(io_context) {}
7c673cae
FG
352 } timers[100];
353
354 int allocation_count = 0;
355
356 for (int i = 0; i < 50; ++i)
357 {
358 timers[i].t.expires_at((boost::asio::system_timer::time_point::max)());
359 timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
360 }
361
362 for (int i = 50; i < 100; ++i)
363 {
364 timers[i].t.expires_at((boost::asio::system_timer::time_point::min)());
365 timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
366 }
367
368 for (int i = 0; i < 50; ++i)
369 timers[i].t.cancel();
370
b32b8144 371 io_context.run();
7c673cae
FG
372
373 BOOST_ASIO_CHECK(allocation_count == 0);
374}
375
b32b8144 376void io_context_run(boost::asio::io_context* ioc)
7c673cae 377{
b32b8144 378 ioc->run();
7c673cae
FG
379}
380
381void system_timer_thread_test()
382{
b32b8144
FG
383 boost::asio::io_context ioc;
384 boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work
385 = boost::asio::make_work_guard(ioc);
386 boost::asio::system_timer t1(ioc);
387 boost::asio::system_timer t2(ioc);
7c673cae
FG
388 int count = 0;
389
b32b8144 390 boost::asio::detail::thread th(bindns::bind(io_context_run, &ioc));
7c673cae 391
b32b8144 392 t2.expires_after(boost::asio::chrono::seconds(2));
7c673cae
FG
393 t2.wait();
394
b32b8144 395 t1.expires_after(boost::asio::chrono::seconds(2));
7c673cae
FG
396 t1.async_wait(bindns::bind(increment, &count));
397
b32b8144 398 t2.expires_after(boost::asio::chrono::seconds(4));
7c673cae
FG
399 t2.wait();
400
b32b8144 401 ioc.stop();
7c673cae
FG
402 th.join();
403
404 BOOST_ASIO_CHECK(count == 1);
405}
406
b32b8144
FG
407#if defined(BOOST_ASIO_HAS_MOVE)
408boost::asio::system_timer make_timer(boost::asio::io_context& ioc, int* count)
409{
410 boost::asio::system_timer t(ioc);
411 t.expires_after(boost::asio::chrono::seconds(1));
412 t.async_wait(bindns::bind(increment, count));
413 return t;
414}
20effc67
TL
415
416typedef boost::asio::basic_waitable_timer<
417 boost::asio::system_timer::clock_type,
418 boost::asio::system_timer::traits_type,
419 boost::asio::io_context::executor_type> io_context_system_timer;
420
421io_context_system_timer make_convertible_timer(boost::asio::io_context& ioc, int* count)
422{
423 io_context_system_timer t(ioc);
424 t.expires_after(boost::asio::chrono::seconds(1));
425 t.async_wait(bindns::bind(increment, count));
426 return t;
427}
b32b8144
FG
428#endif
429
430void system_timer_move_test()
431{
432#if defined(BOOST_ASIO_HAS_MOVE)
433 boost::asio::io_context io_context1;
434 boost::asio::io_context io_context2;
435 int count = 0;
436
437 boost::asio::system_timer t1 = make_timer(io_context1, &count);
438 boost::asio::system_timer t2 = make_timer(io_context2, &count);
439 boost::asio::system_timer t3 = std::move(t1);
440
441 t2 = std::move(t1);
442
443 io_context2.run();
444
445 BOOST_ASIO_CHECK(count == 1);
446
447 io_context1.run();
448
449 BOOST_ASIO_CHECK(count == 2);
20effc67
TL
450
451 boost::asio::system_timer t4 = make_convertible_timer(io_context1, &count);
452 boost::asio::system_timer t5 = make_convertible_timer(io_context2, &count);
453 boost::asio::system_timer t6 = std::move(t4);
454
455 t2 = std::move(t4);
456
457 io_context2.restart();
458 io_context2.run();
459
460 BOOST_ASIO_CHECK(count == 3);
461
462 io_context1.restart();
463 io_context1.run();
464
465 BOOST_ASIO_CHECK(count == 4);
b32b8144
FG
466#endif // defined(BOOST_ASIO_HAS_MOVE)
467}
468
7c673cae
FG
469BOOST_ASIO_TEST_SUITE
470(
471 "system_timer",
472 BOOST_ASIO_TEST_CASE(system_timer_test)
473 BOOST_ASIO_TEST_CASE(system_timer_cancel_test)
474 BOOST_ASIO_TEST_CASE(system_timer_custom_allocation_test)
475 BOOST_ASIO_TEST_CASE(system_timer_thread_test)
b32b8144 476 BOOST_ASIO_TEST_CASE(system_timer_move_test)
7c673cae
FG
477)
478#else // defined(BOOST_ASIO_HAS_STD_CHRONO)
479BOOST_ASIO_TEST_SUITE
480(
481 "system_timer",
482 BOOST_ASIO_TEST_CASE(null_test)
483)
484#endif // defined(BOOST_ASIO_HAS_STD_CHRONO)