basic_signal_set.hpp 22 KB

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