// // basic_deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2005 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_BASIC_DEADLINE_TIMER_HPP #define BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include #include #include namespace boost { namespace asio { /// Provides waitable timer functionality. /** * The basic_deadline_timer class template provides the ability to perform a * blocking or asynchronous wait for a timer to expire. * * Most applications will use the boost::asio::deadline_timer typedef. * * @par Thread Safety: * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * Async_Object, Error_Source. * * @sa @ref deadline_timer_reset * * @par Examples: * Performing a blocking wait: * @code * // Construct a timer without setting an expiry time. * boost::asio::deadline_timer timer(demuxer); * * // Set an expiry time relative to now. * timer.expires_from_now(boost::posix_time::seconds(5)); * * // Wait for the timer to expire. * timer.wait(); * @endcode * * @par * Performing an asynchronous wait: * @code * void handler(const boost::asio::error& error) * { * if (!error) * { * // Timer expired. * } * } * * ... * * // Construct a timer with an absolute expiry time. * boost::asio::deadline_timer timer(demuxer, * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); * * // Start an asynchronous wait. * timer.async_wait(handler); * @endcode */ template class basic_deadline_timer : private noncopyable { public: /// The type of the service that will be used to provide timer operations. typedef Service service_type; /// The native implementation type of the timer. typedef typename service_type::impl_type impl_type; /// The demuxer type for this asynchronous type. typedef typename service_type::demuxer_type demuxer_type; /// The type used for reporting errors. typedef boost::asio::error error_type; /// The time type. typedef typename service_type::time_type time_type; /// The duration type. typedef typename service_type::duration_type duration_type; /// Constructor. /** * This constructor creates a timer without setting an expiry time. The * expires_at() or expires_from_now() functions must be called to set an * expiry time before the timer can be waited on. * * @param d The demuxer object that the timer will use to dispatch handlers * for any asynchronous operations performed on the timer. */ explicit basic_deadline_timer(demuxer_type& d) : service_(d.get_service(service_factory())), impl_(service_.null()) { service_.create(impl_); } /// Constructor to set a particular expiry time as an absolute time. /** * This constructor creates a timer and sets the expiry time. * * @param d The demuxer object that the timer will use to dispatch handlers * for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, expressed * as an absolute time. */ basic_deadline_timer(demuxer_type& d, const time_type& expiry_time) : service_(d.get_service(service_factory())), impl_(service_.null()) { service_.create(impl_); destroy_on_block_exit auto_destroy(service_, impl_); service_.expires_at(impl_, expiry_time); auto_destroy.cancel(); } /// Constructor to set a particular expiry time relative to now. /** * This constructor creates a timer and sets the expiry time. * * @param d The demuxer object that the timer will use to dispatch handlers * for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, relative to * now. */ basic_deadline_timer(demuxer_type& d, const duration_type& expiry_time) : service_(d.get_service(service_factory())), impl_(service_.null()) { service_.create(impl_); destroy_on_block_exit auto_destroy(service_, impl_); service_.expires_from_now(impl_, expiry_time); auto_destroy.cancel(); } /// Destructor. ~basic_deadline_timer() { service_.destroy(impl_); } /// Get the demuxer associated with the asynchronous object. /** * This function may be used to obtain the demuxer object that the timer uses * to dispatch handlers for asynchronous operations. * * @return A reference to the demuxer object that the timer will use to * dispatch handlers. Ownership is not transferred to the caller. */ demuxer_type& demuxer() { return service_.demuxer(); } /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the * timer. This is intended to allow access to native timer functionality that * is not otherwise provided. */ impl_type impl() { return impl_; } /// Get the timer's expiry time as an absolute time. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. */ time_type expires_at() const { return service_.expires_at(impl_); } /// Set the timer's expiry time as an absolute time. /** * This function sets the expiry time. * * @param expiry_time The expiry time to be used for the timer. * * @note Modifying the expiry time of a timer while it is active (where * active means there are asynchronous waits on the timer) has undefined * behaviour. See @ref deadline_timer_reset for information on how to safely * alter a timer's expiry in this case. */ void expires_at(const time_type& expiry_time) { service_.expires_at(impl_, expiry_time); } /// Get the timer's expiry time relative to now. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. */ duration_type expires_from_now() const { return service_.expires_from_now(impl_); } /// Set the timer's expiry time relative to now. /** * This function sets the expiry time. * * @param expiry_time The expiry time to be used for the timer. * * @note Modifying the expiry time of a timer while it is active (where * active means there are asynchronous waits on the timer) has undefined * behaviour. See @ref deadline_timer_reset for information on how to safely * alter a timer's expiry in this case. */ void expires_from_now(const duration_type& expiry_time) { service_.expires_from_now(impl_, expiry_time); } /// Cancel any asynchronous operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait * operations against the timer. The handler for each cancelled operation * will be invoked with the boost::asio::error::operation_aborted error code. * * Cancelling the timer does not change the expiry time. * * @return The number of asynchronous operations that were cancelled. */ std::size_t cancel() { return service_.cancel(impl_); } /// Perform a blocking wait on the timer. /** * This function is used to wait for the timer to expire. This function * blocks and does not return until the timer has expired. * * @throws boost::asio::error Thrown on failure. */ void wait() { service_.wait(impl_); } /// Start an asynchronous wait on the timer. /** * This function may be used to initiate an asynchronous wait against the * timer. It always returns immediately. * * For each call to async_wait(), the supplied handler will be called exactly * once. The handler will be called when: * * @li The timer has expired. * * @li The timer was cancelled, in which case the handler is passed the error * code boost::asio::error::operation_aborted. * * @param handler The handler to be called when the timer expires. Copies * will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const boost::asio::error& error // Result of operation * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * boost::asio::demuxer::post(). */ template void async_wait(Handler handler) { service_.async_wait(impl_, handler); } private: /// The backend service implementation. service_type& service_; /// The underlying native implementation. impl_type impl_; // Helper class to automatically destroy the implementation on block exit. class destroy_on_block_exit { public: destroy_on_block_exit(service_type& service, impl_type& impl) : service_(&service), impl_(impl) { } ~destroy_on_block_exit() { if (service_) { service_->destroy(impl_); } } void cancel() { service_ = 0; } private: service_type* service_; impl_type& impl_; }; }; /** * @page deadline_timer_reset Changing an active deadline_timer's expiry time * * Changing the expiry time of a timer while there are asynchronous waits on it * has undefined behaviour. To safely change a timer's expiry, pending * asynchronous waits need to be cancelled first. This works as follows: * * @li The boost::asio::basic_deadline_timer::cancel() function returns the * number of asynchronous waits that were cancelled. If it returns 0 then you * were too late and the wait handler has already been executed, or will soon be * executed. If it returns 1 then the wait handler was successfully cancelled. * * @li If a wait handler is cancelled, the boost::asio::error passed to it * contains the value boost::asio::error::operation_aborted. * * For example, to reset a timer's expiry time in response to some event you * would do something like this: * * @code * void on_some_event() * { * if (my_timer.cancel() > 0) * { * // We managed to cancel the timer. Set new expiry time. * my_timer.expires_from_now(seconds(5)); * my_timer.async_wait(on_timeout); * } * else * { * // Too late, timer has already expired! * } * } * * void on_timeout(const boost::asio::error& e) * { * if (e != boost::asio::error::operation_aborted) * { * // Timer was not cancelled, take necessary action. * } * } * @endcode * * @sa boost::asio::basic_deadline_timer */ } // namespace asio } // namespace boost #include #endif // BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP