mirror of
https://github.com/boostorg/asio.git
synced 2026-01-19 04:02:09 +00:00
Make basic_io_object constructor protected. Make a 0-length send or receive on a stream socket into a no-op. Add cancel() function for cancelling asynchronous socket operations. The Win32 implementation only works if all operations for the socket have been issued from the same thread, otherwise it fails with asio::error::not_supported. Add workaround for an apparent Windows bug where using getpeername on a socket accepted using AcceptEx will sometimes return an endpoint that is all zeroes. Make a strand last as long as it has any handlers to dispatch. Make strand a nested class of io_service. Add io_service() function to io_service::work to return a reference to the io_service object on which the work is being performed. Renamed io_service::service::owner() to io_service::service::io_service(). Unset linger object when socket objects are destroyed. Rename asio_handler_dispatch to asio_handler_invoke. Rename basic_socketbuf to basic_socket_streambuf. Update ip::address_v4 and ip::address_v6 classes to match TR2 proposal. Add run_one(), poll() and poll_one() functions to the io_service. Remove need to #define FD_SETSIZE on Win32. Add detection of incorrect inclusion of WinSock.h. Fix some SSL bugs. Add ability to customise the SSL password callback function. Set the reuse_address option by default on acceptors. The macros FIONREAD and FIONBIO are not integer constants on all platforms, and so cannot be used as template arguments. Make the corresponding I/O control commands into proper classes, not templates. Fixes to better support *BSD platforms. Add support for buffer debugging, if the standard library supports iterator debugging (as MSVC8's standard lib does). Ensure the IOCP queue is drained correctly at shutdown. Move basic_resolver and resolver service into the ip namespace. Fix some issues found by the inspect tool. [SVN r35833]
187 lines
4.9 KiB
C++
187 lines
4.9 KiB
C++
//
|
|
// deadline_timer_test.cpp
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2006 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 <boost/asio/deadline_timer.hpp>
|
|
|
|
#include <boost/bind.hpp>
|
|
#include <boost/asio.hpp>
|
|
#include "unit_test.hpp"
|
|
|
|
using namespace boost::posix_time;
|
|
|
|
void increment(int* count)
|
|
{
|
|
++(*count);
|
|
}
|
|
|
|
void decrement_to_zero(boost::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.
|
|
BOOST_CHECK(*count == before_value);
|
|
}
|
|
}
|
|
|
|
void increment_if_not_cancelled(int* count, const boost::asio::error& e)
|
|
{
|
|
if (!e)
|
|
++(*count);
|
|
}
|
|
|
|
void cancel_timer(boost::asio::deadline_timer* t)
|
|
{
|
|
std::size_t num_cancelled = t->cancel();
|
|
BOOST_CHECK(num_cancelled == 1);
|
|
}
|
|
|
|
ptime now()
|
|
{
|
|
return microsec_clock::universal_time();
|
|
}
|
|
|
|
void deadline_timer_test()
|
|
{
|
|
boost::asio::io_service ios;
|
|
int count = 0;
|
|
|
|
ptime start = now();
|
|
|
|
boost::asio::deadline_timer t1(ios, seconds(1));
|
|
t1.wait();
|
|
|
|
// The timer must block until after its expiry time.
|
|
ptime end = now();
|
|
ptime expected_end = start + seconds(1);
|
|
BOOST_CHECK(expected_end < end || expected_end == end);
|
|
|
|
start = now();
|
|
|
|
boost::asio::deadline_timer t2(ios, seconds(1) + microseconds(500000));
|
|
t2.wait();
|
|
|
|
// The timer must block until after its expiry time.
|
|
end = now();
|
|
expected_end = start + seconds(1) + microseconds(500000);
|
|
BOOST_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);
|
|
BOOST_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);
|
|
BOOST_CHECK(expected_end < end || expected_end == end);
|
|
|
|
start = now();
|
|
|
|
boost::asio::deadline_timer t3(ios, seconds(5));
|
|
t3.async_wait(boost::bind(increment, &count));
|
|
|
|
// No completions can be delivered until run() is called.
|
|
BOOST_CHECK(count == 0);
|
|
|
|
ios.run();
|
|
|
|
// The run() call will not return until all operations have finished, and
|
|
// this should not be until after the timer's expiry time.
|
|
BOOST_CHECK(count == 1);
|
|
end = now();
|
|
expected_end = start + seconds(1);
|
|
BOOST_CHECK(expected_end < end || expected_end == end);
|
|
|
|
count = 3;
|
|
start = now();
|
|
|
|
boost::asio::deadline_timer t4(ios, seconds(1));
|
|
t4.async_wait(boost::bind(decrement_to_zero, &t4, &count));
|
|
|
|
// No completions can be delivered until run() is called.
|
|
BOOST_CHECK(count == 3);
|
|
|
|
ios.reset();
|
|
ios.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.
|
|
BOOST_CHECK(count == 0);
|
|
end = now();
|
|
expected_end = start + seconds(3);
|
|
BOOST_CHECK(expected_end < end || expected_end == end);
|
|
|
|
count = 0;
|
|
start = now();
|
|
|
|
boost::asio::deadline_timer t5(ios, seconds(10));
|
|
t5.async_wait(boost::bind(increment_if_not_cancelled, &count,
|
|
boost::asio::placeholders::error));
|
|
boost::asio::deadline_timer t6(ios, seconds(1));
|
|
t6.async_wait(boost::bind(cancel_timer, &t5));
|
|
|
|
// No completions can be delivered until run() is called.
|
|
BOOST_CHECK(count == 0);
|
|
|
|
ios.reset();
|
|
ios.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).
|
|
BOOST_CHECK(count == 0);
|
|
end = now();
|
|
expected_end = start + seconds(2);
|
|
BOOST_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,
|
|
boost::asio::placeholders::error));
|
|
|
|
ios.reset();
|
|
ios.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.
|
|
BOOST_CHECK(count == 1);
|
|
end = now();
|
|
expected_end = start + seconds(10);
|
|
BOOST_CHECK(expected_end < end);
|
|
}
|
|
|
|
test_suite* init_unit_test_suite(int argc, char* argv[])
|
|
{
|
|
test_suite* test = BOOST_TEST_SUITE("deadline_timer");
|
|
test->add(BOOST_TEST_CASE(&deadline_timer_test));
|
|
return test;
|
|
}
|