Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:29:55

0001 //
0002 // basic_waitable_timer.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 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_BASIC_WAITABLE_TIMER_HPP
0012 #define BOOST_ASIO_BASIC_WAITABLE_TIMER_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 <utility>
0021 #include <boost/asio/any_io_executor.hpp>
0022 #include <boost/asio/detail/chrono_time_traits.hpp>
0023 #include <boost/asio/detail/deadline_timer_service.hpp>
0024 #include <boost/asio/detail/handler_type_requirements.hpp>
0025 #include <boost/asio/detail/io_object_impl.hpp>
0026 #include <boost/asio/detail/non_const_lvalue.hpp>
0027 #include <boost/asio/detail/throw_error.hpp>
0028 #include <boost/asio/error.hpp>
0029 #include <boost/asio/wait_traits.hpp>
0030 
0031 #include <boost/asio/detail/push_options.hpp>
0032 
0033 namespace boost {
0034 namespace asio {
0035 
0036 #if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
0037 #define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL
0038 
0039 // Forward declaration with defaulted arguments.
0040 template <typename Clock,
0041     typename WaitTraits = boost::asio::wait_traits<Clock>,
0042     typename Executor = any_io_executor>
0043 class basic_waitable_timer;
0044 
0045 #endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
0046 
0047 /// Provides waitable timer functionality.
0048 /**
0049  * The basic_waitable_timer class template provides the ability to perform a
0050  * blocking or asynchronous wait for a timer to expire.
0051  *
0052  * A waitable timer is always in one of two states: "expired" or "not expired".
0053  * If the wait() or async_wait() function is called on an expired timer, the
0054  * wait operation will complete immediately.
0055  *
0056  * Most applications will use one of the boost::asio::steady_timer,
0057  * boost::asio::system_timer or boost::asio::high_resolution_timer typedefs.
0058  *
0059  * @note This waitable timer functionality is for use with the C++11 standard
0060  * library's @c &lt;chrono&gt; facility, or with the Boost.Chrono library.
0061  *
0062  * @par Thread Safety
0063  * @e Distinct @e objects: Safe.@n
0064  * @e Shared @e objects: Unsafe.
0065  *
0066  * @par Examples
0067  * Performing a blocking wait (C++11):
0068  * @code
0069  * // Construct a timer without setting an expiry time.
0070  * boost::asio::steady_timer timer(my_context);
0071  *
0072  * // Set an expiry time relative to now.
0073  * timer.expires_after(std::chrono::seconds(5));
0074  *
0075  * // Wait for the timer to expire.
0076  * timer.wait();
0077  * @endcode
0078  *
0079  * @par
0080  * Performing an asynchronous wait (C++11):
0081  * @code
0082  * void handler(const boost::system::error_code& error)
0083  * {
0084  *   if (!error)
0085  *   {
0086  *     // Timer expired.
0087  *   }
0088  * }
0089  *
0090  * ...
0091  *
0092  * // Construct a timer with an absolute expiry time.
0093  * boost::asio::steady_timer timer(my_context,
0094  *     std::chrono::steady_clock::now() + std::chrono::seconds(60));
0095  *
0096  * // Start an asynchronous wait.
0097  * timer.async_wait(handler);
0098  * @endcode
0099  *
0100  * @par Changing an active waitable timer's expiry time
0101  *
0102  * Changing the expiry time of a timer while there are pending asynchronous
0103  * waits causes those wait operations to be cancelled. To ensure that the action
0104  * associated with the timer is performed only once, use something like this:
0105  * used:
0106  *
0107  * @code
0108  * void on_some_event()
0109  * {
0110  *   if (my_timer.expires_after(seconds(5)) > 0)
0111  *   {
0112  *     // We managed to cancel the timer. Start new asynchronous wait.
0113  *     my_timer.async_wait(on_timeout);
0114  *   }
0115  *   else
0116  *   {
0117  *     // Too late, timer has already expired!
0118  *   }
0119  * }
0120  *
0121  * void on_timeout(const boost::system::error_code& e)
0122  * {
0123  *   if (e != boost::asio::error::operation_aborted)
0124  *   {
0125  *     // Timer was not cancelled, take necessary action.
0126  *   }
0127  * }
0128  * @endcode
0129  *
0130  * @li The boost::asio::basic_waitable_timer::expires_after() function
0131  * cancels any pending asynchronous waits, and returns the number of
0132  * asynchronous waits that were cancelled. If it returns 0 then you were too
0133  * late and the wait handler has already been executed, or will soon be
0134  * executed. If it returns 1 then the wait handler was successfully cancelled.
0135  *
0136  * @li If a wait handler is cancelled, the boost::system::error_code passed to
0137  * it contains the value boost::asio::error::operation_aborted.
0138  */
0139 template <typename Clock, typename WaitTraits, typename Executor>
0140 class basic_waitable_timer
0141 {
0142 private:
0143   class initiate_async_wait;
0144 
0145 public:
0146   /// The type of the executor associated with the object.
0147   typedef Executor executor_type;
0148 
0149   /// Rebinds the timer type to another executor.
0150   template <typename Executor1>
0151   struct rebind_executor
0152   {
0153     /// The timer type when rebound to the specified executor.
0154     typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other;
0155   };
0156 
0157   /// The clock type.
0158   typedef Clock clock_type;
0159 
0160   /// The duration type of the clock.
0161   typedef typename clock_type::duration duration;
0162 
0163   /// The time point type of the clock.
0164   typedef typename clock_type::time_point time_point;
0165 
0166   /// The wait traits type.
0167   typedef WaitTraits traits_type;
0168 
0169   /// Constructor.
0170   /**
0171    * This constructor creates a timer without setting an expiry time. The
0172    * expires_at() or expires_after() functions must be called to set an expiry
0173    * time before the timer can be waited on.
0174    *
0175    * @param ex The I/O executor that the timer will use, by default, to
0176    * dispatch handlers for any asynchronous operations performed on the timer.
0177    */
0178   explicit basic_waitable_timer(const executor_type& ex)
0179     : impl_(0, ex)
0180   {
0181   }
0182 
0183   /// Constructor.
0184   /**
0185    * This constructor creates a timer without setting an expiry time. The
0186    * expires_at() or expires_after() functions must be called to set an expiry
0187    * time before the timer can be waited on.
0188    *
0189    * @param context An execution context which provides the I/O executor that
0190    * the timer will use, by default, to dispatch handlers for any asynchronous
0191    * operations performed on the timer.
0192    */
0193   template <typename ExecutionContext>
0194   explicit basic_waitable_timer(ExecutionContext& context,
0195       constraint_t<
0196         is_convertible<ExecutionContext&, execution_context&>::value
0197       > = 0)
0198     : impl_(0, 0, context)
0199   {
0200   }
0201 
0202   /// Constructor to set a particular expiry time as an absolute time.
0203   /**
0204    * This constructor creates a timer and sets the expiry time.
0205    *
0206    * @param ex The I/O executor object that the timer will use, by default, to
0207    * dispatch handlers for any asynchronous operations performed on the timer.
0208    *
0209    * @param expiry_time The expiry time to be used for the timer, expressed
0210    * as an absolute time.
0211    */
0212   basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
0213     : impl_(0, ex)
0214   {
0215     boost::system::error_code ec;
0216     impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
0217     boost::asio::detail::throw_error(ec, "expires_at");
0218   }
0219 
0220   /// Constructor to set a particular expiry time as an absolute time.
0221   /**
0222    * This constructor creates a timer and sets the expiry time.
0223    *
0224    * @param context An execution context which provides the I/O executor that
0225    * the timer will use, by default, to dispatch handlers for any asynchronous
0226    * operations performed on the timer.
0227    *
0228    * @param expiry_time The expiry time to be used for the timer, expressed
0229    * as an absolute time.
0230    */
0231   template <typename ExecutionContext>
0232   explicit basic_waitable_timer(ExecutionContext& context,
0233       const time_point& expiry_time,
0234       constraint_t<
0235         is_convertible<ExecutionContext&, execution_context&>::value
0236       > = 0)
0237     : impl_(0, 0, context)
0238   {
0239     boost::system::error_code ec;
0240     impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
0241     boost::asio::detail::throw_error(ec, "expires_at");
0242   }
0243 
0244   /// Constructor to set a particular expiry time relative to now.
0245   /**
0246    * This constructor creates a timer and sets the expiry time.
0247    *
0248    * @param ex The I/O executor that the timer will use, by default, to
0249    * dispatch handlers for any asynchronous operations performed on the timer.
0250    *
0251    * @param expiry_time The expiry time to be used for the timer, relative to
0252    * now.
0253    */
0254   basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
0255     : impl_(0, ex)
0256   {
0257     boost::system::error_code ec;
0258     impl_.get_service().expires_after(
0259         impl_.get_implementation(), expiry_time, ec);
0260     boost::asio::detail::throw_error(ec, "expires_after");
0261   }
0262 
0263   /// Constructor to set a particular expiry time relative to now.
0264   /**
0265    * This constructor creates a timer and sets the expiry time.
0266    *
0267    * @param context An execution context which provides the I/O executor that
0268    * the timer will use, by default, to dispatch handlers for any asynchronous
0269    * operations performed on the timer.
0270    *
0271    * @param expiry_time The expiry time to be used for the timer, relative to
0272    * now.
0273    */
0274   template <typename ExecutionContext>
0275   explicit basic_waitable_timer(ExecutionContext& context,
0276       const duration& expiry_time,
0277       constraint_t<
0278         is_convertible<ExecutionContext&, execution_context&>::value
0279       > = 0)
0280     : impl_(0, 0, context)
0281   {
0282     boost::system::error_code ec;
0283     impl_.get_service().expires_after(
0284         impl_.get_implementation(), expiry_time, ec);
0285     boost::asio::detail::throw_error(ec, "expires_after");
0286   }
0287 
0288   /// Move-construct a basic_waitable_timer from another.
0289   /**
0290    * This constructor moves a timer from one object to another.
0291    *
0292    * @param other The other basic_waitable_timer object from which the move will
0293    * occur.
0294    *
0295    * @note Following the move, the moved-from object is in the same state as if
0296    * constructed using the @c basic_waitable_timer(const executor_type&)
0297    * constructor.
0298    */
0299   basic_waitable_timer(basic_waitable_timer&& other)
0300     : impl_(std::move(other.impl_))
0301   {
0302   }
0303 
0304   /// Move-assign a basic_waitable_timer from another.
0305   /**
0306    * This assignment operator moves a timer from one object to another. Cancels
0307    * any outstanding asynchronous operations associated with the target object.
0308    *
0309    * @param other The other basic_waitable_timer object from which the move will
0310    * occur.
0311    *
0312    * @note Following the move, the moved-from object is in the same state as if
0313    * constructed using the @c basic_waitable_timer(const executor_type&)
0314    * constructor.
0315    */
0316   basic_waitable_timer& operator=(basic_waitable_timer&& other)
0317   {
0318     impl_ = std::move(other.impl_);
0319     return *this;
0320   }
0321 
0322   // All timers have access to each other's implementations.
0323   template <typename Clock1, typename WaitTraits1, typename Executor1>
0324   friend class basic_waitable_timer;
0325 
0326   /// Move-construct a basic_waitable_timer from another.
0327   /**
0328    * This constructor moves a timer from one object to another.
0329    *
0330    * @param other The other basic_waitable_timer object from which the move will
0331    * occur.
0332    *
0333    * @note Following the move, the moved-from object is in the same state as if
0334    * constructed using the @c basic_waitable_timer(const executor_type&)
0335    * constructor.
0336    */
0337   template <typename Executor1>
0338   basic_waitable_timer(
0339       basic_waitable_timer<Clock, WaitTraits, Executor1>&& other,
0340       constraint_t<
0341         is_convertible<Executor1, Executor>::value
0342       > = 0)
0343     : impl_(std::move(other.impl_))
0344   {
0345   }
0346 
0347   /// Move-assign a basic_waitable_timer from another.
0348   /**
0349    * This assignment operator moves a timer from one object to another. Cancels
0350    * any outstanding asynchronous operations associated with the target object.
0351    *
0352    * @param other The other basic_waitable_timer object from which the move will
0353    * occur.
0354    *
0355    * @note Following the move, the moved-from object is in the same state as if
0356    * constructed using the @c basic_waitable_timer(const executor_type&)
0357    * constructor.
0358    */
0359   template <typename Executor1>
0360   constraint_t<
0361     is_convertible<Executor1, Executor>::value,
0362     basic_waitable_timer&
0363   > operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)
0364   {
0365     basic_waitable_timer tmp(std::move(other));
0366     impl_ = std::move(tmp.impl_);
0367     return *this;
0368   }
0369 
0370   /// Destroys the timer.
0371   /**
0372    * This function destroys the timer, cancelling any outstanding asynchronous
0373    * wait operations associated with the timer as if by calling @c cancel.
0374    */
0375   ~basic_waitable_timer()
0376   {
0377   }
0378 
0379   /// Get the executor associated with the object.
0380   const executor_type& get_executor() noexcept
0381   {
0382     return impl_.get_executor();
0383   }
0384 
0385   /// Cancel any asynchronous operations that are waiting on the timer.
0386   /**
0387    * This function forces the completion of any pending asynchronous wait
0388    * operations against the timer. The handler for each cancelled operation will
0389    * be invoked with the boost::asio::error::operation_aborted error code.
0390    *
0391    * Cancelling the timer does not change the expiry time.
0392    *
0393    * @return The number of asynchronous operations that were cancelled.
0394    *
0395    * @throws boost::system::system_error Thrown on failure.
0396    *
0397    * @note If the timer has already expired when cancel() is called, then the
0398    * handlers for asynchronous wait operations will:
0399    *
0400    * @li have already been invoked; or
0401    *
0402    * @li have been queued for invocation in the near future.
0403    *
0404    * These handlers can no longer be cancelled, and therefore are passed an
0405    * error code that indicates the successful completion of the wait operation.
0406    */
0407   std::size_t cancel()
0408   {
0409     boost::system::error_code ec;
0410     std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
0411     boost::asio::detail::throw_error(ec, "cancel");
0412     return s;
0413   }
0414 
0415   /// Cancels one asynchronous operation that is waiting on the timer.
0416   /**
0417    * This function forces the completion of one pending asynchronous wait
0418    * operation against the timer. Handlers are cancelled in FIFO order. The
0419    * handler for the cancelled operation will be invoked with the
0420    * boost::asio::error::operation_aborted error code.
0421    *
0422    * Cancelling the timer does not change the expiry time.
0423    *
0424    * @return The number of asynchronous operations that were cancelled. That is,
0425    * either 0 or 1.
0426    *
0427    * @throws boost::system::system_error Thrown on failure.
0428    *
0429    * @note If the timer has already expired when cancel_one() is called, then
0430    * the handlers for asynchronous wait operations will:
0431    *
0432    * @li have already been invoked; or
0433    *
0434    * @li have been queued for invocation in the near future.
0435    *
0436    * These handlers can no longer be cancelled, and therefore are passed an
0437    * error code that indicates the successful completion of the wait operation.
0438    */
0439   std::size_t cancel_one()
0440   {
0441     boost::system::error_code ec;
0442     std::size_t s = impl_.get_service().cancel_one(
0443         impl_.get_implementation(), ec);
0444     boost::asio::detail::throw_error(ec, "cancel_one");
0445     return s;
0446   }
0447 
0448   /// Get the timer's expiry time as an absolute time.
0449   /**
0450    * This function may be used to obtain the timer's current expiry time.
0451    * Whether the timer has expired or not does not affect this value.
0452    */
0453   time_point expiry() const
0454   {
0455     return impl_.get_service().expiry(impl_.get_implementation());
0456   }
0457 
0458   /// Set the timer's expiry time as an absolute time.
0459   /**
0460    * This function sets the expiry time. Any pending asynchronous wait
0461    * operations will be cancelled. The handler for each cancelled operation will
0462    * be invoked with the boost::asio::error::operation_aborted error code.
0463    *
0464    * @param expiry_time The expiry time to be used for the timer.
0465    *
0466    * @return The number of asynchronous operations that were cancelled.
0467    *
0468    * @throws boost::system::system_error Thrown on failure.
0469    *
0470    * @note If the timer has already expired when expires_at() is called, then
0471    * the handlers for asynchronous wait operations will:
0472    *
0473    * @li have already been invoked; or
0474    *
0475    * @li have been queued for invocation in the near future.
0476    *
0477    * These handlers can no longer be cancelled, and therefore are passed an
0478    * error code that indicates the successful completion of the wait operation.
0479    */
0480   std::size_t expires_at(const time_point& expiry_time)
0481   {
0482     boost::system::error_code ec;
0483     std::size_t s = impl_.get_service().expires_at(
0484         impl_.get_implementation(), expiry_time, ec);
0485     boost::asio::detail::throw_error(ec, "expires_at");
0486     return s;
0487   }
0488 
0489   /// Set the timer's expiry time relative to now.
0490   /**
0491    * This function sets the expiry time. Any pending asynchronous wait
0492    * operations will be cancelled. The handler for each cancelled operation will
0493    * be invoked with the boost::asio::error::operation_aborted error code.
0494    *
0495    * @param expiry_time The expiry time to be used for the timer.
0496    *
0497    * @return The number of asynchronous operations that were cancelled.
0498    *
0499    * @throws boost::system::system_error Thrown on failure.
0500    *
0501    * @note If the timer has already expired when expires_after() is called,
0502    * then the handlers for asynchronous wait operations will:
0503    *
0504    * @li have already been invoked; or
0505    *
0506    * @li have been queued for invocation in the near future.
0507    *
0508    * These handlers can no longer be cancelled, and therefore are passed an
0509    * error code that indicates the successful completion of the wait operation.
0510    */
0511   std::size_t expires_after(const duration& expiry_time)
0512   {
0513     boost::system::error_code ec;
0514     std::size_t s = impl_.get_service().expires_after(
0515         impl_.get_implementation(), expiry_time, ec);
0516     boost::asio::detail::throw_error(ec, "expires_after");
0517     return s;
0518   }
0519 
0520   /// Perform a blocking wait on the timer.
0521   /**
0522    * This function is used to wait for the timer to expire. This function
0523    * blocks and does not return until the timer has expired.
0524    *
0525    * @throws boost::system::system_error Thrown on failure.
0526    */
0527   void wait()
0528   {
0529     boost::system::error_code ec;
0530     impl_.get_service().wait(impl_.get_implementation(), ec);
0531     boost::asio::detail::throw_error(ec, "wait");
0532   }
0533 
0534   /// Perform a blocking wait on the timer.
0535   /**
0536    * This function is used to wait for the timer to expire. This function
0537    * blocks and does not return until the timer has expired.
0538    *
0539    * @param ec Set to indicate what error occurred, if any.
0540    */
0541   void wait(boost::system::error_code& ec)
0542   {
0543     impl_.get_service().wait(impl_.get_implementation(), ec);
0544   }
0545 
0546   /// Start an asynchronous wait on the timer.
0547   /**
0548    * This function may be used to initiate an asynchronous wait against the
0549    * timer. It is an initiating function for an @ref asynchronous_operation,
0550    * and always returns immediately.
0551    *
0552    * For each call to async_wait(), the completion handler will be called
0553    * exactly once. The completion handler will be called when:
0554    *
0555    * @li The timer has expired.
0556    *
0557    * @li The timer was cancelled, in which case the handler is passed the error
0558    * code boost::asio::error::operation_aborted.
0559    *
0560    * @param token The @ref completion_token that will be used to produce a
0561    * completion handler, which will be called when the timer expires. Potential
0562    * completion tokens include @ref use_future, @ref use_awaitable, @ref
0563    * yield_context, or a function object with the correct completion signature.
0564    * The function signature of the completion handler must be:
0565    * @code void handler(
0566    *   const boost::system::error_code& error // Result of operation.
0567    * ); @endcode
0568    * Regardless of whether the asynchronous operation completes immediately or
0569    * not, the completion handler will not be invoked from within this function.
0570    * On immediate completion, invocation of the handler will be performed in a
0571    * manner equivalent to using boost::asio::async_immediate().
0572    *
0573    * @par Completion Signature
0574    * @code void(boost::system::error_code) @endcode
0575    *
0576    * @par Per-Operation Cancellation
0577    * This asynchronous operation supports cancellation for the following
0578    * boost::asio::cancellation_type values:
0579    *
0580    * @li @c cancellation_type::terminal
0581    *
0582    * @li @c cancellation_type::partial
0583    *
0584    * @li @c cancellation_type::total
0585    */
0586   template <
0587       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
0588         WaitToken = default_completion_token_t<executor_type>>
0589   auto async_wait(
0590       WaitToken&& token = default_completion_token_t<executor_type>())
0591     -> decltype(
0592       async_initiate<WaitToken, void (boost::system::error_code)>(
0593         declval<initiate_async_wait>(), token))
0594   {
0595     return async_initiate<WaitToken, void (boost::system::error_code)>(
0596         initiate_async_wait(this), token);
0597   }
0598 
0599 private:
0600   // Disallow copying and assignment.
0601   basic_waitable_timer(const basic_waitable_timer&) = delete;
0602   basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
0603 
0604   class initiate_async_wait
0605   {
0606   public:
0607     typedef Executor executor_type;
0608 
0609     explicit initiate_async_wait(basic_waitable_timer* self)
0610       : self_(self)
0611     {
0612     }
0613 
0614     const executor_type& get_executor() const noexcept
0615     {
0616       return self_->get_executor();
0617     }
0618 
0619     template <typename WaitHandler>
0620     void operator()(WaitHandler&& handler) const
0621     {
0622       // If you get an error on the following line it means that your handler
0623       // does not meet the documented type requirements for a WaitHandler.
0624       BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
0625 
0626       detail::non_const_lvalue<WaitHandler> handler2(handler);
0627       self_->impl_.get_service().async_wait(
0628           self_->impl_.get_implementation(),
0629           handler2.value, self_->impl_.get_executor());
0630     }
0631 
0632   private:
0633     basic_waitable_timer* self_;
0634   };
0635 
0636   detail::io_object_impl<
0637     detail::deadline_timer_service<
0638       detail::chrono_time_traits<Clock, WaitTraits>>,
0639     executor_type > impl_;
0640 };
0641 
0642 } // namespace asio
0643 } // namespace boost
0644 
0645 #include <boost/asio/detail/pop_options.hpp>
0646 
0647 #endif // BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP