summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/src/tests/unit/deadline_timer.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/src/tests/unit/deadline_timer.cpp')
-rw-r--r--3rdparty/asio/src/tests/unit/deadline_timer.cpp448
1 files changed, 448 insertions, 0 deletions
diff --git a/3rdparty/asio/src/tests/unit/deadline_timer.cpp b/3rdparty/asio/src/tests/unit/deadline_timer.cpp
new file mode 100644
index 00000000000..15d00b0d83b
--- /dev/null
+++ b/3rdparty/asio/src/tests/unit/deadline_timer.cpp
@@ -0,0 +1,448 @@
+//
+// deadline_timer.cpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Disable autolinking for unit tests.
+#if !defined(BOOST_ALL_NO_LIB)
+#define BOOST_ALL_NO_LIB 1
+#endif // !defined(BOOST_ALL_NO_LIB)
+
+// Test that header file is self-contained.
+#include "asio/deadline_timer.hpp"
+
+#include "unit_test.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#include <boost/bind/bind.hpp>
+#include "archetypes/async_result.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/io_context.hpp"
+#include "asio/placeholders.hpp"
+#include "asio/thread.hpp"
+
+using namespace boost::posix_time;
+
+void increment(int* count)
+{
+ ++(*count);
+}
+
+void decrement_to_zero(asio::deadline_timer* t, int* count)
+{
+ if (*count > 0)
+ {
+ --(*count);
+
+ int before_value = *count;
+
+ t->expires_at(t->expires_at() + seconds(1));
+ t->async_wait(boost::bind(decrement_to_zero, t, count));
+
+ // Completion cannot nest, so count value should remain unchanged.
+ ASIO_CHECK(*count == before_value);
+ }
+}
+
+void increment_if_not_cancelled(int* count,
+ const asio::error_code& ec)
+{
+ if (!ec)
+ ++(*count);
+}
+
+void cancel_timer(asio::deadline_timer* t)
+{
+ std::size_t num_cancelled = t->cancel();
+ ASIO_CHECK(num_cancelled == 1);
+}
+
+void cancel_one_timer(asio::deadline_timer* t)
+{
+ std::size_t num_cancelled = t->cancel_one();
+ ASIO_CHECK(num_cancelled == 1);
+}
+
+ptime now()
+{
+#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
+ return microsec_clock::universal_time();
+#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
+ return second_clock::universal_time();
+#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
+}
+
+void deadline_timer_test()
+{
+ asio::io_context ioc;
+ int count = 0;
+
+ ptime start = now();
+
+ asio::deadline_timer t1(ioc, seconds(1));
+ t1.wait();
+
+ // The timer must block until after its expiry time.
+ ptime end = now();
+ ptime expected_end = start + seconds(1);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ start = now();
+
+ asio::deadline_timer t2(ioc, seconds(1) + microseconds(500000));
+ t2.wait();
+
+ // The timer must block until after its expiry time.
+ end = now();
+ expected_end = start + seconds(1) + microseconds(500000);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ t2.expires_at(t2.expires_at() + seconds(1));
+ t2.wait();
+
+ // The timer must block until after its expiry time.
+ end = now();
+ expected_end += seconds(1);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ start = now();
+
+ t2.expires_from_now(seconds(1) + microseconds(200000));
+ t2.wait();
+
+ // The timer must block until after its expiry time.
+ end = now();
+ expected_end = start + seconds(1) + microseconds(200000);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ start = now();
+
+ asio::deadline_timer t3(ioc, seconds(5));
+ t3.async_wait(boost::bind(increment, &count));
+
+ // No completions can be delivered until run() is called.
+ ASIO_CHECK(count == 0);
+
+ ioc.run();
+
+ // The run() call will not return until all operations have finished, and
+ // this should not be until after the timer's expiry time.
+ ASIO_CHECK(count == 1);
+ end = now();
+ expected_end = start + seconds(1);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ count = 3;
+ start = now();
+
+ asio::deadline_timer t4(ioc, seconds(1));
+ t4.async_wait(boost::bind(decrement_to_zero, &t4, &count));
+
+ // No completions can be delivered until run() is called.
+ ASIO_CHECK(count == 3);
+
+ ioc.restart();
+ ioc.run();
+
+ // The run() call will not return until all operations have finished, and
+ // this should not be until after the timer's final expiry time.
+ ASIO_CHECK(count == 0);
+ end = now();
+ expected_end = start + seconds(3);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ count = 0;
+ start = now();
+
+ asio::deadline_timer t5(ioc, seconds(10));
+ t5.async_wait(boost::bind(increment_if_not_cancelled, &count,
+ asio::placeholders::error));
+ asio::deadline_timer t6(ioc, seconds(1));
+ t6.async_wait(boost::bind(cancel_timer, &t5));
+
+ // No completions can be delivered until run() is called.
+ ASIO_CHECK(count == 0);
+
+ ioc.restart();
+ ioc.run();
+
+ // The timer should have been cancelled, so count should not have changed.
+ // The total run time should not have been much more than 1 second (and
+ // certainly far less than 10 seconds).
+ ASIO_CHECK(count == 0);
+ end = now();
+ expected_end = start + seconds(2);
+ ASIO_CHECK(end < expected_end);
+
+ // Wait on the timer again without cancelling it. This time the asynchronous
+ // wait should run to completion and increment the counter.
+ t5.async_wait(boost::bind(increment_if_not_cancelled, &count,
+ asio::placeholders::error));
+
+ ioc.restart();
+ ioc.run();
+
+ // The timer should not have been cancelled, so count should have changed.
+ // The total time since the timer was created should be more than 10 seconds.
+ ASIO_CHECK(count == 1);
+ end = now();
+ expected_end = start + seconds(10);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+
+ count = 0;
+ start = now();
+
+ // Start two waits on a timer, one of which will be cancelled. The one
+ // which is not cancelled should still run to completion and increment the
+ // counter.
+ asio::deadline_timer t7(ioc, seconds(3));
+ t7.async_wait(boost::bind(increment_if_not_cancelled, &count,
+ asio::placeholders::error));
+ t7.async_wait(boost::bind(increment_if_not_cancelled, &count,
+ asio::placeholders::error));
+ asio::deadline_timer t8(ioc, seconds(1));
+ t8.async_wait(boost::bind(cancel_one_timer, &t7));
+
+ ioc.restart();
+ ioc.run();
+
+ // One of the waits should not have been cancelled, so count should have
+ // changed. The total time since the timer was created should be more than 3
+ // seconds.
+ ASIO_CHECK(count == 1);
+ end = now();
+ expected_end = start + seconds(3);
+ ASIO_CHECK(expected_end < end || expected_end == end);
+}
+
+void timer_handler(const asio::error_code&)
+{
+}
+
+void deadline_timer_cancel_test()
+{
+ static asio::io_context io_context;
+ struct timer
+ {
+ asio::deadline_timer t;
+ timer() : t(io_context) { t.expires_at(boost::posix_time::pos_infin); }
+ } timers[50];
+
+ timers[2].t.async_wait(&timer_handler);
+ timers[41].t.async_wait(&timer_handler);
+ for (int i = 10; i < 20; ++i)
+ timers[i].t.async_wait(&timer_handler);
+
+ ASIO_CHECK(timers[2].t.cancel() == 1);
+ ASIO_CHECK(timers[41].t.cancel() == 1);
+ for (int i = 10; i < 20; ++i)
+ ASIO_CHECK(timers[i].t.cancel() == 1);
+}
+
+struct custom_allocation_timer_handler
+{
+ custom_allocation_timer_handler(int* count) : count_(count) {}
+ void operator()(const asio::error_code&) {}
+ int* count_;
+
+ template <typename T>
+ struct allocator
+ {
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template <typename U>
+ struct rebind
+ {
+ typedef allocator<U> other;
+ };
+
+ explicit allocator(int* count) ASIO_NOEXCEPT
+ : count_(count)
+ {
+ }
+
+ allocator(const allocator& other) ASIO_NOEXCEPT
+ : count_(other.count_)
+ {
+ }
+
+ template <typename U>
+ allocator(const allocator<U>& other) ASIO_NOEXCEPT
+ : count_(other.count_)
+ {
+ }
+
+ pointer allocate(size_type n, const void* = 0)
+ {
+ ++(*count_);
+ return static_cast<T*>(::operator new(sizeof(T) * n));
+ }
+
+ void deallocate(pointer p, size_type)
+ {
+ --(*count_);
+ ::operator delete(p);
+ }
+
+ size_type max_size() const
+ {
+ return ~size_type(0);
+ }
+
+ void construct(pointer p, const T& v)
+ {
+ new (p) T(v);
+ }
+
+ void destroy(pointer p)
+ {
+ p->~T();
+ }
+
+ int* count_;
+ };
+
+ typedef allocator<int> allocator_type;
+
+ allocator_type get_allocator() const ASIO_NOEXCEPT
+ {
+ return allocator_type(count_);
+ }
+};
+
+void deadline_timer_custom_allocation_test()
+{
+ static asio::io_context io_context;
+ struct timer
+ {
+ asio::deadline_timer t;
+ timer() : t(io_context) {}
+ } timers[100];
+
+ int allocation_count = 0;
+
+ for (int i = 0; i < 50; ++i)
+ {
+ timers[i].t.expires_at(boost::posix_time::pos_infin);
+ timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
+ }
+
+ for (int i = 50; i < 100; ++i)
+ {
+ timers[i].t.expires_at(boost::posix_time::neg_infin);
+ timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count));
+ }
+
+ for (int i = 0; i < 50; ++i)
+ timers[i].t.cancel();
+
+ io_context.run();
+
+ ASIO_CHECK(allocation_count == 0);
+}
+
+void io_context_run(asio::io_context* ioc)
+{
+ ioc->run();
+}
+
+void deadline_timer_thread_test()
+{
+ asio::io_context ioc;
+ asio::executor_work_guard<asio::io_context::executor_type> work
+ = asio::make_work_guard(ioc);
+ asio::deadline_timer t1(ioc);
+ asio::deadline_timer t2(ioc);
+ int count = 0;
+
+ asio::thread th(boost::bind(io_context_run, &ioc));
+
+ t2.expires_from_now(boost::posix_time::seconds(2));
+ t2.wait();
+
+ t1.expires_from_now(boost::posix_time::seconds(2));
+ t1.async_wait(boost::bind(increment, &count));
+
+ t2.expires_from_now(boost::posix_time::seconds(4));
+ t2.wait();
+
+ ioc.stop();
+ th.join();
+
+ ASIO_CHECK(count == 1);
+}
+
+void deadline_timer_async_result_test()
+{
+ asio::io_context ioc;
+ asio::deadline_timer t1(ioc);
+
+ t1.expires_from_now(boost::posix_time::seconds(1));
+ int i = t1.async_wait(archetypes::lazy_handler());
+ ASIO_CHECK(i == 42);
+
+ ioc.run();
+}
+
+#if defined(ASIO_HAS_MOVE)
+asio::deadline_timer make_timer(asio::io_context& ioc, int* count)
+{
+ asio::deadline_timer t(ioc);
+ t.expires_from_now(boost::posix_time::seconds(1));
+ t.async_wait(boost::bind(increment, count));
+ return t;
+}
+#endif // defined(ASIO_HAS_MOVE)
+
+void deadline_timer_move_test()
+{
+#if defined(ASIO_HAS_MOVE)
+ asio::io_context io_context1;
+ asio::io_context io_context2;
+ int count = 0;
+
+ asio::deadline_timer t1 = make_timer(io_context1, &count);
+ asio::deadline_timer t2 = make_timer(io_context2, &count);
+ asio::deadline_timer t3 = std::move(t1);
+
+ t2 = std::move(t1);
+
+ io_context2.run();
+
+ ASIO_CHECK(count == 1);
+
+ io_context1.run();
+
+ ASIO_CHECK(count == 2);
+#endif // defined(ASIO_HAS_MOVE)
+}
+
+ASIO_TEST_SUITE
+(
+ "deadline_timer",
+ ASIO_TEST_CASE(deadline_timer_test)
+ ASIO_TEST_CASE(deadline_timer_cancel_test)
+ ASIO_TEST_CASE(deadline_timer_custom_allocation_test)
+ ASIO_TEST_CASE(deadline_timer_thread_test)
+ ASIO_TEST_CASE(deadline_timer_async_result_test)
+ ASIO_TEST_CASE(deadline_timer_move_test)
+)
+#else // defined(ASIO_HAS_BOOST_DATE_TIME)
+ASIO_TEST_SUITE
+(
+ "deadline_timer",
+ ASIO_TEST_CASE(null_test)
+)
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)