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

source code of boost/libs/asio/include/boost/asio/basic_signal_set.hpp