Chris@16: // Chris@16: // detail/deadline_timer_service.hpp Chris@16: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP Chris@16: #define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #if defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: # include Chris@16: # include Chris@16: #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: class deadline_timer_service Chris@16: { Chris@16: public: Chris@16: // The time type. Chris@16: typedef typename Time_Traits::time_type time_type; Chris@16: Chris@16: // The duration type. Chris@16: typedef typename Time_Traits::duration_type duration_type; Chris@16: Chris@16: // The implementation type of the timer. This type is dependent on the Chris@16: // underlying implementation of the timer service. Chris@16: struct implementation_type Chris@16: : private boost::asio::detail::noncopyable Chris@16: { Chris@16: time_type expiry; Chris@16: bool might_have_pending_waits; Chris@16: typename timer_queue::per_timer_data timer_data; Chris@16: }; Chris@16: Chris@16: // Constructor. Chris@16: deadline_timer_service(boost::asio::io_service& io_service) Chris@16: : scheduler_(boost::asio::use_service(io_service)) Chris@16: { Chris@16: scheduler_.init_task(); Chris@16: scheduler_.add_timer_queue(timer_queue_); Chris@16: } Chris@16: Chris@16: // Destructor. Chris@16: ~deadline_timer_service() Chris@16: { Chris@16: scheduler_.remove_timer_queue(timer_queue_); Chris@16: } Chris@16: Chris@16: // Destroy all user-defined handler objects owned by the service. Chris@16: void shutdown_service() Chris@16: { Chris@16: } Chris@16: Chris@16: // Construct a new timer implementation. Chris@16: void construct(implementation_type& impl) Chris@16: { Chris@16: impl.expiry = time_type(); Chris@16: impl.might_have_pending_waits = false; Chris@16: } Chris@16: Chris@16: // Destroy a timer implementation. Chris@16: void destroy(implementation_type& impl) Chris@16: { Chris@16: boost::system::error_code ec; Chris@16: cancel(impl, ec); Chris@16: } Chris@16: Chris@16: // Cancel any asynchronous wait operations associated with the timer. Chris@16: std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) Chris@16: { Chris@16: if (!impl.might_have_pending_waits) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return 0; Chris@16: } Chris@16: Chris@16: BOOST_ASIO_HANDLER_OPERATION(("deadline_timer", &impl, "cancel")); Chris@16: Chris@16: std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); Chris@16: impl.might_have_pending_waits = false; Chris@16: ec = boost::system::error_code(); Chris@16: return count; Chris@16: } Chris@16: Chris@16: // Cancels one asynchronous wait operation associated with the timer. Chris@16: std::size_t cancel_one(implementation_type& impl, Chris@16: boost::system::error_code& ec) Chris@16: { Chris@16: if (!impl.might_have_pending_waits) Chris@16: { Chris@16: ec = boost::system::error_code(); Chris@16: return 0; Chris@16: } Chris@16: Chris@16: BOOST_ASIO_HANDLER_OPERATION(("deadline_timer", &impl, "cancel_one")); Chris@16: Chris@16: std::size_t count = scheduler_.cancel_timer( Chris@16: timer_queue_, impl.timer_data, 1); Chris@16: if (count == 0) Chris@16: impl.might_have_pending_waits = false; Chris@16: ec = boost::system::error_code(); Chris@16: return count; Chris@16: } Chris@16: Chris@16: // Get the expiry time for the timer as an absolute time. Chris@16: time_type expires_at(const implementation_type& impl) const Chris@16: { Chris@16: return impl.expiry; Chris@16: } Chris@16: Chris@16: // Set the expiry time for the timer as an absolute time. Chris@16: std::size_t expires_at(implementation_type& impl, Chris@16: const time_type& expiry_time, boost::system::error_code& ec) Chris@16: { Chris@16: std::size_t count = cancel(impl, ec); Chris@16: impl.expiry = expiry_time; Chris@16: ec = boost::system::error_code(); Chris@16: return count; Chris@16: } Chris@16: Chris@16: // Get the expiry time for the timer relative to now. Chris@16: duration_type expires_from_now(const implementation_type& impl) const Chris@16: { Chris@16: return Time_Traits::subtract(expires_at(impl), Time_Traits::now()); Chris@16: } Chris@16: Chris@16: // Set the expiry time for the timer relative to now. Chris@16: std::size_t expires_from_now(implementation_type& impl, Chris@16: const duration_type& expiry_time, boost::system::error_code& ec) Chris@16: { Chris@16: return expires_at(impl, Chris@16: Time_Traits::add(Time_Traits::now(), expiry_time), ec); Chris@16: } Chris@16: Chris@16: // Perform a blocking wait on the timer. Chris@16: void wait(implementation_type& impl, boost::system::error_code& ec) Chris@16: { Chris@16: time_type now = Time_Traits::now(); Chris@16: ec = boost::system::error_code(); Chris@16: while (Time_Traits::less_than(now, impl.expiry) && !ec) Chris@16: { Chris@16: this->do_wait(Time_Traits::to_posix_duration( Chris@16: Time_Traits::subtract(impl.expiry, now)), ec); Chris@16: now = Time_Traits::now(); Chris@16: } Chris@16: } Chris@16: Chris@16: // Start an asynchronous wait on the timer. Chris@16: template Chris@16: void async_wait(implementation_type& impl, Handler& handler) Chris@16: { Chris@16: // Allocate and construct an operation to wrap the handler. Chris@16: typedef wait_handler op; Chris@16: typename op::ptr p = { boost::asio::detail::addressof(handler), Chris@16: boost_asio_handler_alloc_helpers::allocate( Chris@16: sizeof(op), handler), 0 }; Chris@16: p.p = new (p.v) op(handler); Chris@16: Chris@16: impl.might_have_pending_waits = true; Chris@16: Chris@16: BOOST_ASIO_HANDLER_CREATION((p.p, "deadline_timer", &impl, "async_wait")); Chris@16: Chris@16: scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); Chris@16: p.v = p.p = 0; Chris@16: } Chris@16: Chris@16: private: Chris@16: // Helper function to wait given a duration type. The duration type should Chris@16: // either be of type boost::posix_time::time_duration, or implement the Chris@16: // required subset of its interface. Chris@16: template Chris@16: void do_wait(const Duration& timeout, boost::system::error_code& ec) Chris@16: { Chris@16: #if defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: std::this_thread::sleep_for( Chris@16: std::chrono::seconds(timeout.total_seconds()) Chris@16: + std::chrono::microseconds(timeout.total_microseconds())); Chris@16: ec = boost::system::error_code(); Chris@16: #else // defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: ::timeval tv; Chris@16: tv.tv_sec = timeout.total_seconds(); Chris@16: tv.tv_usec = timeout.total_microseconds() % 1000000; Chris@16: socket_ops::select(0, 0, 0, 0, &tv, ec); Chris@16: #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) Chris@16: } Chris@16: Chris@16: // The queue of timers. Chris@16: timer_queue timer_queue_; Chris@16: Chris@16: // The object that schedules and executes timers. Usually a reactor. Chris@16: timer_scheduler& scheduler_; Chris@16: }; Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP