mirror of
https://github.com/boostorg/asio.git
synced 2026-01-27 18:42:07 +00:00
........ r57393 | hkaiser | 2009-11-05 11:26:15 +1100 (Thu, 05 Nov 2009) | 1 line Asio: disabled VC workaround for VC2010 beta2 compiler. Fixes #3796. ........ r58621 | chris_kohlhoff | 2010-01-02 10:04:35 +1100 (Sat, 02 Jan 2010) | 2 lines Wrap long line. ........ r58624 | chris_kohlhoff | 2010-01-02 17:09:02 +1100 (Sat, 02 Jan 2010) | 3 lines Windows needs the OVERLAPPED structure to be valid until both the initiating function call has returned and the completion packet has been delivered. ........ r58625 | chris_kohlhoff | 2010-01-02 18:16:41 +1100 (Sat, 02 Jan 2010) | 2 lines Use specific type_traits headers. ........ r58626 | chris_kohlhoff | 2010-01-02 18:18:09 +1100 (Sat, 02 Jan 2010) | 2 lines Include specific headers in unit tests rather than the convenience header asio.hpp. ........ r58627 | chris_kohlhoff | 2010-01-02 19:24:12 +1100 (Sat, 02 Jan 2010) | 3 lines Use boost::addressof to get the address of handler objects, rather than applying operator& directly. Fixes #2977. ........ r58628 | chris_kohlhoff | 2010-01-02 20:48:01 +1100 (Sat, 02 Jan 2010) | 3 lines Don't block signals while performing system calls, but instead restart the calls if they are interrupted. ........ r58629 | chris_kohlhoff | 2010-01-02 21:20:12 +1100 (Sat, 02 Jan 2010) | 2 lines Ensure that kqueue support is enabled for BSD platforms. Fixes #3626. ........ r58630 | chris_kohlhoff | 2010-01-02 21:30:41 +1100 (Sat, 02 Jan 2010) | 2 lines Add boost_ prefix to extern "C" thread entry point function. Fixes #3809. ........ r58647 | chris_kohlhoff | 2010-01-03 07:36:59 +1100 (Sun, 03 Jan 2010) | 2 lines Use a pool of strand implementations to make copying of strands cheaper. ........ r58650 | chris_kohlhoff | 2010-01-03 08:35:33 +1100 (Sun, 03 Jan 2010) | 4 lines In getaddrinfo emulation, only check the socket type (SOCK_STREAM or SOCK_DGRAM) if a service name has been specified. This should allow the emulation to work with raw sockets. ........ r58651 | chris_kohlhoff | 2010-01-03 08:37:10 +1100 (Sun, 03 Jan 2010) | 3 lines Add a workaround for some broken Windows firewalls that make a socket appear bound to 0.0.0.0 when it is in fact bound to 127.0.0.1. ........ r58652 | chris_kohlhoff | 2010-01-03 08:38:44 +1100 (Sun, 03 Jan 2010) | 2 lines Only include implementation headers required for each platform. ........ [SVN r58669]
267 lines
6.8 KiB
C++
267 lines
6.8 KiB
C++
//
|
|
// deadline_timer.cpp
|
|
// ~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2010 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/io_service.hpp>
|
|
#include <boost/asio/placeholders.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::system::error_code& ec)
|
|
{
|
|
if (!ec)
|
|
++(*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 || expected_end == end);
|
|
}
|
|
|
|
void timer_handler(const boost::system::error_code&)
|
|
{
|
|
}
|
|
|
|
void deadline_timer_cancel_test()
|
|
{
|
|
static boost::asio::io_service io_service;
|
|
struct timer
|
|
{
|
|
boost::asio::deadline_timer t;
|
|
timer() : t(io_service) { 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);
|
|
|
|
BOOST_CHECK(timers[2].t.cancel() == 1);
|
|
BOOST_CHECK(timers[41].t.cancel() == 1);
|
|
for (int i = 10; i < 20; ++i)
|
|
BOOST_CHECK(timers[i].t.cancel() == 1);
|
|
}
|
|
|
|
struct custom_allocation_timer_handler
|
|
{
|
|
custom_allocation_timer_handler(int* count) : count_(count) {}
|
|
void operator()(const boost::system::error_code&) {}
|
|
int* count_;
|
|
};
|
|
|
|
void* asio_handler_allocate(std::size_t size,
|
|
custom_allocation_timer_handler* handler)
|
|
{
|
|
++(*handler->count_);
|
|
return ::operator new(size);
|
|
}
|
|
|
|
void asio_handler_deallocate(void* pointer, std::size_t,
|
|
custom_allocation_timer_handler* handler)
|
|
{
|
|
--(*handler->count_);
|
|
::operator delete(pointer);
|
|
}
|
|
|
|
void deadline_timer_custom_allocation_test()
|
|
{
|
|
static boost::asio::io_service io_service;
|
|
struct timer
|
|
{
|
|
boost::asio::deadline_timer t;
|
|
timer() : t(io_service) {}
|
|
} 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_service.run();
|
|
|
|
BOOST_CHECK(allocation_count == 0);
|
|
}
|
|
|
|
test_suite* init_unit_test_suite(int, char*[])
|
|
{
|
|
test_suite* test = BOOST_TEST_SUITE("deadline_timer");
|
|
test->add(BOOST_TEST_CASE(&deadline_timer_test));
|
|
test->add(BOOST_TEST_CASE(&deadline_timer_cancel_test));
|
|
test->add(BOOST_TEST_CASE(&deadline_timer_custom_allocation_test));
|
|
return test;
|
|
}
|