1 // 2 // basic_waitable_timer.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2015 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_WAITABLE_TIMER_HPP 12 #define BOOST_ASIO_BASIC_WAITABLE_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 #include <cstddef> 20 #include <boost/asio/basic_io_object.hpp> 21 #include <boost/asio/detail/handler_type_requirements.hpp> 22 #include <boost/asio/detail/throw_error.hpp> 23 #include <boost/asio/error.hpp> 24 #include <boost/asio/wait_traits.hpp> 25 #include <boost/asio/waitable_timer_service.hpp> 26 27 #include <boost/asio/detail/push_options.hpp> 28 29 namespace boost { 30 namespace asio { 31 32 /// Provides waitable timer functionality. 33 /** 34 * The basic_waitable_timer class template provides the ability to perform a 35 * blocking or asynchronous wait for a timer to expire. 36 * 37 * A waitable timer is always in one of two states: "expired" or "not expired". 38 * If the wait() or async_wait() function is called on an expired timer, the 39 * wait operation will complete immediately. 40 * 41 * Most applications will use one of the boost::asio::steady_timer, 42 * boost::asio::system_timer or boost::asio::high_resolution_timer typedefs. 43 * 44 * @note This waitable timer functionality is for use with the C++11 standard 45 * library's @c <chrono> facility, or with the Boost.Chrono library. 46 * 47 * @par Thread Safety 48 * @e Distinct @e objects: Safe.@n 49 * @e Shared @e objects: Unsafe. 50 * 51 * @par Examples 52 * Performing a blocking wait (C++11): 53 * @code 54 * // Construct a timer without setting an expiry time. 55 * boost::asio::steady_timer timer(io_service); 56 * 57 * // Set an expiry time relative to now. 58 * timer.expires_from_now(std::chrono::seconds(5)); 59 * 60 * // Wait for the timer to expire. 61 * timer.wait(); 62 * @endcode 63 * 64 * @par 65 * Performing an asynchronous wait (C++11): 66 * @code 67 * void handler(const boost::system::error_code& error) 68 * { 69 * if (!error) 70 * { 71 * // Timer expired. 72 * } 73 * } 74 * 75 * ... 76 * 77 * // Construct a timer with an absolute expiry time. 78 * boost::asio::steady_timer timer(io_service, 79 * std::chrono::steady_clock::now() + std::chrono::seconds(60)); 80 * 81 * // Start an asynchronous wait. 82 * timer.async_wait(handler); 83 * @endcode 84 * 85 * @par Changing an active waitable timer's expiry time 86 * 87 * Changing the expiry time of a timer while there are pending asynchronous 88 * waits causes those wait operations to be cancelled. To ensure that the action 89 * associated with the timer is performed only once, use something like this: 90 * used: 91 * 92 * @code 93 * void on_some_event() 94 * { 95 * if (my_timer.expires_from_now(seconds(5)) > 0) 96 * { 97 * // We managed to cancel the timer. Start new asynchronous wait. 98 * my_timer.async_wait(on_timeout); 99 * } 100 * else 101 * { 102 * // Too late, timer has already expired! 103 * } 104 * } 105 * 106 * void on_timeout(const boost::system::error_code& e) 107 * { 108 * if (e != boost::asio::error::operation_aborted) 109 * { 110 * // Timer was not cancelled, take necessary action. 111 * } 112 * } 113 * @endcode 114 * 115 * @li The boost::asio::basic_waitable_timer::expires_from_now() function 116 * cancels any pending asynchronous waits, and returns the number of 117 * asynchronous waits that were cancelled. If it returns 0 then you were too 118 * late and the wait handler has already been executed, or will soon be 119 * executed. If it returns 1 then the wait handler was successfully cancelled. 120 * 121 * @li If a wait handler is cancelled, the boost::system::error_code passed to 122 * it contains the value boost::asio::error::operation_aborted. 123 */ 124 template <typename Clock, 125 typename WaitTraits = boost::asio::wait_traits<Clock>, 126 typename WaitableTimerService = waitable_timer_service<Clock, WaitTraits> > 127 class basic_waitable_timer 128 : public basic_io_object<WaitableTimerService> 129 { 130 public: 131 /// The clock type. 132 typedef Clock clock_type; 133 134 /// The duration type of the clock. 135 typedef typename clock_type::duration duration; 136 137 /// The time point type of the clock. 138 typedef typename clock_type::time_point time_point; 139 140 /// The wait traits type. 141 typedef WaitTraits traits_type; 142 143 /// Constructor. 144 /** 145 * This constructor creates a timer without setting an expiry time. The 146 * expires_at() or expires_from_now() functions must be called to set an 147 * expiry time before the timer can be waited on. 148 * 149 * @param io_service The io_service object that the timer will use to dispatch 150 * handlers for any asynchronous operations performed on the timer. 151 */ basic_waitable_timer(boost::asio::io_service & io_service)152 explicit basic_waitable_timer(boost::asio::io_service& io_service) 153 : basic_io_object<WaitableTimerService>(io_service) 154 { 155 } 156 157 /// Constructor to set a particular expiry time as an absolute time. 158 /** 159 * This constructor creates a timer and sets the expiry time. 160 * 161 * @param io_service The io_service object that the timer will use to dispatch 162 * handlers for any asynchronous operations performed on the timer. 163 * 164 * @param expiry_time The expiry time to be used for the timer, expressed 165 * as an absolute time. 166 */ basic_waitable_timer(boost::asio::io_service & io_service,const time_point & expiry_time)167 basic_waitable_timer(boost::asio::io_service& io_service, 168 const time_point& expiry_time) 169 : basic_io_object<WaitableTimerService>(io_service) 170 { 171 boost::system::error_code ec; 172 this->service.expires_at(this->implementation, expiry_time, ec); 173 boost::asio::detail::throw_error(ec, "expires_at"); 174 } 175 176 /// Constructor to set a particular expiry time relative to now. 177 /** 178 * This constructor creates a timer and sets the expiry time. 179 * 180 * @param io_service The io_service object that the timer will use to dispatch 181 * handlers for any asynchronous operations performed on the timer. 182 * 183 * @param expiry_time The expiry time to be used for the timer, relative to 184 * now. 185 */ basic_waitable_timer(boost::asio::io_service & io_service,const duration & expiry_time)186 basic_waitable_timer(boost::asio::io_service& io_service, 187 const duration& expiry_time) 188 : basic_io_object<WaitableTimerService>(io_service) 189 { 190 boost::system::error_code ec; 191 this->service.expires_from_now(this->implementation, expiry_time, ec); 192 boost::asio::detail::throw_error(ec, "expires_from_now"); 193 } 194 195 /// Cancel any asynchronous operations that are waiting on the timer. 196 /** 197 * This function forces the completion of any pending asynchronous wait 198 * operations against the timer. The handler for each cancelled operation will 199 * be invoked with the boost::asio::error::operation_aborted error code. 200 * 201 * Cancelling the timer does not change the expiry time. 202 * 203 * @return The number of asynchronous operations that were cancelled. 204 * 205 * @throws boost::system::system_error Thrown on failure. 206 * 207 * @note If the timer has already expired when cancel() is called, then the 208 * handlers for asynchronous wait operations will: 209 * 210 * @li have already been invoked; or 211 * 212 * @li have been queued for invocation in the near future. 213 * 214 * These handlers can no longer be cancelled, and therefore are passed an 215 * error code that indicates the successful completion of the wait operation. 216 */ cancel()217 std::size_t cancel() 218 { 219 boost::system::error_code ec; 220 std::size_t s = this->service.cancel(this->implementation, ec); 221 boost::asio::detail::throw_error(ec, "cancel"); 222 return s; 223 } 224 225 /// Cancel any asynchronous operations that are waiting on the timer. 226 /** 227 * This function forces the completion of any pending asynchronous wait 228 * operations against the timer. The handler for each cancelled operation will 229 * be invoked with the boost::asio::error::operation_aborted error code. 230 * 231 * Cancelling the timer does not change the expiry time. 232 * 233 * @param ec Set to indicate what error occurred, if any. 234 * 235 * @return The number of asynchronous operations that were cancelled. 236 * 237 * @note If the timer has already expired when cancel() is called, then the 238 * handlers for asynchronous wait operations will: 239 * 240 * @li have already been invoked; or 241 * 242 * @li have been queued for invocation in the near future. 243 * 244 * These handlers can no longer be cancelled, and therefore are passed an 245 * error code that indicates the successful completion of the wait operation. 246 */ cancel(boost::system::error_code & ec)247 std::size_t cancel(boost::system::error_code& ec) 248 { 249 return this->service.cancel(this->implementation, ec); 250 } 251 252 /// Cancels one asynchronous operation that is waiting on the timer. 253 /** 254 * This function forces the completion of one pending asynchronous wait 255 * operation against the timer. Handlers are cancelled in FIFO order. The 256 * handler for the cancelled operation will be invoked with the 257 * boost::asio::error::operation_aborted error code. 258 * 259 * Cancelling the timer does not change the expiry time. 260 * 261 * @return The number of asynchronous operations that were cancelled. That is, 262 * either 0 or 1. 263 * 264 * @throws boost::system::system_error Thrown on failure. 265 * 266 * @note If the timer has already expired when cancel_one() is called, then 267 * the handlers for asynchronous wait operations will: 268 * 269 * @li have already been invoked; or 270 * 271 * @li have been queued for invocation in the near future. 272 * 273 * These handlers can no longer be cancelled, and therefore are passed an 274 * error code that indicates the successful completion of the wait operation. 275 */ cancel_one()276 std::size_t cancel_one() 277 { 278 boost::system::error_code ec; 279 std::size_t s = this->service.cancel_one(this->implementation, ec); 280 boost::asio::detail::throw_error(ec, "cancel_one"); 281 return s; 282 } 283 284 /// Cancels one asynchronous operation that is waiting on the timer. 285 /** 286 * This function forces the completion of one pending asynchronous wait 287 * operation against the timer. Handlers are cancelled in FIFO order. The 288 * handler for the cancelled operation will be invoked with the 289 * boost::asio::error::operation_aborted error code. 290 * 291 * Cancelling the timer does not change the expiry time. 292 * 293 * @param ec Set to indicate what error occurred, if any. 294 * 295 * @return The number of asynchronous operations that were cancelled. That is, 296 * either 0 or 1. 297 * 298 * @note If the timer has already expired when cancel_one() is called, then 299 * the handlers for asynchronous wait operations will: 300 * 301 * @li have already been invoked; or 302 * 303 * @li have been queued for invocation in the near future. 304 * 305 * These handlers can no longer be cancelled, and therefore are passed an 306 * error code that indicates the successful completion of the wait operation. 307 */ cancel_one(boost::system::error_code & ec)308 std::size_t cancel_one(boost::system::error_code& ec) 309 { 310 return this->service.cancel_one(this->implementation, ec); 311 } 312 313 /// Get the timer's expiry time as an absolute time. 314 /** 315 * This function may be used to obtain the timer's current expiry time. 316 * Whether the timer has expired or not does not affect this value. 317 */ expires_at() const318 time_point expires_at() const 319 { 320 return this->service.expires_at(this->implementation); 321 } 322 323 /// Set the timer's expiry time as an absolute time. 324 /** 325 * This function sets the expiry time. Any pending asynchronous wait 326 * operations will be cancelled. The handler for each cancelled operation will 327 * be invoked with the boost::asio::error::operation_aborted error code. 328 * 329 * @param expiry_time The expiry time to be used for the timer. 330 * 331 * @return The number of asynchronous operations that were cancelled. 332 * 333 * @throws boost::system::system_error Thrown on failure. 334 * 335 * @note If the timer has already expired when expires_at() is called, then 336 * the handlers for asynchronous wait operations will: 337 * 338 * @li have already been invoked; or 339 * 340 * @li have been queued for invocation in the near future. 341 * 342 * These handlers can no longer be cancelled, and therefore are passed an 343 * error code that indicates the successful completion of the wait operation. 344 */ expires_at(const time_point & expiry_time)345 std::size_t expires_at(const time_point& expiry_time) 346 { 347 boost::system::error_code ec; 348 std::size_t s = this->service.expires_at( 349 this->implementation, expiry_time, ec); 350 boost::asio::detail::throw_error(ec, "expires_at"); 351 return s; 352 } 353 354 /// Set the timer's expiry time as an absolute time. 355 /** 356 * This function sets the expiry time. Any pending asynchronous wait 357 * operations will be cancelled. The handler for each cancelled operation will 358 * be invoked with the boost::asio::error::operation_aborted error code. 359 * 360 * @param expiry_time The expiry time to be used for the timer. 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 expires_at() is called, then 367 * the 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 */ expires_at(const time_point & expiry_time,boost::system::error_code & ec)376 std::size_t expires_at(const time_point& expiry_time, 377 boost::system::error_code& ec) 378 { 379 return this->service.expires_at(this->implementation, expiry_time, ec); 380 } 381 382 /// Get the timer's expiry time relative to now. 383 /** 384 * This function may be used to obtain the timer's current expiry time. 385 * Whether the timer has expired or not does not affect this value. 386 */ expires_from_now() const387 duration expires_from_now() const 388 { 389 return this->service.expires_from_now(this->implementation); 390 } 391 392 /// Set the timer's expiry time relative to now. 393 /** 394 * This function sets the expiry time. Any pending asynchronous wait 395 * operations will be cancelled. The handler for each cancelled operation will 396 * be invoked with the boost::asio::error::operation_aborted error code. 397 * 398 * @param expiry_time The expiry time to be used for the timer. 399 * 400 * @return The number of asynchronous operations that were cancelled. 401 * 402 * @throws boost::system::system_error Thrown on failure. 403 * 404 * @note If the timer has already expired when expires_from_now() is called, 405 * then the handlers for asynchronous wait operations will: 406 * 407 * @li have already been invoked; or 408 * 409 * @li have been queued for invocation in the near future. 410 * 411 * These handlers can no longer be cancelled, and therefore are passed an 412 * error code that indicates the successful completion of the wait operation. 413 */ expires_from_now(const duration & expiry_time)414 std::size_t expires_from_now(const duration& expiry_time) 415 { 416 boost::system::error_code ec; 417 std::size_t s = this->service.expires_from_now( 418 this->implementation, expiry_time, ec); 419 boost::asio::detail::throw_error(ec, "expires_from_now"); 420 return s; 421 } 422 423 /// Set the timer's expiry time relative to now. 424 /** 425 * This function sets the expiry time. Any pending asynchronous wait 426 * operations will be cancelled. The handler for each cancelled operation will 427 * be invoked with the boost::asio::error::operation_aborted error code. 428 * 429 * @param expiry_time The expiry time to be used for the timer. 430 * 431 * @param ec Set to indicate what error occurred, if any. 432 * 433 * @return The number of asynchronous operations that were cancelled. 434 * 435 * @note If the timer has already expired when expires_from_now() is called, 436 * then the handlers for asynchronous wait operations will: 437 * 438 * @li have already been invoked; or 439 * 440 * @li have been queued for invocation in the near future. 441 * 442 * These handlers can no longer be cancelled, and therefore are passed an 443 * error code that indicates the successful completion of the wait operation. 444 */ expires_from_now(const duration & expiry_time,boost::system::error_code & ec)445 std::size_t expires_from_now(const duration& expiry_time, 446 boost::system::error_code& ec) 447 { 448 return this->service.expires_from_now( 449 this->implementation, expiry_time, ec); 450 } 451 452 /// Perform a blocking wait on the timer. 453 /** 454 * This function is used to wait for the timer to expire. This function 455 * blocks and does not return until the timer has expired. 456 * 457 * @throws boost::system::system_error Thrown on failure. 458 */ wait()459 void wait() 460 { 461 boost::system::error_code ec; 462 this->service.wait(this->implementation, ec); 463 boost::asio::detail::throw_error(ec, "wait"); 464 } 465 466 /// Perform a blocking wait on the timer. 467 /** 468 * This function is used to wait for the timer to expire. This function 469 * blocks and does not return until the timer has expired. 470 * 471 * @param ec Set to indicate what error occurred, if any. 472 */ wait(boost::system::error_code & ec)473 void wait(boost::system::error_code& ec) 474 { 475 this->service.wait(this->implementation, ec); 476 } 477 478 /// Start an asynchronous wait on the timer. 479 /** 480 * This function may be used to initiate an asynchronous wait against the 481 * timer. It always returns immediately. 482 * 483 * For each call to async_wait(), the supplied handler will be called exactly 484 * once. The handler will be called when: 485 * 486 * @li The timer has expired. 487 * 488 * @li The timer was cancelled, in which case the handler is passed the error 489 * code boost::asio::error::operation_aborted. 490 * 491 * @param handler The handler to be called when the timer expires. Copies 492 * will be made of the handler as required. The function signature of the 493 * handler must be: 494 * @code void handler( 495 * const boost::system::error_code& error // Result of operation. 496 * ); @endcode 497 * Regardless of whether the asynchronous operation completes immediately or 498 * not, the handler will not be invoked from within this function. Invocation 499 * of the handler will be performed in a manner equivalent to using 500 * boost::asio::io_service::post(). 501 */ 502 template <typename WaitHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler,void (boost::system::error_code))503 BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, 504 void (boost::system::error_code)) 505 async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) 506 { 507 // If you get an error on the following line it means that your handler does 508 // not meet the documented type requirements for a WaitHandler. 509 BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; 510 511 return this->service.async_wait(this->implementation, 512 BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); 513 } 514 }; 515 516 } // namespace asio 517 } // namespace boost 518 519 #include <boost/asio/detail/pop_options.hpp> 520 521 #endif // BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP 522