1//
2// basic_deadline_timer.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP
12#define BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
21 || defined(GENERATING_DOCUMENTATION)
22
23#include <cstddef>
24#include <boost/asio/any_io_executor.hpp>
25#include <boost/asio/detail/deadline_timer_service.hpp>
26#include <boost/asio/detail/handler_type_requirements.hpp>
27#include <boost/asio/detail/io_object_impl.hpp>
28#include <boost/asio/detail/non_const_lvalue.hpp>
29#include <boost/asio/detail/throw_error.hpp>
30#include <boost/asio/error.hpp>
31#include <boost/asio/execution_context.hpp>
32#include <boost/asio/time_traits.hpp>
33
34#include <boost/asio/detail/push_options.hpp>
35
36namespace boost {
37namespace asio {
38
39/// Provides waitable timer functionality.
40/**
41 * The basic_deadline_timer class template provides the ability to perform a
42 * blocking or asynchronous wait for a timer to expire.
43 *
44 * A deadline timer is always in one of two states: "expired" or "not expired".
45 * If the wait() or async_wait() function is called on an expired timer, the
46 * wait operation will complete immediately.
47 *
48 * Most applications will use the boost::asio::deadline_timer typedef.
49 *
50 * @par Thread Safety
51 * @e Distinct @e objects: Safe.@n
52 * @e Shared @e objects: Unsafe.
53 *
54 * @par Examples
55 * Performing a blocking wait:
56 * @code
57 * // Construct a timer without setting an expiry time.
58 * boost::asio::deadline_timer timer(my_context);
59 *
60 * // Set an expiry time relative to now.
61 * timer.expires_from_now(boost::posix_time::seconds(5));
62 *
63 * // Wait for the timer to expire.
64 * timer.wait();
65 * @endcode
66 *
67 * @par
68 * Performing an asynchronous wait:
69 * @code
70 * void handler(const boost::system::error_code& error)
71 * {
72 * if (!error)
73 * {
74 * // Timer expired.
75 * }
76 * }
77 *
78 * ...
79 *
80 * // Construct a timer with an absolute expiry time.
81 * boost::asio::deadline_timer timer(my_context,
82 * boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
83 *
84 * // Start an asynchronous wait.
85 * timer.async_wait(handler);
86 * @endcode
87 *
88 * @par Changing an active deadline_timer's expiry time
89 *
90 * Changing the expiry time of a timer while there are pending asynchronous
91 * waits causes those wait operations to be cancelled. To ensure that the action
92 * associated with the timer is performed only once, use something like this:
93 * used:
94 *
95 * @code
96 * void on_some_event()
97 * {
98 * if (my_timer.expires_from_now(seconds(5)) > 0)
99 * {
100 * // We managed to cancel the timer. Start new asynchronous wait.
101 * my_timer.async_wait(on_timeout);
102 * }
103 * else
104 * {
105 * // Too late, timer has already expired!
106 * }
107 * }
108 *
109 * void on_timeout(const boost::system::error_code& e)
110 * {
111 * if (e != boost::asio::error::operation_aborted)
112 * {
113 * // Timer was not cancelled, take necessary action.
114 * }
115 * }
116 * @endcode
117 *
118 * @li The boost::asio::basic_deadline_timer::expires_from_now() function
119 * cancels any pending asynchronous waits, and returns the number of
120 * asynchronous waits that were cancelled. If it returns 0 then you were too
121 * late and the wait handler has already been executed, or will soon be
122 * executed. If it returns 1 then the wait handler was successfully cancelled.
123 *
124 * @li If a wait handler is cancelled, the boost::system::error_code passed to
125 * it contains the value boost::asio::error::operation_aborted.
126 */
127template <typename Time,
128 typename TimeTraits = boost::asio::time_traits<Time>,
129 typename Executor = any_io_executor>
130class basic_deadline_timer
131{
132private:
133 class initiate_async_wait;
134
135public:
136 /// The type of the executor associated with the object.
137 typedef Executor executor_type;
138
139 /// Rebinds the timer type to another executor.
140 template <typename Executor1>
141 struct rebind_executor
142 {
143 /// The timer type when rebound to the specified executor.
144 typedef basic_deadline_timer<Time, TimeTraits, Executor1> other;
145 };
146
147 /// The time traits type.
148 typedef TimeTraits traits_type;
149
150 /// The time type.
151 typedef typename traits_type::time_type time_type;
152
153 /// The duration type.
154 typedef typename traits_type::duration_type duration_type;
155
156 /// Constructor.
157 /**
158 * This constructor creates a timer without setting an expiry time. The
159 * expires_at() or expires_from_now() functions must be called to set an
160 * expiry time before the timer can be waited on.
161 *
162 * @param ex The I/O executor that the timer will use, by default, to
163 * dispatch handlers for any asynchronous operations performed on the timer.
164 */
165 explicit basic_deadline_timer(const executor_type& ex)
166 : impl_(0, ex)
167 {
168 }
169
170 /// Constructor.
171 /**
172 * This constructor creates a timer without setting an expiry time. The
173 * expires_at() or expires_from_now() functions must be called to set an
174 * expiry time before the timer can be waited on.
175 *
176 * @param context An execution context which provides the I/O executor that
177 * the timer will use, by default, to dispatch handlers for any asynchronous
178 * operations performed on the timer.
179 */
180 template <typename ExecutionContext>
181 explicit basic_deadline_timer(ExecutionContext& context,
182 constraint_t<
183 is_convertible<ExecutionContext&, execution_context&>::value
184 > = 0)
185 : impl_(0, 0, context)
186 {
187 }
188
189 /// Constructor to set a particular expiry time as an absolute time.
190 /**
191 * This constructor creates a timer and sets the expiry time.
192 *
193 * @param ex The I/O executor that the timer will use, by default, to
194 * dispatch handlers for any asynchronous operations performed on the timer.
195 *
196 * @param expiry_time The expiry time to be used for the timer, expressed
197 * as an absolute time.
198 */
199 basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
200 : impl_(0, ex)
201 {
202 boost::system::error_code ec;
203 impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
204 boost::asio::detail::throw_error(err: ec, location: "expires_at");
205 }
206
207 /// Constructor to set a particular expiry time as an absolute time.
208 /**
209 * This constructor creates a timer and sets the expiry time.
210 *
211 * @param context An execution context which provides the I/O executor that
212 * the timer will use, by default, to dispatch handlers for any asynchronous
213 * operations performed on the timer.
214 *
215 * @param expiry_time The expiry time to be used for the timer, expressed
216 * as an absolute time.
217 */
218 template <typename ExecutionContext>
219 basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
220 constraint_t<
221 is_convertible<ExecutionContext&, execution_context&>::value
222 > = 0)
223 : impl_(0, 0, context)
224 {
225 boost::system::error_code ec;
226 impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
227 boost::asio::detail::throw_error(err: ec, location: "expires_at");
228 }
229
230 /// Constructor to set a particular expiry time relative to now.
231 /**
232 * This constructor creates a timer and sets the expiry time.
233 *
234 * @param ex The I/O executor that the timer will use, by default, to
235 * dispatch handlers for any asynchronous operations performed on the timer.
236 *
237 * @param expiry_time The expiry time to be used for the timer, relative to
238 * now.
239 */
240 basic_deadline_timer(const executor_type& ex,
241 const duration_type& expiry_time)
242 : impl_(0, ex)
243 {
244 boost::system::error_code ec;
245 impl_.get_service().expires_from_now(
246 impl_.get_implementation(), expiry_time, ec);
247 boost::asio::detail::throw_error(err: ec, location: "expires_from_now");
248 }
249
250 /// Constructor to set a particular expiry time relative to now.
251 /**
252 * This constructor creates a timer and sets the expiry time.
253 *
254 * @param context An execution context which provides the I/O executor that
255 * the timer will use, by default, to dispatch handlers for any asynchronous
256 * operations performed on the timer.
257 *
258 * @param expiry_time The expiry time to be used for the timer, relative to
259 * now.
260 */
261 template <typename ExecutionContext>
262 basic_deadline_timer(ExecutionContext& context,
263 const duration_type& expiry_time,
264 constraint_t<
265 is_convertible<ExecutionContext&, execution_context&>::value
266 > = 0)
267 : impl_(0, 0, context)
268 {
269 boost::system::error_code ec;
270 impl_.get_service().expires_from_now(
271 impl_.get_implementation(), expiry_time, ec);
272 boost::asio::detail::throw_error(err: ec, location: "expires_from_now");
273 }
274
275 /// Move-construct a basic_deadline_timer from another.
276 /**
277 * This constructor moves a timer from one object to another.
278 *
279 * @param other The other basic_deadline_timer object from which the move will
280 * occur.
281 *
282 * @note Following the move, the moved-from object is in the same state as if
283 * constructed using the @c basic_deadline_timer(const executor_type&)
284 * constructor.
285 */
286 basic_deadline_timer(basic_deadline_timer&& other)
287 : impl_(std::move(other.impl_))
288 {
289 }
290
291 /// Move-assign a basic_deadline_timer from another.
292 /**
293 * This assignment operator moves a timer from one object to another. Cancels
294 * any outstanding asynchronous operations associated with the target object.
295 *
296 * @param other The other basic_deadline_timer object from which the move will
297 * occur.
298 *
299 * @note Following the move, the moved-from object is in the same state as if
300 * constructed using the @c basic_deadline_timer(const executor_type&)
301 * constructor.
302 */
303 basic_deadline_timer& operator=(basic_deadline_timer&& other)
304 {
305 impl_ = std::move(other.impl_);
306 return *this;
307 }
308
309 /// Destroys the timer.
310 /**
311 * This function destroys the timer, cancelling any outstanding asynchronous
312 * wait operations associated with the timer as if by calling @c cancel.
313 */
314 ~basic_deadline_timer()
315 {
316 }
317
318 /// Get the executor associated with the object.
319 const executor_type& get_executor() noexcept
320 {
321 return impl_.get_executor();
322 }
323
324 /// Cancel any asynchronous operations that are waiting on the timer.
325 /**
326 * This function forces the completion of any pending asynchronous wait
327 * operations against the timer. The handler for each cancelled operation will
328 * be invoked with the boost::asio::error::operation_aborted error code.
329 *
330 * Cancelling the timer does not change the expiry time.
331 *
332 * @return The number of asynchronous operations that were cancelled.
333 *
334 * @throws boost::system::system_error Thrown on failure.
335 *
336 * @note If the timer has already expired when cancel() is called, then the
337 * handlers for asynchronous wait operations will:
338 *
339 * @li have already been invoked; or
340 *
341 * @li have been queued for invocation in the near future.
342 *
343 * These handlers can no longer be cancelled, and therefore are passed an
344 * error code that indicates the successful completion of the wait operation.
345 */
346 std::size_t cancel()
347 {
348 boost::system::error_code ec;
349 std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
350 boost::asio::detail::throw_error(err: ec, location: "cancel");
351 return s;
352 }
353
354 /// Cancel any asynchronous operations that are waiting on the timer.
355 /**
356 * This function forces the completion of any pending asynchronous wait
357 * operations against the timer. The handler for each cancelled operation will
358 * be invoked with the boost::asio::error::operation_aborted error code.
359 *
360 * Cancelling the timer does not change the expiry time.
361 *
362 * @param ec Set to indicate what error occurred, if any.
363 *
364 * @return The number of asynchronous operations that were cancelled.
365 *
366 * @note If the timer has already expired when cancel() is called, then the
367 * handlers for asynchronous wait operations will:
368 *
369 * @li have already been invoked; or
370 *
371 * @li have been queued for invocation in the near future.
372 *
373 * These handlers can no longer be cancelled, and therefore are passed an
374 * error code that indicates the successful completion of the wait operation.
375 */
376 std::size_t cancel(boost::system::error_code& ec)
377 {
378 return impl_.get_service().cancel(impl_.get_implementation(), ec);
379 }
380
381 /// Cancels one asynchronous operation that is waiting on the timer.
382 /**
383 * This function forces the completion of one pending asynchronous wait
384 * operation against the timer. Handlers are cancelled in FIFO order. The
385 * handler for the cancelled operation will be invoked with the
386 * boost::asio::error::operation_aborted error code.
387 *
388 * Cancelling the timer does not change the expiry time.
389 *
390 * @return The number of asynchronous operations that were cancelled. That is,
391 * either 0 or 1.
392 *
393 * @throws boost::system::system_error Thrown on failure.
394 *
395 * @note If the timer has already expired when cancel_one() is called, then
396 * the handlers for asynchronous wait operations will:
397 *
398 * @li have already been invoked; or
399 *
400 * @li have been queued for invocation in the near future.
401 *
402 * These handlers can no longer be cancelled, and therefore are passed an
403 * error code that indicates the successful completion of the wait operation.
404 */
405 std::size_t cancel_one()
406 {
407 boost::system::error_code ec;
408 std::size_t s = impl_.get_service().cancel_one(
409 impl_.get_implementation(), ec);
410 boost::asio::detail::throw_error(err: ec, location: "cancel_one");
411 return s;
412 }
413
414 /// Cancels one asynchronous operation that is waiting on the timer.
415 /**
416 * This function forces the completion of one pending asynchronous wait
417 * operation against the timer. Handlers are cancelled in FIFO order. The
418 * handler for the cancelled operation will be invoked with the
419 * boost::asio::error::operation_aborted error code.
420 *
421 * Cancelling the timer does not change the expiry time.
422 *
423 * @param ec Set to indicate what error occurred, if any.
424 *
425 * @return The number of asynchronous operations that were cancelled. That is,
426 * either 0 or 1.
427 *
428 * @note If the timer has already expired when cancel_one() is called, then
429 * the handlers for asynchronous wait operations will:
430 *
431 * @li have already been invoked; or
432 *
433 * @li have been queued for invocation in the near future.
434 *
435 * These handlers can no longer be cancelled, and therefore are passed an
436 * error code that indicates the successful completion of the wait operation.
437 */
438 std::size_t cancel_one(boost::system::error_code& ec)
439 {
440 return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
441 }
442
443 /// Get the timer's expiry time as an absolute time.
444 /**
445 * This function may be used to obtain the timer's current expiry time.
446 * Whether the timer has expired or not does not affect this value.
447 */
448 time_type expires_at() const
449 {
450 return impl_.get_service().expires_at(impl_.get_implementation());
451 }
452
453 /// Set the timer's expiry time as an absolute time.
454 /**
455 * This function sets the expiry time. Any pending asynchronous wait
456 * operations will be cancelled. The handler for each cancelled operation will
457 * be invoked with the boost::asio::error::operation_aborted error code.
458 *
459 * @param expiry_time The expiry time to be used for the timer.
460 *
461 * @return The number of asynchronous operations that were cancelled.
462 *
463 * @throws boost::system::system_error Thrown on failure.
464 *
465 * @note If the timer has already expired when expires_at() is called, then
466 * the handlers for asynchronous wait operations will:
467 *
468 * @li have already been invoked; or
469 *
470 * @li have been queued for invocation in the near future.
471 *
472 * These handlers can no longer be cancelled, and therefore are passed an
473 * error code that indicates the successful completion of the wait operation.
474 */
475 std::size_t expires_at(const time_type& expiry_time)
476 {
477 boost::system::error_code ec;
478 std::size_t s = impl_.get_service().expires_at(
479 impl_.get_implementation(), expiry_time, ec);
480 boost::asio::detail::throw_error(err: ec, location: "expires_at");
481 return s;
482 }
483
484 /// Set the timer's expiry time as an absolute time.
485 /**
486 * This function sets the expiry time. Any pending asynchronous wait
487 * operations will be cancelled. The handler for each cancelled operation will
488 * be invoked with the boost::asio::error::operation_aborted error code.
489 *
490 * @param expiry_time The expiry time to be used for the timer.
491 *
492 * @param ec Set to indicate what error occurred, if any.
493 *
494 * @return The number of asynchronous operations that were cancelled.
495 *
496 * @note If the timer has already expired when expires_at() is called, then
497 * the handlers for asynchronous wait operations will:
498 *
499 * @li have already been invoked; or
500 *
501 * @li have been queued for invocation in the near future.
502 *
503 * These handlers can no longer be cancelled, and therefore are passed an
504 * error code that indicates the successful completion of the wait operation.
505 */
506 std::size_t expires_at(const time_type& expiry_time,
507 boost::system::error_code& ec)
508 {
509 return impl_.get_service().expires_at(
510 impl_.get_implementation(), expiry_time, ec);
511 }
512
513 /// Get the timer's expiry time relative to now.
514 /**
515 * This function may be used to obtain the timer's current expiry time.
516 * Whether the timer has expired or not does not affect this value.
517 */
518 duration_type expires_from_now() const
519 {
520 return impl_.get_service().expires_from_now(impl_.get_implementation());
521 }
522
523 /// Set the timer's expiry time relative to now.
524 /**
525 * This function sets the expiry time. Any pending asynchronous wait
526 * operations will be cancelled. The handler for each cancelled operation will
527 * be invoked with the boost::asio::error::operation_aborted error code.
528 *
529 * @param expiry_time The expiry time to be used for the timer.
530 *
531 * @return The number of asynchronous operations that were cancelled.
532 *
533 * @throws boost::system::system_error Thrown on failure.
534 *
535 * @note If the timer has already expired when expires_from_now() is called,
536 * then the handlers for asynchronous wait operations will:
537 *
538 * @li have already been invoked; or
539 *
540 * @li have been queued for invocation in the near future.
541 *
542 * These handlers can no longer be cancelled, and therefore are passed an
543 * error code that indicates the successful completion of the wait operation.
544 */
545 std::size_t expires_from_now(const duration_type& expiry_time)
546 {
547 boost::system::error_code ec;
548 std::size_t s = impl_.get_service().expires_from_now(
549 impl_.get_implementation(), expiry_time, ec);
550 boost::asio::detail::throw_error(err: ec, location: "expires_from_now");
551 return s;
552 }
553
554 /// Set the timer's expiry time relative to now.
555 /**
556 * This function sets the expiry time. Any pending asynchronous wait
557 * operations will be cancelled. The handler for each cancelled operation will
558 * be invoked with the boost::asio::error::operation_aborted error code.
559 *
560 * @param expiry_time The expiry time to be used for the timer.
561 *
562 * @param ec Set to indicate what error occurred, if any.
563 *
564 * @return The number of asynchronous operations that were cancelled.
565 *
566 * @note If the timer has already expired when expires_from_now() is called,
567 * then the handlers for asynchronous wait operations will:
568 *
569 * @li have already been invoked; or
570 *
571 * @li have been queued for invocation in the near future.
572 *
573 * These handlers can no longer be cancelled, and therefore are passed an
574 * error code that indicates the successful completion of the wait operation.
575 */
576 std::size_t expires_from_now(const duration_type& expiry_time,
577 boost::system::error_code& ec)
578 {
579 return impl_.get_service().expires_from_now(
580 impl_.get_implementation(), expiry_time, ec);
581 }
582
583 /// Perform a blocking wait on the timer.
584 /**
585 * This function is used to wait for the timer to expire. This function
586 * blocks and does not return until the timer has expired.
587 *
588 * @throws boost::system::system_error Thrown on failure.
589 */
590 void wait()
591 {
592 boost::system::error_code ec;
593 impl_.get_service().wait(impl_.get_implementation(), ec);
594 boost::asio::detail::throw_error(err: ec, location: "wait");
595 }
596
597 /// Perform a blocking wait on the timer.
598 /**
599 * This function is used to wait for the timer to expire. This function
600 * blocks and does not return until the timer has expired.
601 *
602 * @param ec Set to indicate what error occurred, if any.
603 */
604 void wait(boost::system::error_code& ec)
605 {
606 impl_.get_service().wait(impl_.get_implementation(), ec);
607 }
608
609 /// Start an asynchronous wait on the timer.
610 /**
611 * This function may be used to initiate an asynchronous wait against the
612 * timer. It is an initiating function for an @ref asynchronous_operation,
613 * and always returns immediately.
614 *
615 * For each call to async_wait(), the completion handler will be called
616 * exactly once. The completion handler will be called when:
617 *
618 * @li The timer has expired.
619 *
620 * @li The timer was cancelled, in which case the handler is passed the error
621 * code boost::asio::error::operation_aborted.
622 *
623 * @param token The @ref completion_token that will be used to produce a
624 * completion handler, which will be called when the timer expires. Potential
625 * completion tokens include @ref use_future, @ref use_awaitable, @ref
626 * yield_context, or a function object with the correct completion signature.
627 * The function signature of the completion handler must be:
628 * @code void handler(
629 * const boost::system::error_code& error // Result of operation.
630 * ); @endcode
631 * Regardless of whether the asynchronous operation completes immediately or
632 * not, the completion handler will not be invoked from within this function.
633 * On immediate completion, invocation of the handler will be performed in a
634 * manner equivalent to using boost::asio::post().
635 *
636 * @par Completion Signature
637 * @code void(boost::system::error_code) @endcode
638 *
639 * @par Per-Operation Cancellation
640 * This asynchronous operation supports cancellation for the following
641 * boost::asio::cancellation_type values:
642 *
643 * @li @c cancellation_type::terminal
644 *
645 * @li @c cancellation_type::partial
646 *
647 * @li @c cancellation_type::total
648 */
649 template <
650 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
651 WaitToken = default_completion_token_t<executor_type>>
652 auto async_wait(
653 WaitToken&& token = default_completion_token_t<executor_type>())
654 -> decltype(
655 async_initiate<WaitToken, void (boost::system::error_code)>(
656 declval<initiate_async_wait>(), token))
657 {
658 return async_initiate<WaitToken, void (boost::system::error_code)>(
659 initiate_async_wait(this), token);
660 }
661
662private:
663 // Disallow copying and assignment.
664 basic_deadline_timer(const basic_deadline_timer&) = delete;
665 basic_deadline_timer& operator=(
666 const basic_deadline_timer&) = delete;
667
668 class initiate_async_wait
669 {
670 public:
671 typedef Executor executor_type;
672
673 explicit initiate_async_wait(basic_deadline_timer* self)
674 : self_(self)
675 {
676 }
677
678 const executor_type& get_executor() const noexcept
679 {
680 return self_->get_executor();
681 }
682
683 template <typename WaitHandler>
684 void operator()(WaitHandler&& handler) const
685 {
686 // If you get an error on the following line it means that your handler
687 // does not meet the documented type requirements for a WaitHandler.
688 BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
689
690 detail::non_const_lvalue<WaitHandler> handler2(handler);
691 self_->impl_.get_service().async_wait(
692 self_->impl_.get_implementation(),
693 handler2.value, self_->impl_.get_executor());
694 }
695
696 private:
697 basic_deadline_timer* self_;
698 };
699
700 detail::io_object_impl<
701 detail::deadline_timer_service<TimeTraits>, Executor> impl_;
702};
703
704} // namespace asio
705} // namespace boost
706
707#include <boost/asio/detail/pop_options.hpp>
708
709#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
710 // || defined(GENERATING_DOCUMENTATION)
711
712#endif // BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP
713

source code of boost/libs/asio/include/boost/asio/basic_deadline_timer.hpp