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/deadline_timer.hpp>
19 #include "unit_test.hpp"
21 #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
23 #include <boost/bind/bind.hpp>
24 #include "archetypes/async_result.hpp"
25 #include <boost/asio/executor_work_guard.hpp>
26 #include <boost/asio/io_context.hpp>
27 #include <boost/asio/placeholders.hpp>
28 #include <boost/asio/detail/thread.hpp>
30 using namespace boost::posix_time
;
32 void increment(int* count
)
37 void decrement_to_zero(boost::asio::deadline_timer
* t
, int* count
)
43 int before_value
= *count
;
45 t
->expires_at(t
->expires_at() + seconds(1));
46 t
->async_wait(boost::bind(decrement_to_zero
, t
, count
));
48 // Completion cannot nest, so count value should remain unchanged.
49 BOOST_ASIO_CHECK(*count
== before_value
);
53 void increment_if_not_cancelled(int* count
,
54 const boost::system::error_code
& ec
)
60 void cancel_timer(boost::asio::deadline_timer
* t
)
62 std::size_t num_cancelled
= t
->cancel();
63 BOOST_ASIO_CHECK(num_cancelled
== 1);
66 void cancel_one_timer(boost::asio::deadline_timer
* t
)
68 std::size_t num_cancelled
= t
->cancel_one();
69 BOOST_ASIO_CHECK(num_cancelled
== 1);
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)
81 void deadline_timer_test()
83 boost::asio::io_context ioc
;
88 boost::asio::deadline_timer
t1(ioc
, seconds(1));
91 // The timer must block until after its expiry time.
93 ptime expected_end
= start
+ seconds(1);
94 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
98 boost::asio::deadline_timer
t2(ioc
, seconds(1) + microseconds(500000));
101 // The timer must block until after its expiry time.
103 expected_end
= start
+ seconds(1) + microseconds(500000);
104 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
106 t2
.expires_at(t2
.expires_at() + seconds(1));
109 // The timer must block until after its expiry time.
111 expected_end
+= seconds(1);
112 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
116 t2
.expires_from_now(seconds(1) + microseconds(200000));
119 // The timer must block until after its expiry time.
121 expected_end
= start
+ seconds(1) + microseconds(200000);
122 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
126 boost::asio::deadline_timer
t3(ioc
, seconds(5));
127 t3
.async_wait(boost::bind(increment
, &count
));
129 // No completions can be delivered until run() is called.
130 BOOST_ASIO_CHECK(count
== 0);
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);
138 expected_end
= start
+ seconds(1);
139 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
144 boost::asio::deadline_timer
t4(ioc
, seconds(1));
145 t4
.async_wait(boost::bind(decrement_to_zero
, &t4
, &count
));
147 // No completions can be delivered until run() is called.
148 BOOST_ASIO_CHECK(count
== 3);
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);
157 expected_end
= start
+ seconds(3);
158 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
163 boost::asio::deadline_timer
t5(ioc
, seconds(10));
164 t5
.async_wait(boost::bind(increment_if_not_cancelled
, &count
,
165 boost::asio::placeholders::error
));
166 boost::asio::deadline_timer
t6(ioc
, seconds(1));
167 t6
.async_wait(boost::bind(cancel_timer
, &t5
));
169 // No completions can be delivered until run() is called.
170 BOOST_ASIO_CHECK(count
== 0);
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);
180 expected_end
= start
+ seconds(2);
181 BOOST_ASIO_CHECK(end
< expected_end
);
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
));
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);
195 expected_end
= start
+ seconds(10);
196 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
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
204 boost::asio::deadline_timer
t7(ioc
, seconds(3));
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
));
209 boost::asio::deadline_timer
t8(ioc
, seconds(1));
210 t8
.async_wait(boost::bind(cancel_one_timer
, &t7
));
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
218 BOOST_ASIO_CHECK(count
== 1);
220 expected_end
= start
+ seconds(3);
221 BOOST_ASIO_CHECK(expected_end
< end
|| expected_end
== end
);
224 void timer_handler(const boost::system::error_code
&)
228 void deadline_timer_cancel_test()
230 static boost::asio::io_context io_context
;
233 boost::asio::deadline_timer t
;
234 timer() : t(io_context
) { t
.expires_at(boost::posix_time::pos_infin
); }
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
);
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);
248 struct custom_allocation_timer_handler
250 custom_allocation_timer_handler(int* count
) : count_(count
) {}
251 void operator()(const boost::system::error_code
&) {}
254 template <typename T
>
257 typedef size_t size_type
;
258 typedef ptrdiff_t difference_type
;
260 typedef const T
* const_pointer
;
261 typedef T
& reference
;
262 typedef const T
& const_reference
;
263 typedef T value_type
;
265 template <typename U
>
268 typedef allocator
<U
> other
;
271 explicit allocator(int* count
) BOOST_ASIO_NOEXCEPT
276 allocator(const allocator
& other
) BOOST_ASIO_NOEXCEPT
277 : count_(other
.count_
)
281 template <typename U
>
282 allocator(const allocator
<U
>& other
) BOOST_ASIO_NOEXCEPT
283 : count_(other
.count_
)
287 pointer
allocate(size_type n
, const void* = 0)
290 return static_cast<T
*>(::operator new(sizeof(T
) * n
));
293 void deallocate(pointer p
, size_type
)
296 ::operator delete(p
);
299 size_type
max_size() const
301 return ~size_type(0);
304 void construct(pointer p
, const T
& v
)
309 void destroy(pointer p
)
317 typedef allocator
<int> allocator_type
;
319 allocator_type
get_allocator() const BOOST_ASIO_NOEXCEPT
321 return allocator_type(count_
);
325 void deadline_timer_custom_allocation_test()
327 static boost::asio::io_context io_context
;
330 boost::asio::deadline_timer t
;
331 timer() : t(io_context
) {}
334 int allocation_count
= 0;
336 for (int i
= 0; i
< 50; ++i
)
338 timers
[i
].t
.expires_at(boost::posix_time::pos_infin
);
339 timers
[i
].t
.async_wait(custom_allocation_timer_handler(&allocation_count
));
342 for (int i
= 50; i
< 100; ++i
)
344 timers
[i
].t
.expires_at(boost::posix_time::neg_infin
);
345 timers
[i
].t
.async_wait(custom_allocation_timer_handler(&allocation_count
));
348 for (int i
= 0; i
< 50; ++i
)
349 timers
[i
].t
.cancel();
353 BOOST_ASIO_CHECK(allocation_count
== 0);
356 void io_context_run(boost::asio::io_context
* ioc
)
361 void deadline_timer_thread_test()
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
);
370 boost::asio::detail::thread
th(boost::bind(io_context_run
, &ioc
));
372 t2
.expires_from_now(boost::posix_time::seconds(2));
375 t1
.expires_from_now(boost::posix_time::seconds(2));
376 t1
.async_wait(boost::bind(increment
, &count
));
378 t2
.expires_from_now(boost::posix_time::seconds(4));
384 BOOST_ASIO_CHECK(count
== 1);
387 void deadline_timer_async_result_test()
389 boost::asio::io_context ioc
;
390 boost::asio::deadline_timer
t1(ioc
);
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);
399 #if defined(BOOST_ASIO_HAS_MOVE)
400 boost::asio::deadline_timer
make_timer(boost::asio::io_context
& ioc
, int* count
)
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
));
407 #endif // defined(BOOST_ASIO_HAS_MOVE)
409 void deadline_timer_move_test()
411 #if defined(BOOST_ASIO_HAS_MOVE)
412 boost::asio::io_context io_context1
;
413 boost::asio::io_context io_context2
;
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
);
424 BOOST_ASIO_CHECK(count
== 1);
428 BOOST_ASIO_CHECK(count
== 2);
429 #endif // defined(BOOST_ASIO_HAS_MOVE)
432 BOOST_ASIO_TEST_SUITE
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
)
440 BOOST_ASIO_TEST_CASE(deadline_timer_move_test
)
442 #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
443 BOOST_ASIO_TEST_SUITE
446 BOOST_ASIO_TEST_CASE(null_test
)
448 #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)