basic_signal_set.hpp 20 KB

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