1 // 2 // basic_signal_set.hpp 3 // ~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2020 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_SIGNAL_SET_HPP 12 #define BOOST_ASIO_BASIC_SIGNAL_SET_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 #include <boost/asio/any_io_executor.hpp> 21 #include <boost/asio/async_result.hpp> 22 #include <boost/asio/detail/handler_type_requirements.hpp> 23 #include <boost/asio/detail/io_object_impl.hpp> 24 #include <boost/asio/detail/non_const_lvalue.hpp> 25 #include <boost/asio/detail/signal_set_service.hpp> 26 #include <boost/asio/detail/throw_error.hpp> 27 #include <boost/asio/detail/type_traits.hpp> 28 #include <boost/asio/error.hpp> 29 #include <boost/asio/execution_context.hpp> 30 31 namespace boost { 32 namespace asio { 33 34 /// Provides signal functionality. 35 /** 36 * The basic_signal_set class provides the ability to perform an asynchronous 37 * wait for one or more signals to occur. 38 * 39 * @par Thread Safety 40 * @e Distinct @e objects: Safe.@n 41 * @e Shared @e objects: Unsafe. 42 * 43 * @par Example 44 * Performing an asynchronous wait: 45 * @code 46 * void handler( 47 * const boost::system::error_code& error, 48 * int signal_number) 49 * { 50 * if (!error) 51 * { 52 * // A signal occurred. 53 * } 54 * } 55 * 56 * ... 57 * 58 * // Construct a signal set registered for process termination. 59 * boost::asio::signal_set signals(my_context, SIGINT, SIGTERM); 60 * 61 * // Start an asynchronous wait for one of the signals to occur. 62 * signals.async_wait(handler); 63 * @endcode 64 * 65 * @par Queueing of signal notifications 66 * 67 * If a signal is registered with a signal_set, and the signal occurs when 68 * there are no waiting handlers, then the signal notification is queued. The 69 * next async_wait operation on that signal_set will dequeue the notification. 70 * If multiple notifications are queued, subsequent async_wait operations 71 * dequeue them one at a time. Signal notifications are dequeued in order of 72 * ascending signal number. 73 * 74 * If a signal number is removed from a signal_set (using the @c remove or @c 75 * erase member functions) then any queued notifications for that signal are 76 * discarded. 77 * 78 * @par Multiple registration of signals 79 * 80 * The same signal number may be registered with different signal_set objects. 81 * When the signal occurs, one handler is called for each signal_set object. 82 * 83 * Note that multiple registration only works for signals that are registered 84 * using Asio. The application must not also register a signal handler using 85 * functions such as @c signal() or @c sigaction(). 86 * 87 * @par Signal masking on POSIX platforms 88 * 89 * POSIX allows signals to be blocked using functions such as @c sigprocmask() 90 * and @c pthread_sigmask(). For signals to be delivered, programs must ensure 91 * that any signals registered using signal_set objects are unblocked in at 92 * least one thread. 93 */ 94 template <typename Executor = any_io_executor> 95 class basic_signal_set 96 { 97 public: 98 /// The type of the executor associated with the object. 99 typedef Executor executor_type; 100 101 /// Rebinds the signal set type to another executor. 102 template <typename Executor1> 103 struct rebind_executor 104 { 105 /// The signal set type when rebound to the specified executor. 106 typedef basic_signal_set<Executor1> other; 107 }; 108 109 /// Construct a signal set without adding any signals. 110 /** 111 * This constructor creates a signal set without registering for any signals. 112 * 113 * @param ex The I/O executor that the signal set will use, by default, to 114 * dispatch handlers for any asynchronous operations performed on the 115 * signal set. 116 */ basic_signal_set(const executor_type & ex)117 explicit basic_signal_set(const executor_type& ex) 118 : impl_(ex) 119 { 120 } 121 122 /// Construct a signal set without adding any signals. 123 /** 124 * This constructor creates a signal set without registering for any signals. 125 * 126 * @param context An execution context which provides the I/O executor that 127 * the signal set will use, by default, to dispatch handlers for any 128 * asynchronous operations performed on the signal set. 129 */ 130 template <typename ExecutionContext> basic_signal_set(ExecutionContext & context,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)131 explicit basic_signal_set(ExecutionContext& context, 132 typename enable_if< 133 is_convertible<ExecutionContext&, execution_context&>::value 134 >::type* = 0) 135 : impl_(context) 136 { 137 } 138 139 /// Construct a signal set and add one signal. 140 /** 141 * This constructor creates a signal set and registers for one signal. 142 * 143 * @param ex The I/O executor that the signal set will use, by default, to 144 * dispatch handlers for any asynchronous operations performed on the 145 * signal set. 146 * 147 * @param signal_number_1 The signal number to be added. 148 * 149 * @note This constructor is equivalent to performing: 150 * @code boost::asio::signal_set signals(ex); 151 * signals.add(signal_number_1); @endcode 152 */ basic_signal_set(const executor_type & ex,int signal_number_1)153 basic_signal_set(const executor_type& ex, int signal_number_1) 154 : impl_(ex) 155 { 156 boost::system::error_code ec; 157 impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); 158 boost::asio::detail::throw_error(ec, "add"); 159 } 160 161 /// Construct a signal set and add one signal. 162 /** 163 * This constructor creates a signal set and registers for one signal. 164 * 165 * @param context An execution context which provides the I/O executor that 166 * the signal set will use, by default, to dispatch handlers for any 167 * asynchronous operations performed on the signal set. 168 * 169 * @param signal_number_1 The signal number to be added. 170 * 171 * @note This constructor is equivalent to performing: 172 * @code boost::asio::signal_set signals(context); 173 * signals.add(signal_number_1); @endcode 174 */ 175 template <typename ExecutionContext> basic_signal_set(ExecutionContext & context,int signal_number_1,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)176 basic_signal_set(ExecutionContext& context, int signal_number_1, 177 typename enable_if< 178 is_convertible<ExecutionContext&, execution_context&>::value 179 >::type* = 0) 180 : impl_(context) 181 { 182 boost::system::error_code ec; 183 impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); 184 boost::asio::detail::throw_error(ec, "add"); 185 } 186 187 /// Construct a signal set and add two signals. 188 /** 189 * This constructor creates a signal set and registers for two signals. 190 * 191 * @param ex The I/O executor that the signal set will use, by default, to 192 * dispatch handlers for any asynchronous operations performed on the 193 * signal set. 194 * 195 * @param signal_number_1 The first signal number to be added. 196 * 197 * @param signal_number_2 The second signal number to be added. 198 * 199 * @note This constructor is equivalent to performing: 200 * @code boost::asio::signal_set signals(ex); 201 * signals.add(signal_number_1); 202 * signals.add(signal_number_2); @endcode 203 */ basic_signal_set(const executor_type & ex,int signal_number_1,int signal_number_2)204 basic_signal_set(const executor_type& ex, int signal_number_1, 205 int signal_number_2) 206 : impl_(ex) 207 { 208 boost::system::error_code ec; 209 impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); 210 boost::asio::detail::throw_error(ec, "add"); 211 impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); 212 boost::asio::detail::throw_error(ec, "add"); 213 } 214 215 /// Construct a signal set and add two signals. 216 /** 217 * This constructor creates a signal set and registers for two signals. 218 * 219 * @param context An execution context which provides the I/O executor that 220 * the signal set will use, by default, to dispatch handlers for any 221 * asynchronous operations performed on the signal set. 222 * 223 * @param signal_number_1 The first signal number to be added. 224 * 225 * @param signal_number_2 The second signal number to be added. 226 * 227 * @note This constructor is equivalent to performing: 228 * @code boost::asio::signal_set signals(context); 229 * signals.add(signal_number_1); 230 * signals.add(signal_number_2); @endcode 231 */ 232 template <typename ExecutionContext> basic_signal_set(ExecutionContext & context,int signal_number_1,int signal_number_2,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)233 basic_signal_set(ExecutionContext& context, int signal_number_1, 234 int signal_number_2, 235 typename enable_if< 236 is_convertible<ExecutionContext&, execution_context&>::value 237 >::type* = 0) 238 : impl_(context) 239 { 240 boost::system::error_code ec; 241 impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); 242 boost::asio::detail::throw_error(ec, "add"); 243 impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); 244 boost::asio::detail::throw_error(ec, "add"); 245 } 246 247 /// Construct a signal set and add three signals. 248 /** 249 * This constructor creates a signal set and registers for three signals. 250 * 251 * @param ex The I/O executor that the signal set will use, by default, to 252 * dispatch handlers for any asynchronous operations performed on the 253 * signal set. 254 * 255 * @param signal_number_1 The first signal number to be added. 256 * 257 * @param signal_number_2 The second signal number to be added. 258 * 259 * @param signal_number_3 The third signal number to be added. 260 * 261 * @note This constructor is equivalent to performing: 262 * @code boost::asio::signal_set signals(ex); 263 * signals.add(signal_number_1); 264 * signals.add(signal_number_2); 265 * signals.add(signal_number_3); @endcode 266 */ basic_signal_set(const executor_type & ex,int signal_number_1,int signal_number_2,int signal_number_3)267 basic_signal_set(const executor_type& ex, int signal_number_1, 268 int signal_number_2, int signal_number_3) 269 : impl_(ex) 270 { 271 boost::system::error_code ec; 272 impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); 273 boost::asio::detail::throw_error(ec, "add"); 274 impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); 275 boost::asio::detail::throw_error(ec, "add"); 276 impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); 277 boost::asio::detail::throw_error(ec, "add"); 278 } 279 280 /// Construct a signal set and add three signals. 281 /** 282 * This constructor creates a signal set and registers for three signals. 283 * 284 * @param context An execution context which provides the I/O executor that 285 * the signal set will use, by default, to dispatch handlers for any 286 * asynchronous operations performed on the signal set. 287 * 288 * @param signal_number_1 The first signal number to be added. 289 * 290 * @param signal_number_2 The second signal number to be added. 291 * 292 * @param signal_number_3 The third signal number to be added. 293 * 294 * @note This constructor is equivalent to performing: 295 * @code boost::asio::signal_set signals(context); 296 * signals.add(signal_number_1); 297 * signals.add(signal_number_2); 298 * signals.add(signal_number_3); @endcode 299 */ 300 template <typename ExecutionContext> basic_signal_set(ExecutionContext & context,int signal_number_1,int signal_number_2,int signal_number_3,typename enable_if<is_convertible<ExecutionContext &,execution_context &>::value>::type * =0)301 basic_signal_set(ExecutionContext& context, int signal_number_1, 302 int signal_number_2, int signal_number_3, 303 typename enable_if< 304 is_convertible<ExecutionContext&, execution_context&>::value 305 >::type* = 0) 306 : impl_(context) 307 { 308 boost::system::error_code ec; 309 impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); 310 boost::asio::detail::throw_error(ec, "add"); 311 impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); 312 boost::asio::detail::throw_error(ec, "add"); 313 impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); 314 boost::asio::detail::throw_error(ec, "add"); 315 } 316 317 /// Destroys the signal set. 318 /** 319 * This function destroys the signal set, cancelling any outstanding 320 * asynchronous wait operations associated with the signal set as if by 321 * calling @c cancel. 322 */ ~basic_signal_set()323 ~basic_signal_set() 324 { 325 } 326 327 /// Get the executor associated with the object. get_executor()328 executor_type get_executor() BOOST_ASIO_NOEXCEPT 329 { 330 return impl_.get_executor(); 331 } 332 333 /// Add a signal to a signal_set. 334 /** 335 * This function adds the specified signal to the set. It has no effect if the 336 * signal is already in the set. 337 * 338 * @param signal_number The signal to be added to the set. 339 * 340 * @throws boost::system::system_error Thrown on failure. 341 */ add(int signal_number)342 void add(int signal_number) 343 { 344 boost::system::error_code ec; 345 impl_.get_service().add(impl_.get_implementation(), signal_number, ec); 346 boost::asio::detail::throw_error(ec, "add"); 347 } 348 349 /// Add a signal to a signal_set. 350 /** 351 * This function adds the specified signal to the set. It has no effect if the 352 * signal is already in the set. 353 * 354 * @param signal_number The signal to be added to the set. 355 * 356 * @param ec Set to indicate what error occurred, if any. 357 */ add(int signal_number,boost::system::error_code & ec)358 BOOST_ASIO_SYNC_OP_VOID add(int signal_number, 359 boost::system::error_code& ec) 360 { 361 impl_.get_service().add(impl_.get_implementation(), signal_number, ec); 362 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 363 } 364 365 /// Remove a signal from a signal_set. 366 /** 367 * This function removes the specified signal from the set. It has no effect 368 * if the signal is not in the set. 369 * 370 * @param signal_number The signal to be removed from the set. 371 * 372 * @throws boost::system::system_error Thrown on failure. 373 * 374 * @note Removes any notifications that have been queued for the specified 375 * signal number. 376 */ remove(int signal_number)377 void remove(int signal_number) 378 { 379 boost::system::error_code ec; 380 impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); 381 boost::asio::detail::throw_error(ec, "remove"); 382 } 383 384 /// Remove a signal from a signal_set. 385 /** 386 * This function removes the specified signal from the set. It has no effect 387 * if the signal is not in the set. 388 * 389 * @param signal_number The signal to be removed from the set. 390 * 391 * @param ec Set to indicate what error occurred, if any. 392 * 393 * @note Removes any notifications that have been queued for the specified 394 * signal number. 395 */ remove(int signal_number,boost::system::error_code & ec)396 BOOST_ASIO_SYNC_OP_VOID remove(int signal_number, 397 boost::system::error_code& ec) 398 { 399 impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); 400 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 401 } 402 403 /// Remove all signals from a signal_set. 404 /** 405 * This function removes all signals from the set. It has no effect if the set 406 * is already empty. 407 * 408 * @throws boost::system::system_error Thrown on failure. 409 * 410 * @note Removes all queued notifications. 411 */ clear()412 void clear() 413 { 414 boost::system::error_code ec; 415 impl_.get_service().clear(impl_.get_implementation(), ec); 416 boost::asio::detail::throw_error(ec, "clear"); 417 } 418 419 /// Remove all signals from a signal_set. 420 /** 421 * This function removes all signals from the set. It has no effect if the set 422 * is already empty. 423 * 424 * @param ec Set to indicate what error occurred, if any. 425 * 426 * @note Removes all queued notifications. 427 */ clear(boost::system::error_code & ec)428 BOOST_ASIO_SYNC_OP_VOID clear(boost::system::error_code& ec) 429 { 430 impl_.get_service().clear(impl_.get_implementation(), ec); 431 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 432 } 433 434 /// Cancel all operations associated with the signal set. 435 /** 436 * This function forces the completion of any pending asynchronous wait 437 * operations against the signal set. The handler for each cancelled 438 * operation will be invoked with the boost::asio::error::operation_aborted 439 * error code. 440 * 441 * Cancellation does not alter the set of registered signals. 442 * 443 * @throws boost::system::system_error Thrown on failure. 444 * 445 * @note If a registered signal occurred before cancel() is called, then the 446 * handlers for asynchronous wait operations will: 447 * 448 * @li have already been invoked; or 449 * 450 * @li have been queued for invocation in the near future. 451 * 452 * These handlers can no longer be cancelled, and therefore are passed an 453 * error code that indicates the successful completion of the wait operation. 454 */ cancel()455 void cancel() 456 { 457 boost::system::error_code ec; 458 impl_.get_service().cancel(impl_.get_implementation(), ec); 459 boost::asio::detail::throw_error(ec, "cancel"); 460 } 461 462 /// Cancel all operations associated with the signal set. 463 /** 464 * This function forces the completion of any pending asynchronous wait 465 * operations against the signal set. The handler for each cancelled 466 * operation will be invoked with the boost::asio::error::operation_aborted 467 * error code. 468 * 469 * Cancellation does not alter the set of registered signals. 470 * 471 * @param ec Set to indicate what error occurred, if any. 472 * 473 * @note If a registered signal occurred before cancel() is called, then the 474 * handlers for asynchronous wait operations will: 475 * 476 * @li have already been invoked; or 477 * 478 * @li have been queued for invocation in the near future. 479 * 480 * These handlers can no longer be cancelled, and therefore are passed an 481 * error code that indicates the successful completion of the wait operation. 482 */ cancel(boost::system::error_code & ec)483 BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) 484 { 485 impl_.get_service().cancel(impl_.get_implementation(), ec); 486 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 487 } 488 489 /// Start an asynchronous operation to wait for a signal to be delivered. 490 /** 491 * This function may be used to initiate an asynchronous wait against the 492 * signal set. It always returns immediately. 493 * 494 * For each call to async_wait(), the supplied handler will be called exactly 495 * once. The handler will be called when: 496 * 497 * @li One of the registered signals in the signal set occurs; or 498 * 499 * @li The signal set was cancelled, in which case the handler is passed the 500 * error code boost::asio::error::operation_aborted. 501 * 502 * @param handler The handler to be called when the signal occurs. Copies 503 * will be made of the handler as required. The function signature of the 504 * handler must be: 505 * @code void handler( 506 * const boost::system::error_code& error, // Result of operation. 507 * int signal_number // Indicates which signal occurred. 508 * ); @endcode 509 * Regardless of whether the asynchronous operation completes immediately or 510 * not, the handler will not be invoked from within this function. On 511 * immediate completion, invocation of the handler will be performed in a 512 * manner equivalent to using boost::asio::post(). 513 */ 514 template < 515 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, int)) 516 SignalHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler,void (boost::system::error_code,int))517 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler, 518 void (boost::system::error_code, int)) 519 async_wait( 520 BOOST_ASIO_MOVE_ARG(SignalHandler) handler 521 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) 522 { 523 return async_initiate<SignalHandler, void (boost::system::error_code, int)>( 524 initiate_async_wait(this), handler); 525 } 526 527 private: 528 // Disallow copying and assignment. 529 basic_signal_set(const basic_signal_set&) BOOST_ASIO_DELETED; 530 basic_signal_set& operator=(const basic_signal_set&) BOOST_ASIO_DELETED; 531 532 class initiate_async_wait 533 { 534 public: 535 typedef Executor executor_type; 536 initiate_async_wait(basic_signal_set * self)537 explicit initiate_async_wait(basic_signal_set* self) 538 : self_(self) 539 { 540 } 541 get_executor() const542 executor_type get_executor() const BOOST_ASIO_NOEXCEPT 543 { 544 return self_->get_executor(); 545 } 546 547 template <typename SignalHandler> operator ()(BOOST_ASIO_MOVE_ARG (SignalHandler)handler) const548 void operator()(BOOST_ASIO_MOVE_ARG(SignalHandler) handler) const 549 { 550 // If you get an error on the following line it means that your handler 551 // does not meet the documented type requirements for a SignalHandler. 552 BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; 553 554 detail::non_const_lvalue<SignalHandler> handler2(handler); 555 self_->impl_.get_service().async_wait( 556 self_->impl_.get_implementation(), 557 handler2.value, self_->impl_.get_executor()); 558 } 559 560 private: 561 basic_signal_set* self_; 562 }; 563 564 detail::io_object_impl<detail::signal_set_service, Executor> impl_; 565 }; 566 567 } // namespace asio 568 } // namespace boost 569 570 #endif // BOOST_ASIO_BASIC_SIGNAL_SET_HPP 571