Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 08:08:45

0001 //
0002 // detail/deadline_timer_service.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <cstddef>
0020 #include <boost/asio/associated_cancellation_slot.hpp>
0021 #include <boost/asio/cancellation_type.hpp>
0022 #include <boost/asio/error.hpp>
0023 #include <boost/asio/execution_context.hpp>
0024 #include <boost/asio/detail/bind_handler.hpp>
0025 #include <boost/asio/detail/fenced_block.hpp>
0026 #include <boost/asio/detail/memory.hpp>
0027 #include <boost/asio/detail/noncopyable.hpp>
0028 #include <boost/asio/detail/socket_ops.hpp>
0029 #include <boost/asio/detail/socket_types.hpp>
0030 #include <boost/asio/detail/timer_queue.hpp>
0031 #include <boost/asio/detail/timer_queue_ptime.hpp>
0032 #include <boost/asio/detail/timer_scheduler.hpp>
0033 #include <boost/asio/detail/wait_handler.hpp>
0034 #include <boost/asio/detail/wait_op.hpp>
0035 
0036 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0037 # include <chrono>
0038 # include <thread>
0039 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
0040 
0041 #include <boost/asio/detail/push_options.hpp>
0042 
0043 namespace boost {
0044 namespace asio {
0045 namespace detail {
0046 
0047 template <typename Time_Traits>
0048 class deadline_timer_service
0049   : public execution_context_service_base<deadline_timer_service<Time_Traits>>
0050 {
0051 public:
0052   // The time type.
0053   typedef typename Time_Traits::time_type time_type;
0054 
0055   // The duration type.
0056   typedef typename Time_Traits::duration_type duration_type;
0057 
0058   // The implementation type of the timer. This type is dependent on the
0059   // underlying implementation of the timer service.
0060   struct implementation_type
0061     : private boost::asio::detail::noncopyable
0062   {
0063     time_type expiry;
0064     bool might_have_pending_waits;
0065     typename timer_queue<Time_Traits>::per_timer_data timer_data;
0066   };
0067 
0068   // Constructor.
0069   deadline_timer_service(execution_context& context)
0070     : execution_context_service_base<
0071         deadline_timer_service<Time_Traits>>(context),
0072       scheduler_(boost::asio::use_service<timer_scheduler>(context))
0073   {
0074     scheduler_.init_task();
0075     scheduler_.add_timer_queue(timer_queue_);
0076   }
0077 
0078   // Destructor.
0079   ~deadline_timer_service()
0080   {
0081     scheduler_.remove_timer_queue(timer_queue_);
0082   }
0083 
0084   // Destroy all user-defined handler objects owned by the service.
0085   void shutdown()
0086   {
0087   }
0088 
0089   // Construct a new timer implementation.
0090   void construct(implementation_type& impl)
0091   {
0092     impl.expiry = time_type();
0093     impl.might_have_pending_waits = false;
0094   }
0095 
0096   // Destroy a timer implementation.
0097   void destroy(implementation_type& impl)
0098   {
0099     boost::system::error_code ec;
0100     cancel(impl, ec);
0101   }
0102 
0103   // Move-construct a new timer implementation.
0104   void move_construct(implementation_type& impl,
0105       implementation_type& other_impl)
0106   {
0107     if (other_impl.might_have_pending_waits)
0108     {
0109       scheduler_.move_timer(timer_queue_,
0110           impl.timer_data, other_impl.timer_data);
0111     }
0112 
0113     impl.expiry = other_impl.expiry;
0114     other_impl.expiry = time_type();
0115 
0116     impl.might_have_pending_waits = other_impl.might_have_pending_waits;
0117     other_impl.might_have_pending_waits = false;
0118   }
0119 
0120   // Move-assign from another timer implementation.
0121   void move_assign(implementation_type& impl,
0122       deadline_timer_service& other_service,
0123       implementation_type& other_impl)
0124   {
0125     if (this != &other_service)
0126       if (impl.might_have_pending_waits)
0127         scheduler_.cancel_timer(timer_queue_, impl.timer_data);
0128 
0129     other_service.scheduler_.move_timer(other_service.timer_queue_,
0130         impl.timer_data, other_impl.timer_data);
0131 
0132     impl.expiry = other_impl.expiry;
0133     other_impl.expiry = time_type();
0134 
0135     impl.might_have_pending_waits = other_impl.might_have_pending_waits;
0136     other_impl.might_have_pending_waits = false;
0137   }
0138 
0139   // Move-construct a new timer implementation.
0140   void converting_move_construct(implementation_type& impl,
0141       deadline_timer_service&, implementation_type& other_impl)
0142   {
0143     move_construct(impl, other_impl);
0144   }
0145 
0146   // Move-assign from another timer implementation.
0147   void converting_move_assign(implementation_type& impl,
0148       deadline_timer_service& other_service,
0149       implementation_type& other_impl)
0150   {
0151     move_assign(impl, other_service, other_impl);
0152   }
0153 
0154   // Cancel any asynchronous wait operations associated with the timer.
0155   std::size_t cancel(implementation_type& impl, boost::system::error_code& ec)
0156   {
0157     if (!impl.might_have_pending_waits)
0158     {
0159       ec = boost::system::error_code();
0160       return 0;
0161     }
0162 
0163     BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(),
0164           "deadline_timer", &impl, 0, "cancel"));
0165 
0166     std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
0167     impl.might_have_pending_waits = false;
0168     ec = boost::system::error_code();
0169     return count;
0170   }
0171 
0172   // Cancels one asynchronous wait operation associated with the timer.
0173   std::size_t cancel_one(implementation_type& impl,
0174       boost::system::error_code& ec)
0175   {
0176     if (!impl.might_have_pending_waits)
0177     {
0178       ec = boost::system::error_code();
0179       return 0;
0180     }
0181 
0182     BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(),
0183           "deadline_timer", &impl, 0, "cancel_one"));
0184 
0185     std::size_t count = scheduler_.cancel_timer(
0186         timer_queue_, impl.timer_data, 1);
0187     if (count == 0)
0188       impl.might_have_pending_waits = false;
0189     ec = boost::system::error_code();
0190     return count;
0191   }
0192 
0193   // Get the expiry time for the timer as an absolute time.
0194   time_type expiry(const implementation_type& impl) const
0195   {
0196     return impl.expiry;
0197   }
0198 
0199   // Get the expiry time for the timer as an absolute time.
0200   time_type expires_at(const implementation_type& impl) const
0201   {
0202     return impl.expiry;
0203   }
0204 
0205   // Get the expiry time for the timer relative to now.
0206   duration_type expires_from_now(const implementation_type& impl) const
0207   {
0208     return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());
0209   }
0210 
0211   // Set the expiry time for the timer as an absolute time.
0212   std::size_t expires_at(implementation_type& impl,
0213       const time_type& expiry_time, boost::system::error_code& ec)
0214   {
0215     std::size_t count = cancel(impl, ec);
0216     impl.expiry = expiry_time;
0217     ec = boost::system::error_code();
0218     return count;
0219   }
0220 
0221   // Set the expiry time for the timer relative to now.
0222   std::size_t expires_after(implementation_type& impl,
0223       const duration_type& expiry_time, boost::system::error_code& ec)
0224   {
0225     return expires_at(impl,
0226         Time_Traits::add(Time_Traits::now(), expiry_time), ec);
0227   }
0228 
0229   // Set the expiry time for the timer relative to now.
0230   std::size_t expires_from_now(implementation_type& impl,
0231       const duration_type& expiry_time, boost::system::error_code& ec)
0232   {
0233     return expires_at(impl,
0234         Time_Traits::add(Time_Traits::now(), expiry_time), ec);
0235   }
0236 
0237   // Perform a blocking wait on the timer.
0238   void wait(implementation_type& impl, boost::system::error_code& ec)
0239   {
0240     time_type now = Time_Traits::now();
0241     ec = boost::system::error_code();
0242     while (Time_Traits::less_than(now, impl.expiry) && !ec)
0243     {
0244       this->do_wait(Time_Traits::to_posix_duration(
0245             Time_Traits::subtract(impl.expiry, now)), ec);
0246       now = Time_Traits::now();
0247     }
0248   }
0249 
0250   // Start an asynchronous wait on the timer.
0251   template <typename Handler, typename IoExecutor>
0252   void async_wait(implementation_type& impl,
0253       Handler& handler, const IoExecutor& io_ex)
0254   {
0255     associated_cancellation_slot_t<Handler> slot
0256       = boost::asio::get_associated_cancellation_slot(handler);
0257 
0258     // Allocate and construct an operation to wrap the handler.
0259     typedef wait_handler<Handler, IoExecutor> op;
0260     typename op::ptr p = { boost::asio::detail::addressof(handler),
0261       op::ptr::allocate(handler), 0 };
0262     p.p = new (p.v) op(handler, io_ex);
0263 
0264     // Optionally register for per-operation cancellation.
0265     if (slot.is_connected())
0266     {
0267       p.p->cancellation_key_ =
0268         &slot.template emplace<op_cancellation>(this, &impl.timer_data);
0269     }
0270 
0271     impl.might_have_pending_waits = true;
0272 
0273     BOOST_ASIO_HANDLER_CREATION((scheduler_.context(),
0274           *p.p, "deadline_timer", &impl, 0, "async_wait"));
0275 
0276     scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
0277     p.v = p.p = 0;
0278   }
0279 
0280 private:
0281   // Helper function to wait given a duration type. The duration type should
0282   // either be of type boost::posix_time::time_duration, or implement the
0283   // required subset of its interface.
0284   template <typename Duration>
0285   void do_wait(const Duration& timeout, boost::system::error_code& ec)
0286   {
0287 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0288     std::this_thread::sleep_for(
0289         std::chrono::seconds(timeout.total_seconds())
0290         + std::chrono::microseconds(timeout.total_microseconds()));
0291     ec = boost::system::error_code();
0292 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
0293     ::timeval tv;
0294     tv.tv_sec = timeout.total_seconds();
0295     tv.tv_usec = timeout.total_microseconds() % 1000000;
0296     socket_ops::select(0, 0, 0, 0, &tv, ec);
0297 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
0298   }
0299 
0300   // Helper class used to implement per-operation cancellation.
0301   class op_cancellation
0302   {
0303   public:
0304     op_cancellation(deadline_timer_service* s,
0305         typename timer_queue<Time_Traits>::per_timer_data* p)
0306       : service_(s),
0307         timer_data_(p)
0308     {
0309     }
0310 
0311     void operator()(cancellation_type_t type)
0312     {
0313       if (!!(type &
0314             (cancellation_type::terminal
0315               | cancellation_type::partial
0316               | cancellation_type::total)))
0317       {
0318         service_->scheduler_.cancel_timer_by_key(
0319             service_->timer_queue_, timer_data_, this);
0320       }
0321     }
0322 
0323   private:
0324     deadline_timer_service* service_;
0325     typename timer_queue<Time_Traits>::per_timer_data* timer_data_;
0326   };
0327 
0328   // The queue of timers.
0329   timer_queue<Time_Traits> timer_queue_;
0330 
0331   // The object that schedules and executes timers. Usually a reactor.
0332   timer_scheduler& scheduler_;
0333 };
0334 
0335 } // namespace detail
0336 } // namespace asio
0337 } // namespace boost
0338 
0339 #include <boost/asio/detail/pop_options.hpp>
0340 
0341 #endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP