Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

542 lines
18KB

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