]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/test/deadline_timer.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / asio / test / deadline_timer.cpp
CommitLineData
7c673cae
FG
1//
2// deadline_timer.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/deadline_timer.hpp>
18
19#include "unit_test.hpp"
20
21#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
22
f67539c2 23#include <boost/bind/bind.hpp>
7c673cae 24#include "archetypes/async_result.hpp"
b32b8144
FG
25#include <boost/asio/executor_work_guard.hpp>
26#include <boost/asio/io_context.hpp>
7c673cae
FG
27#include <boost/asio/placeholders.hpp>
28#include <boost/asio/detail/thread.hpp>
29
30using namespace boost::posix_time;
31
32void increment(int* count)
33{
34 ++(*count);
35}
36
37void decrement_to_zero(boost::asio::deadline_timer* t, int* count)
38{
39 if (*count > 0)
40 {
41 --(*count);
42
43 int before_value = *count;
44
45 t->expires_at(t->expires_at() + seconds(1));
46 t->async_wait(boost::bind(decrement_to_zero, t, count));
47
48 // Completion cannot nest, so count value should remain unchanged.
49 BOOST_ASIO_CHECK(*count == before_value);
50 }
51}
52
53void increment_if_not_cancelled(int* count,
54 const boost::system::error_code& ec)
55{
56 if (!ec)
57 ++(*count);
58}
59
60void cancel_timer(boost::asio::deadline_timer* t)
61{
62 std::size_t num_cancelled = t->cancel();
63 BOOST_ASIO_CHECK(num_cancelled == 1);
64}
65
66void cancel_one_timer(boost::asio::deadline_timer* t)
67{
68 std::size_t num_cancelled = t->cancel_one();
69 BOOST_ASIO_CHECK(num_cancelled == 1);
70}
71
72ptime now()
73{
74#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
75 return microsec_clock::universal_time();
76#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
77 return second_clock::universal_time();
78#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
79}
80
81void deadline_timer_test()
82{
b32b8144 83 boost::asio::io_context ioc;
7c673cae
FG
84 int count = 0;
85
86 ptime start = now();
87
b32b8144 88 boost::asio::deadline_timer t1(ioc, seconds(1));
7c673cae
FG
89 t1.wait();
90
91 // The timer must block until after its expiry time.
92 ptime end = now();
93 ptime expected_end = start + seconds(1);
94 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
95
96 start = now();
97
b32b8144 98 boost::asio::deadline_timer t2(ioc, seconds(1) + microseconds(500000));
7c673cae
FG
99 t2.wait();
100
101 // The timer must block until after its expiry time.
102 end = now();
103 expected_end = start + seconds(1) + microseconds(500000);
104 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
105
106 t2.expires_at(t2.expires_at() + seconds(1));
107 t2.wait();
108
109 // The timer must block until after its expiry time.
110 end = now();
111 expected_end += seconds(1);
112 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
113
114 start = now();
115
116 t2.expires_from_now(seconds(1) + microseconds(200000));
117 t2.wait();
118
119 // The timer must block until after its expiry time.
120 end = now();
121 expected_end = start + seconds(1) + microseconds(200000);
122 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
123
124 start = now();
125
b32b8144 126 boost::asio::deadline_timer t3(ioc, seconds(5));
7c673cae
FG
127 t3.async_wait(boost::bind(increment, &count));
128
129 // No completions can be delivered until run() is called.
130 BOOST_ASIO_CHECK(count == 0);
131
b32b8144 132 ioc.run();
7c673cae
FG
133
134 // The run() call will not return until all operations have finished, and
135 // this should not be until after the timer's expiry time.
136 BOOST_ASIO_CHECK(count == 1);
137 end = now();
138 expected_end = start + seconds(1);
139 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
140
141 count = 3;
142 start = now();
143
b32b8144 144 boost::asio::deadline_timer t4(ioc, seconds(1));
7c673cae
FG
145 t4.async_wait(boost::bind(decrement_to_zero, &t4, &count));
146
147 // No completions can be delivered until run() is called.
148 BOOST_ASIO_CHECK(count == 3);
149
b32b8144
FG
150 ioc.restart();
151 ioc.run();
7c673cae
FG
152
153 // The run() call will not return until all operations have finished, and
154 // this should not be until after the timer's final expiry time.
155 BOOST_ASIO_CHECK(count == 0);
156 end = now();
157 expected_end = start + seconds(3);
158 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
159
160 count = 0;
161 start = now();
162
b32b8144 163 boost::asio::deadline_timer t5(ioc, seconds(10));
7c673cae
FG
164 t5.async_wait(boost::bind(increment_if_not_cancelled, &count,
165 boost::asio::placeholders::error));
b32b8144 166 boost::asio::deadline_timer t6(ioc, seconds(1));
7c673cae
FG
167 t6.async_wait(boost::bind(cancel_timer, &t5));
168
169 // No completions can be delivered until run() is called.
170 BOOST_ASIO_CHECK(count == 0);
171
b32b8144
FG
172 ioc.restart();
173 ioc.run();
7c673cae
FG
174
175 // The timer should have been cancelled, so count should not have changed.
176 // The total run time should not have been much more than 1 second (and
177 // certainly far less than 10 seconds).
178 BOOST_ASIO_CHECK(count == 0);
179 end = now();
180 expected_end = start + seconds(2);
181 BOOST_ASIO_CHECK(end < expected_end);
182
183 // Wait on the timer again without cancelling it. This time the asynchronous
184 // wait should run to completion and increment the counter.
185 t5.async_wait(boost::bind(increment_if_not_cancelled, &count,
186 boost::asio::placeholders::error));
187
b32b8144
FG
188 ioc.restart();
189 ioc.run();
7c673cae
FG
190
191 // The timer should not have been cancelled, so count should have changed.
192 // The total time since the timer was created should be more than 10 seconds.
193 BOOST_ASIO_CHECK(count == 1);
194 end = now();
195 expected_end = start + seconds(10);
196 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
197
198 count = 0;
199 start = now();
200
201 // Start two waits on a timer, one of which will be cancelled. The one
202 // which is not cancelled should still run to completion and increment the
203 // counter.
b32b8144 204 boost::asio::deadline_timer t7(ioc, seconds(3));
7c673cae
FG
205 t7.async_wait(boost::bind(increment_if_not_cancelled, &count,
206 boost::asio::placeholders::error));
207 t7.async_wait(boost::bind(increment_if_not_cancelled, &count,
208 boost::asio::placeholders::error));
b32b8144 209 boost::asio::deadline_timer t8(ioc, seconds(1));
7c673cae
FG
210 t8.async_wait(boost::bind(cancel_one_timer, &t7));
211
b32b8144
FG
212 ioc.restart();
213 ioc.run();
7c673cae
FG
214
215 // One of the waits should not have been cancelled, so count should have
216 // changed. The total time since the timer was created should be more than 3
217 // seconds.
218 BOOST_ASIO_CHECK(count == 1);
219 end = now();
220 expected_end = start + seconds(3);
221 BOOST_ASIO_CHECK(expected_end < end || expected_end == end);
222}
223
224void timer_handler(const boost::system::error_code&)
225{
226}
227
228void deadline_timer_cancel_test()
229{
b32b8144 230 static boost::asio::io_context io_context;
7c673cae
FG
231 struct timer
232 {
233 boost::asio::deadline_timer t;
b32b8144 234 timer() : t(io_context) { t.expires_at(boost::posix_time::pos_infin); }
7c673cae
FG
235 } timers[50];
236
237 timers[2].t.async_wait(&timer_handler);
238 timers[41].t.async_wait(&timer_handler);
239 for (int i = 10; i < 20; ++i)
240 timers[i].t.async_wait(&timer_handler);
241
242 BOOST_ASIO_CHECK(timers[2].t.cancel() == 1);
243 BOOST_ASIO_CHECK(timers[41].t.cancel() == 1);
244 for (int i = 10; i < 20; ++i)
245 BOOST_ASIO_CHECK(timers[i].t.cancel() == 1);
246}
247
248struct custom_allocation_timer_handler
249{
250 custom_allocation_timer_handler(int* count) : count_(count) {}
251 void operator()(const boost::system::error_code&) {}
252 int* count_;
7c673cae 253
20effc67
TL
254 template <typename T>
255 struct allocator
256 {
257 typedef size_t size_type;
258 typedef ptrdiff_t difference_type;
259 typedef T* pointer;
260 typedef const T* const_pointer;
261 typedef T& reference;
262 typedef const T& const_reference;
263 typedef T value_type;
264
265 template <typename U>
266 struct rebind
267 {
268 typedef allocator<U> other;
269 };
270
271 explicit allocator(int* count) BOOST_ASIO_NOEXCEPT
272 : count_(count)
273 {
274 }
275
276 allocator(const allocator& other) BOOST_ASIO_NOEXCEPT
277 : count_(other.count_)
278 {
279 }
280
281 template <typename U>
282 allocator(const allocator<U>& other) BOOST_ASIO_NOEXCEPT
283 : count_(other.count_)
284 {
285 }
286
287 pointer allocate(size_type n, const void* = 0)
288 {
289 ++(*count_);
290 return static_cast<T*>(::operator new(sizeof(T) * n));
291 }
292
293 void deallocate(pointer p, size_type)
294 {
295 --(*count_);
296 ::operator delete(p);
297 }
298
299 size_type max_size() const
300 {
301 return ~size_type(0);
302 }
303
304 void construct(pointer p, const T& v)
305 {
306 new (p) T(v);
307 }
308
309 void destroy(pointer p)
310 {
311 p->~T();
312 }
313
314 int* count_;
315 };
316
317 typedef allocator<int> allocator_type;
318
319 allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
320 {
321 return allocator_type(count_);
322 }
323};
7c673cae
FG
324
325void deadline_timer_custom_allocation_test()
326{
b32b8144 327 static boost::asio::io_context io_context;
7c673cae
FG
328 struct timer
329 {
330 boost::asio::deadline_timer t;
b32b8144 331 timer() : t(io_context) {}
7c673cae
FG
332 } timers[100];
333
334 int allocation_count = 0;
335
336 for (int i = 0; i < 50; ++i)
337 {
338 timers[i].t.expires_at(boost::posix_time::pos_infin);
339 timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
340 }
341
342 for (int i = 50; i < 100; ++i)
343 {
344 timers[i].t.expires_at(boost::posix_time::neg_infin);
345 timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
346 }
347
348 for (int i = 0; i < 50; ++i)
349 timers[i].t.cancel();
350
b32b8144 351 io_context.run();
7c673cae
FG
352
353 BOOST_ASIO_CHECK(allocation_count == 0);
354}
355
b32b8144 356void io_context_run(boost::asio::io_context* ioc)
7c673cae 357{
b32b8144 358 ioc->run();
7c673cae
FG
359}
360
361void deadline_timer_thread_test()
362{
b32b8144
FG
363 boost::asio::io_context ioc;
364 boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work
365 = boost::asio::make_work_guard(ioc);
366 boost::asio::deadline_timer t1(ioc);
367 boost::asio::deadline_timer t2(ioc);
7c673cae
FG
368 int count = 0;
369
b32b8144 370 boost::asio::detail::thread th(boost::bind(io_context_run, &ioc));
7c673cae
FG
371
372 t2.expires_from_now(boost::posix_time::seconds(2));
373 t2.wait();
374
375 t1.expires_from_now(boost::posix_time::seconds(2));
376 t1.async_wait(boost::bind(increment, &count));
377
378 t2.expires_from_now(boost::posix_time::seconds(4));
379 t2.wait();
380
b32b8144 381 ioc.stop();
7c673cae
FG
382 th.join();
383
384 BOOST_ASIO_CHECK(count == 1);
385}
386
387void deadline_timer_async_result_test()
388{
b32b8144
FG
389 boost::asio::io_context ioc;
390 boost::asio::deadline_timer t1(ioc);
7c673cae
FG
391
392 t1.expires_from_now(boost::posix_time::seconds(1));
393 int i = t1.async_wait(archetypes::lazy_handler());
394 BOOST_ASIO_CHECK(i == 42);
395
b32b8144
FG
396 ioc.run();
397}
398
399#if defined(BOOST_ASIO_HAS_MOVE)
400boost::asio::deadline_timer make_timer(boost::asio::io_context& ioc, int* count)
401{
402 boost::asio::deadline_timer t(ioc);
403 t.expires_from_now(boost::posix_time::seconds(1));
404 t.async_wait(boost::bind(increment, count));
405 return t;
406}
407#endif // defined(BOOST_ASIO_HAS_MOVE)
408
409void deadline_timer_move_test()
410{
411#if defined(BOOST_ASIO_HAS_MOVE)
412 boost::asio::io_context io_context1;
413 boost::asio::io_context io_context2;
414 int count = 0;
415
416 boost::asio::deadline_timer t1 = make_timer(io_context1, &count);
417 boost::asio::deadline_timer t2 = make_timer(io_context2, &count);
418 boost::asio::deadline_timer t3 = std::move(t1);
419
420 t2 = std::move(t1);
421
422 io_context2.run();
423
424 BOOST_ASIO_CHECK(count == 1);
425
426 io_context1.run();
427
428 BOOST_ASIO_CHECK(count == 2);
429#endif // defined(BOOST_ASIO_HAS_MOVE)
7c673cae
FG
430}
431
432BOOST_ASIO_TEST_SUITE
433(
434 "deadline_timer",
435 BOOST_ASIO_TEST_CASE(deadline_timer_test)
436 BOOST_ASIO_TEST_CASE(deadline_timer_cancel_test)
437 BOOST_ASIO_TEST_CASE(deadline_timer_custom_allocation_test)
438 BOOST_ASIO_TEST_CASE(deadline_timer_thread_test)
439 BOOST_ASIO_TEST_CASE(deadline_timer_async_result_test)
b32b8144 440 BOOST_ASIO_TEST_CASE(deadline_timer_move_test)
7c673cae
FG
441)
442#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
443BOOST_ASIO_TEST_SUITE
444(
445 "deadline_timer",
446 BOOST_ASIO_TEST_CASE(null_test)
447)
448#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)