Update of /cvsroot/boost/boost/boost/asio/detail
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv6057/boost/asio/detail
Modified Files:
epoll_reactor.hpp kqueue_reactor.hpp
reactive_socket_service.hpp select_reactor.hpp
Added Files:
deadline_timer_service.hpp timer_queue.hpp
timer_queue_base.hpp
Removed Files:
reactive_deadline_timer_service.hpp reactor_timer_queue.hpp
Log Message:
Maintain separate timer queues for each time traits type.
--- NEW FILE: deadline_timer_service.hpp ---
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// 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)
//
#ifndef BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
#define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/detail/push_options.hpp>
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
#include <boost/asio/detail/timer_queue.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Time_Traits, typename Timer_Scheduler>
class deadline_timer_service
: public boost::asio::io_service::service
{
public:
// The time type.
typedef typename Time_Traits::time_type time_type;
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
// The implementation type of the timer. This type is dependent on the
// underlying implementation of the timer service.
struct implementation_type
: private boost::asio::detail::noncopyable
{
time_type expiry;
bool might_have_pending_waits;
};
// Constructor.
deadline_timer_service(boost::asio::io_service& io_service)
: boost::asio::io_service::service(io_service),
scheduler_(boost::asio::use_service<Timer_Scheduler>(io_service))
{
scheduler_.add_timer_queue(timer_queue_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
// Construct a new timer implementation.
void construct(implementation_type& impl)
{
impl.expiry = time_type();
impl.might_have_pending_waits = false;
}
// Destroy a timer implementation.
void destroy(implementation_type& impl)
{
cancel(impl);
}
// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl)
{
if (!impl.might_have_pending_waits)
return 0;
std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
impl.might_have_pending_waits = false;
return count;
}
// Get the expiry time for the timer as an absolute time.
time_type expires_at(const implementation_type& impl) const
{
return impl.expiry;
}
// Set the expiry time for the timer as an absolute time.
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time)
{
std::size_t count = cancel(impl);
impl.expiry = expiry_time;
return count;
}
// Get the expiry time for the timer relative to now.
duration_type expires_from_now(const implementation_type& impl) const
{
return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
}
// Set the expiry time for the timer relative to now.
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time)
{
return expires_at(impl, Time_Traits::add(Time_Traits::now(), expiry_time));
}
// Perform a blocking wait on the timer.
void wait(implementation_type& impl)
{
time_type now = Time_Traits::now();
while (Time_Traits::less_than(now, impl.expiry))
{
boost::posix_time::time_duration timeout =
Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now));
::timeval tv;
tv.tv_sec = timeout.total_seconds();
tv.tv_usec = timeout.total_microseconds() % 1000000;
socket_ops::select(0, 0, 0, 0, &tv);
now = Time_Traits::now();
}
}
template <typename Handler>
class wait_handler
{
public:
wait_handler(boost::asio::io_service& io_service, Handler handler)
: io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()(int result)
{
boost::asio::error e(result);
io_service_.post(detail::bind_handler(handler_, e));
}
private:
boost::asio::io_service& io_service_;
boost::asio::io_service::work work_;
Handler handler_;
};
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler handler)
{
impl.might_have_pending_waits = true;
scheduler_.schedule_timer(timer_queue_, impl.expiry,
wait_handler<Handler>(owner(), handler), &impl);
}
private:
// The queue of timers.
timer_queue<Time_Traits> timer_queue_;
// The object that schedules and executes timers. Usually a reactor.
Timer_Scheduler& scheduler_;
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
--- NEW FILE: timer_queue.hpp ---
//
// timer_queue.hpp
// ~~~~~~~~~~~~~~~
//
// 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)
//
#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
#define BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/detail/push_options.hpp>
#include <cstddef>
#include <functional>
#include <limits>
#include <memory>
#include <vector>
#include <boost/config.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/hash_map.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/timer_queue_base.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Time_Traits>
class timer_queue
: public timer_queue_base
{
public:
// The time type.
typedef typename Time_Traits::time_type time_type;
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
// Constructor.
timer_queue()
: timers_(),
heap_()
{
}
// Add a new timer to the queue. Returns true if this is the timer that is
// earliest in the queue, in which case the reactor's event demultiplexing
// function call may need to be interrupted and restarted.
template <typename Handler>
bool enqueue_timer(const time_type& time, Handler handler, void* token)
{
// Ensure that there is space for the timer in the heap. We reserve here so
// that the push_back below will not throw due to a reallocation failure.
heap_.reserve(heap_.size() + 1);
// Create a new timer object.
std::auto_ptr<timer<Handler> > new_timer(
new timer<Handler>(time, handler, token));
// Insert the new timer into the hash.
typedef typename hash_map<void*, timer_base*>::iterator iterator;
typedef typename hash_map<void*, timer_base*>::value_type value_type;
std::pair<iterator, bool> result =
timers_.insert(value_type(token, new_timer.get()));
if (!result.second)
{
result.first->second->prev_ = new_timer.get();
new_timer->next_ = result.first->second;
result.first->second = new_timer.get();
}
// Put the timer at the correct position in the heap.
new_timer->heap_index_ = heap_.size();
heap_.push_back(new_timer.get());
up_heap(heap_.size() - 1);
bool is_first = (heap_[0] == new_timer.get());
// Ownership of the timer is transferred to the timer queue.
new_timer.release();
return is_first;
}
// Whether there are no timers in the queue.
virtual bool empty() const
{
return heap_.empty();
}
// Get the time for the timer that is earliest in the queue.
virtual boost::posix_time::time_duration wait_duration() const
{
return Time_Traits::to_posix_duration(
Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
}
// Dispatch the timers that are earlier than the specified time.
virtual void dispatch_timers()
{
const time_type now = Time_Traits::now();
while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
{
timer_base* t = heap_[0];
remove_timer(t);
t->invoke(0);
}
}
// Cancel the timer with the given token. The handler will be invoked
// immediately with the result operation_aborted.
std::size_t cancel_timer(void* timer_token)
{
std::size_t num_cancelled = 0;
typedef typename hash_map<void*, timer_base*>::iterator iterator;
iterator it = timers_.find(timer_token);
if (it != timers_.end())
{
timer_base* t = it->second;
while (t)
{
timer_base* next = t->next_;
remove_timer(t);
t->invoke(boost::asio::error::operation_aborted);
t = next;
++num_cancelled;
}
}
return num_cancelled;
}
// Destroy all timers.
virtual void destroy_timers()
{
typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
typename hash_map<void*, timer_base*>::iterator end = timers_.end();
while (i != end)
{
timer_base* t = i->second;
typename hash_map<void*, timer_base*>::iterator old_i = i++;
timers_.erase(old_i);
t->destroy();
}
heap_.clear();
timers_.clear();
}
private:
// Base class for timer operations. Function pointers are used instead of
// virtual functions to avoid the associated overhead.
class timer_base
{
public:
// Perform the timer operation and then destroy.
void invoke(int result)
{
invoke_func_(this, result);
}
// Destroy the timer operation.
void destroy()
{
destroy_func_(this);
}
protected:
typedef void (*invoke_func_type)(timer_base*, int);
typedef void (*destroy_func_type)(timer_base*);
// Constructor.
timer_base(invoke_func_type invoke_func, destroy_func_type destroy_func,
const time_type& time, void* token)
: invoke_func_(invoke_func),
destroy_func_(destroy_func),
time_(time),
token_(token),
next_(0),
prev_(0),
heap_index_(
std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
{
}
// Prevent deletion through this type.
~timer_base()
{
}
private:
friend class timer_queue<Time_Traits>;
// The function to be called to dispatch the handler.
invoke_func_type invoke_func_;
// The function to be called to destroy the handler.
destroy_func_type destroy_func_;
// The time when the operation should fire.
time_type time_;
// The token associated with the timer.
void* token_;
// The next timer known to the queue.
timer_base* next_;
// The previous timer known to the queue.
timer_base* prev_;
// The index of the timer in the heap.
size_t heap_index_;
};
// Adaptor class template for using handlers in timers.
template <typename Handler>
class timer
: public timer_base
{
public:
// Constructor.
timer(const time_type& time, Handler handler, void* token)
: timer_base(&timer<Handler>::invoke_handler,
&timer<Handler>::destroy_handler, time, token),
handler_(handler)
{
}
// Invoke the handler and then destroy it.
static void invoke_handler(timer_base* base, int result)
{
std::auto_ptr<timer<Handler> > t(static_cast<timer<Handler>*>(base));
t->handler_(result);
}
// Destroy the handler.
static void destroy_handler(timer_base* base)
{
delete static_cast<timer<Handler>*>(base);
}
private:
Handler handler_;
};
// Move the item at the given index up the heap to its correct position.
void up_heap(size_t index)
{
size_t parent = (index - 1) / 2;
while (index > 0
&& Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
{
swap_heap(index, parent);
index = parent;
parent = (index - 1) / 2;
}
}
// Move the item at the given index down the heap to its correct position.
void down_heap(size_t index)
{
size_t child = index * 2 + 1;
while (child < heap_.size())
{
size_t min_child = (child + 1 == heap_.size()
|| Time_Traits::less_than(
heap_[child]->time_, heap_[child + 1]->time_))
? child : child + 1;
if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
break;
swap_heap(index, min_child);
index = min_child;
child = index * 2 + 1;
}
}
// Swap two entries in the heap.
void swap_heap(size_t index1, size_t index2)
{
timer_base* tmp = heap_[index1];
heap_[index1] = heap_[index2];
heap_[index2] = tmp;
heap_[index1]->heap_index_ = index1;
heap_[index2]->heap_index_ = index2;
}
// Remove a timer from the heap and list of timers.
void remove_timer(timer_base* t)
{
// Remove the timer from the heap.
size_t index = t->heap_index_;
if (!heap_.empty() && index < heap_.size())
{
if (index == heap_.size() - 1)
{
heap_.pop_back();
}
else
{
swap_heap(index, heap_.size() - 1);
heap_.pop_back();
size_t parent = (index - 1) / 2;
if (index > 0 && Time_Traits::less_than(t->time_, heap_[parent]->time_))
up_heap(index);
else
down_heap(index);
}
}
// Remove the timer from the hash.
typedef typename hash_map<void*, timer_base*>::iterator iterator;
iterator it = timers_.find(t->token_);
if (it != timers_.end())
{
if (it->second == t)
it->second = t->next_;
if (t->prev_)
t->prev_->next_ = t->next_;
if (t->next_)
t->next_->prev_ = t->prev_;
if (it->second == 0)
timers_.erase(it);
}
}
// A hash of timer token to linked lists of timers.
hash_map<void*, timer_base*> timers_;
// The heap of timers, with the earliest timer at the front.
std::vector<timer_base*> heap_;
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
--- NEW FILE: timer_queue_base.hpp ---
//
// timer_queue_base.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// 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)
//
#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
#define BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/detail/socket_types.hpp> // Must come before posix_time.
#include <boost/asio/detail/push_options.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/detail/noncopyable.hpp>
namespace boost {
namespace asio {
namespace detail {
class timer_queue_base
: private noncopyable
{
public:
// Destructor.
virtual ~timer_queue_base() {}
// Whether there are no timers in the queue.
virtual bool empty() const = 0;
// Get the time to wait until the next timer.
virtual boost::posix_time::time_duration wait_duration() const = 0;
// Dispatch all ready timers.
virtual void dispatch_timers() = 0;
// Destroy all timers.
virtual void destroy_timers() = 0;
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
Index: epoll_reactor.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/asio/detail/epoll_reactor.hpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- epoll_reactor.hpp 14 Jun 2006 22:26:30 -0000 1.1
+++ epoll_reactor.hpp 26 Jul 2006 11:23:25 -0000 1.2
@@ -38,10 +38,10 @@
#include <boost/asio/detail/task_io_service.hpp>
#include <boost/asio/detail/thread.hpp>
#include <boost/asio/detail/reactor_op_queue.hpp>
-#include <boost/asio/detail/reactor_timer_queue.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
namespace boost {
namespace asio {
@@ -108,7 +108,10 @@
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
- timer_queue_.destroy_timers();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
@@ -286,24 +289,33 @@
cancel_ops_unlocked(descriptor);
}
- // Schedule a timer to expire at the specified absolute time. The handler
- // object will be invoked when the timer expires.
- template <typename Handler>
- void schedule_timer(const boost::posix_time::ptime& time,
- Handler handler, void* token)
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void*
token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue_.enqueue_timer(time, handler, token))
+ if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
- std::size_t cancel_timer(void* token)
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- return timer_queue_.cancel_timer(token);
+ return timer_queue.cancel_timer(token);
}
private:
@@ -335,7 +347,7 @@
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
- && except_op_queue_.empty() && timer_queue_.empty())
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
{
// Clean up operations. We must not hold the lock since the operations
may
// make calls back into this reactor.
@@ -427,8 +439,8 @@
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
- timer_queue_.dispatch_timers(
- boost::posix_time::microsec_clock::universal_time());
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_timers();
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
@@ -483,26 +495,39 @@
return fd;
}
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
// Get the timeout value for the epoll_wait call. The timeout value is
// returned as a number of milliseconds. A return value of -1 indicates
// that epoll_wait should block indefinitely.
int get_timeout()
{
- if (timer_queue_.empty())
+ if (all_timer_queues_are_empty())
return -1;
- boost::posix_time::ptime now
- = boost::posix_time::microsec_clock::universal_time();
- boost::posix_time::ptime earliest_timer;
- timer_queue_.get_earliest_time(earliest_timer);
- if (now < earliest_timer)
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
- boost::posix_time::time_duration timeout = earliest_timer - now;
- const int max_timeout_in_seconds = INT_MAX / 1000;
- if (max_timeout_in_seconds < timeout.total_seconds())
- return max_timeout_in_seconds * 1000;
- else
- return timeout.total_milliseconds();
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ return minimum_wait_duration.total_milliseconds();
}
else
{
@@ -543,8 +568,8 @@
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
- // The queue of timers.
- reactor_timer_queue<boost::posix_time::ptime> timer_queue_;
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
Index: kqueue_reactor.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/asio/detail/kqueue_reactor.hpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- kqueue_reactor.hpp 5 Jul 2006 05:26:35 -0000 1.2
+++ kqueue_reactor.hpp 26 Jul 2006 11:23:25 -0000 1.3
@@ -40,10 +40,10 @@
#include <boost/asio/detail/task_io_service.hpp>
#include <boost/asio/detail/thread.hpp>
#include <boost/asio/detail/reactor_op_queue.hpp>
-#include <boost/asio/detail/reactor_timer_queue.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
// Older versions of Mac OS X may not define EV_OOBAND.
#if !defined(EV_OOBAND)
@@ -115,7 +115,10 @@
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
- timer_queue_.destroy_timers();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
@@ -275,26 +278,33 @@
cancel_ops_unlocked(descriptor);
}
- // Schedule a timer to expire at the specified absolute time. The
- // do_operation function of the handler object will be invoked when the timer
- // expires. Returns a token that may be used for cancelling the timer, but it
- // is not valid after the timer expires.
- template <typename Handler>
- void schedule_timer(const boost::posix_time::ptime& time,
- Handler handler, void* token)
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void*
token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue_.enqueue_timer(time, handler, token))
+ if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
- std::size_t cancel_timer(void* token)
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- return timer_queue_.cancel_timer(token);
+ return timer_queue.cancel_timer(token);
}
private:
@@ -326,7 +336,7 @@
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
- && except_op_queue_.empty() && timer_queue_.empty())
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
{
// Clean up operations. We must not hold the lock since the operations
may
// make calls back into this reactor.
@@ -433,11 +443,11 @@
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
- timer_queue_.dispatch_timers(
- boost::posix_time::microsec_clock::universal_time());
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_timers();
// Issue any pending cancellations.
- for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ for (std::size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
@@ -486,21 +496,38 @@
return fd;
}
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
// Get the timeout value for the kevent call.
timespec* get_timeout(timespec& ts)
{
- if (timer_queue_.empty())
+ if (all_timer_queues_are_empty())
return 0;
- boost::posix_time::ptime now
- = boost::posix_time::microsec_clock::universal_time();
- boost::posix_time::ptime earliest_timer;
- timer_queue_.get_earliest_time(earliest_timer);
- if (now < earliest_timer)
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
- boost::posix_time::time_duration timeout = earliest_timer - now;
- ts.tv_sec = timeout.total_seconds();
- ts.tv_nsec = timeout.total_nanoseconds() % 1000000000;
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ ts.tv_sec = minimum_wait_duration.total_seconds();
+ ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000;
}
else
{
@@ -544,8 +571,8 @@
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
- // The queue of timers.
- reactor_timer_queue<boost::posix_time::ptime> timer_queue_;
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
Index: reactive_socket_service.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/asio/detail/reactive_socket_service.hpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- reactive_socket_service.hpp 9 Jul 2006 06:57:33 -0000 1.3
+++ reactive_socket_service.hpp 26 Jul 2006 11:23:25 -0000 1.4
@@ -1063,12 +1063,6 @@
return;
}
- if (int err = socket_ops::get_error())
- {
- error_handler(boost::asio::error(err));
- return;
- }
-
// Accept a socket.
for (;;)
{
Index: select_reactor.hpp
===================================================================
RCS file: /cvsroot/boost/boost/boost/asio/detail/select_reactor.hpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- select_reactor.hpp 14 Jun 2006 22:26:31 -0000 1.1
+++ select_reactor.hpp 26 Jul 2006 11:23:25 -0000 1.2
@@ -34,12 +34,12 @@
#include <boost/asio/detail/task_io_service.hpp>
#include <boost/asio/detail/thread.hpp>
#include <boost/asio/detail/reactor_op_queue.hpp>
-#include <boost/asio/detail/reactor_timer_queue.hpp>
#include <boost/asio/detail/select_interrupter.hpp>
#include <boost/asio/detail/select_reactor_fwd.hpp>
#include <boost/asio/detail/signal_blocker.hpp>
#include <boost/asio/detail/socket_ops.hpp>
#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
namespace boost {
namespace asio {
@@ -97,7 +97,10 @@
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
- timer_queue_.destroy_timers();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
@@ -184,24 +187,33 @@
cancel_ops_unlocked(descriptor);
}
- // Schedule a timer to expire at the specified absolute time. The handler
- // object will be invoked when the timer expires.
- template <typename Handler>
- void schedule_timer(const boost::posix_time::ptime& time,
- Handler handler, void* token)
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void*
token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
- if (timer_queue_.enqueue_timer(time, handler, token))
+ if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
- std::size_t cancel_timer(void* token)
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
- return timer_queue_.cancel_timer(token);
+ return timer_queue.cancel_timer(token);
}
private:
@@ -233,7 +245,7 @@
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
- && except_op_queue_.empty() && timer_queue_.empty())
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
{
// Clean up operations. We must not hold the lock since the operations
may
// make calls back into this reactor.
@@ -288,8 +300,8 @@
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
}
- timer_queue_.dispatch_timers(
- boost::posix_time::microsec_clock::universal_time());
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_timers();
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
@@ -328,21 +340,38 @@
interrupter_.interrupt();
}
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
// Get the timeout value for the select call.
timeval* get_timeout(timeval& tv)
{
- if (timer_queue_.empty())
+ if (all_timer_queues_are_empty())
return 0;
- boost::posix_time::ptime now
- = boost::posix_time::microsec_clock::universal_time();
- boost::posix_time::ptime earliest_timer;
- timer_queue_.get_earliest_time(earliest_timer);
- if (now < earliest_timer)
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
- boost::posix_time::time_duration timeout = earliest_timer - now;
- tv.tv_sec = timeout.total_seconds();
- tv.tv_usec = timeout.total_microseconds() % 1000000;
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ tv.tv_sec = minimum_wait_duration.total_seconds();
+ tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000;
}
else
{
@@ -383,8 +412,8 @@
// The queue of exception operations.
reactor_op_queue<socket_type> except_op_queue_;
- // The queue of timers.
- reactor_timer_queue<boost::posix_time::ptime> timer_queue_;
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
--- reactive_deadline_timer_service.hpp DELETED ---
--- reactor_timer_queue.hpp DELETED ---
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs