Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:05

0001 //
0002 // basic_signal_set.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_BASIC_SIGNAL_SET_HPP
0012 #define BOOST_ASIO_BASIC_SIGNAL_SET_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #include <boost/asio/any_io_executor.hpp>
0021 #include <boost/asio/async_result.hpp>
0022 #include <boost/asio/detail/handler_type_requirements.hpp>
0023 #include <boost/asio/detail/io_object_impl.hpp>
0024 #include <boost/asio/detail/non_const_lvalue.hpp>
0025 #include <boost/asio/detail/signal_set_service.hpp>
0026 #include <boost/asio/detail/throw_error.hpp>
0027 #include <boost/asio/detail/type_traits.hpp>
0028 #include <boost/asio/error.hpp>
0029 #include <boost/asio/execution_context.hpp>
0030 #include <boost/asio/signal_set_base.hpp>
0031 
0032 #include <boost/asio/detail/push_options.hpp>
0033 
0034 namespace boost {
0035 namespace asio {
0036 
0037 /// Provides signal functionality.
0038 /**
0039  * The basic_signal_set class provides the ability to perform an asynchronous
0040  * wait for one or more signals to occur.
0041  *
0042  * @par Thread Safety
0043  * @e Distinct @e objects: Safe.@n
0044  * @e Shared @e objects: Unsafe.
0045  *
0046  * @par Example
0047  * Performing an asynchronous wait:
0048  * @code
0049  * void handler(
0050  *     const boost::system::error_code& error,
0051  *     int signal_number)
0052  * {
0053  *   if (!error)
0054  *   {
0055  *     // A signal occurred.
0056  *   }
0057  * }
0058  *
0059  * ...
0060  *
0061  * // Construct a signal set registered for process termination.
0062  * boost::asio::signal_set signals(my_context, SIGINT, SIGTERM);
0063  *
0064  * // Start an asynchronous wait for one of the signals to occur.
0065  * signals.async_wait(handler);
0066  * @endcode
0067  *
0068  * @par Queueing of signal notifications
0069  *
0070  * If a signal is registered with a signal_set, and the signal occurs when
0071  * there are no waiting handlers, then the signal notification is queued. The
0072  * next async_wait operation on that signal_set will dequeue the notification.
0073  * If multiple notifications are queued, subsequent async_wait operations
0074  * dequeue them one at a time. Signal notifications are dequeued in order of
0075  * ascending signal number.
0076  *
0077  * If a signal number is removed from a signal_set (using the @c remove or @c
0078  * erase member functions) then any queued notifications for that signal are
0079  * discarded.
0080  *
0081  * @par Multiple registration of signals
0082  *
0083  * The same signal number may be registered with different signal_set objects.
0084  * When the signal occurs, one handler is called for each signal_set object.
0085  *
0086  * Note that multiple registration only works for signals that are registered
0087  * using Asio. The application must not also register a signal handler using
0088  * functions such as @c signal() or @c sigaction().
0089  *
0090  * @par Signal masking on POSIX platforms
0091  *
0092  * POSIX allows signals to be blocked using functions such as @c sigprocmask()
0093  * and @c pthread_sigmask(). For signals to be delivered, programs must ensure
0094  * that any signals registered using signal_set objects are unblocked in at
0095  * least one thread.
0096  */
0097 template <typename Executor = any_io_executor>
0098 class basic_signal_set : public signal_set_base
0099 {
0100 private:
0101   class initiate_async_wait;
0102 
0103 public:
0104   /// The type of the executor associated with the object.
0105   typedef Executor executor_type;
0106 
0107   /// Rebinds the signal set type to another executor.
0108   template <typename Executor1>
0109   struct rebind_executor
0110   {
0111     /// The signal set type when rebound to the specified executor.
0112     typedef basic_signal_set<Executor1> other;
0113   };
0114 
0115   /// Construct a signal set without adding any signals.
0116   /**
0117    * This constructor creates a signal set without registering for any signals.
0118    *
0119    * @param ex The I/O executor that the signal set will use, by default, to
0120    * dispatch handlers for any asynchronous operations performed on the
0121    * signal set.
0122    */
0123   explicit basic_signal_set(const executor_type& ex)
0124     : impl_(0, ex)
0125   {
0126   }
0127 
0128   /// Construct a signal set without adding any signals.
0129   /**
0130    * This constructor creates a signal set without registering for any signals.
0131    *
0132    * @param context An execution context which provides the I/O executor that
0133    * the signal set will use, by default, to dispatch handlers for any
0134    * asynchronous operations performed on the signal set.
0135    */
0136   template <typename ExecutionContext>
0137   explicit basic_signal_set(ExecutionContext& context,
0138       constraint_t<
0139         is_convertible<ExecutionContext&, execution_context&>::value,
0140         defaulted_constraint
0141       > = defaulted_constraint())
0142     : impl_(0, 0, context)
0143   {
0144   }
0145 
0146   /// Construct a signal set and add one signal.
0147   /**
0148    * This constructor creates a signal set and registers for one signal.
0149    *
0150    * @param ex The I/O executor that the signal set will use, by default, to
0151    * dispatch handlers for any asynchronous operations performed on the
0152    * signal set.
0153    *
0154    * @param signal_number_1 The signal number to be added.
0155    *
0156    * @note This constructor is equivalent to performing:
0157    * @code boost::asio::signal_set signals(ex);
0158    * signals.add(signal_number_1); @endcode
0159    */
0160   basic_signal_set(const executor_type& ex, int signal_number_1)
0161     : impl_(0, ex)
0162   {
0163     boost::system::error_code ec;
0164     impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
0165     boost::asio::detail::throw_error(ec, "add");
0166   }
0167 
0168   /// Construct a signal set and add one signal.
0169   /**
0170    * This constructor creates a signal set and registers for one signal.
0171    *
0172    * @param context An execution context which provides the I/O executor that
0173    * the signal set will use, by default, to dispatch handlers for any
0174    * asynchronous operations performed on the signal set.
0175    *
0176    * @param signal_number_1 The signal number to be added.
0177    *
0178    * @note This constructor is equivalent to performing:
0179    * @code boost::asio::signal_set signals(context);
0180    * signals.add(signal_number_1); @endcode
0181    */
0182   template <typename ExecutionContext>
0183   basic_signal_set(ExecutionContext& context, int signal_number_1,
0184       constraint_t<
0185         is_convertible<ExecutionContext&, execution_context&>::value,
0186         defaulted_constraint
0187       > = defaulted_constraint())
0188     : impl_(0, 0, context)
0189   {
0190     boost::system::error_code ec;
0191     impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
0192     boost::asio::detail::throw_error(ec, "add");
0193   }
0194 
0195   /// Construct a signal set and add two signals.
0196   /**
0197    * This constructor creates a signal set and registers for two signals.
0198    *
0199    * @param ex The I/O executor that the signal set will use, by default, to
0200    * dispatch handlers for any asynchronous operations performed on the
0201    * signal set.
0202    *
0203    * @param signal_number_1 The first signal number to be added.
0204    *
0205    * @param signal_number_2 The second signal number to be added.
0206    *
0207    * @note This constructor is equivalent to performing:
0208    * @code boost::asio::signal_set signals(ex);
0209    * signals.add(signal_number_1);
0210    * signals.add(signal_number_2); @endcode
0211    */
0212   basic_signal_set(const executor_type& ex, int signal_number_1,
0213       int signal_number_2)
0214     : impl_(0, ex)
0215   {
0216     boost::system::error_code ec;
0217     impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
0218     boost::asio::detail::throw_error(ec, "add");
0219     impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
0220     boost::asio::detail::throw_error(ec, "add");
0221   }
0222 
0223   /// Construct a signal set and add two signals.
0224   /**
0225    * This constructor creates a signal set and registers for two signals.
0226    *
0227    * @param context An execution context which provides the I/O executor that
0228    * the signal set will use, by default, to dispatch handlers for any
0229    * asynchronous operations performed on the signal set.
0230    *
0231    * @param signal_number_1 The first signal number to be added.
0232    *
0233    * @param signal_number_2 The second signal number to be added.
0234    *
0235    * @note This constructor is equivalent to performing:
0236    * @code boost::asio::signal_set signals(context);
0237    * signals.add(signal_number_1);
0238    * signals.add(signal_number_2); @endcode
0239    */
0240   template <typename ExecutionContext>
0241   basic_signal_set(ExecutionContext& context, int signal_number_1,
0242       int signal_number_2,
0243       constraint_t<
0244         is_convertible<ExecutionContext&, execution_context&>::value,
0245         defaulted_constraint
0246       > = defaulted_constraint())
0247     : impl_(0, 0, context)
0248   {
0249     boost::system::error_code ec;
0250     impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
0251     boost::asio::detail::throw_error(ec, "add");
0252     impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
0253     boost::asio::detail::throw_error(ec, "add");
0254   }
0255 
0256   /// Construct a signal set and add three signals.
0257   /**
0258    * This constructor creates a signal set and registers for three signals.
0259    *
0260    * @param ex The I/O executor that the signal set will use, by default, to
0261    * dispatch handlers for any asynchronous operations performed on the
0262    * signal set.
0263    *
0264    * @param signal_number_1 The first signal number to be added.
0265    *
0266    * @param signal_number_2 The second signal number to be added.
0267    *
0268    * @param signal_number_3 The third signal number to be added.
0269    *
0270    * @note This constructor is equivalent to performing:
0271    * @code boost::asio::signal_set signals(ex);
0272    * signals.add(signal_number_1);
0273    * signals.add(signal_number_2);
0274    * signals.add(signal_number_3); @endcode
0275    */
0276   basic_signal_set(const executor_type& ex, int signal_number_1,
0277       int signal_number_2, int signal_number_3)
0278     : impl_(0, ex)
0279   {
0280     boost::system::error_code ec;
0281     impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
0282     boost::asio::detail::throw_error(ec, "add");
0283     impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
0284     boost::asio::detail::throw_error(ec, "add");
0285     impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
0286     boost::asio::detail::throw_error(ec, "add");
0287   }
0288 
0289   /// Construct a signal set and add three signals.
0290   /**
0291    * This constructor creates a signal set and registers for three signals.
0292    *
0293    * @param context An execution context which provides the I/O executor that
0294    * the signal set will use, by default, to dispatch handlers for any
0295    * asynchronous operations performed on the signal set.
0296    *
0297    * @param signal_number_1 The first signal number to be added.
0298    *
0299    * @param signal_number_2 The second signal number to be added.
0300    *
0301    * @param signal_number_3 The third signal number to be added.
0302    *
0303    * @note This constructor is equivalent to performing:
0304    * @code boost::asio::signal_set signals(context);
0305    * signals.add(signal_number_1);
0306    * signals.add(signal_number_2);
0307    * signals.add(signal_number_3); @endcode
0308    */
0309   template <typename ExecutionContext>
0310   basic_signal_set(ExecutionContext& context, int signal_number_1,
0311       int signal_number_2, int signal_number_3,
0312       constraint_t<
0313         is_convertible<ExecutionContext&, execution_context&>::value,
0314         defaulted_constraint
0315       > = defaulted_constraint())
0316     : impl_(0, 0, context)
0317   {
0318     boost::system::error_code ec;
0319     impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
0320     boost::asio::detail::throw_error(ec, "add");
0321     impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
0322     boost::asio::detail::throw_error(ec, "add");
0323     impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
0324     boost::asio::detail::throw_error(ec, "add");
0325   }
0326 
0327   /// Destroys the signal set.
0328   /**
0329    * This function destroys the signal set, cancelling any outstanding
0330    * asynchronous wait operations associated with the signal set as if by
0331    * calling @c cancel.
0332    */
0333   ~basic_signal_set()
0334   {
0335   }
0336 
0337   /// Get the executor associated with the object.
0338   const executor_type& get_executor() noexcept
0339   {
0340     return impl_.get_executor();
0341   }
0342 
0343   /// Add a signal to a signal_set.
0344   /**
0345    * This function adds the specified signal to the set. It has no effect if the
0346    * signal is already in the set.
0347    *
0348    * @param signal_number The signal to be added to the set.
0349    *
0350    * @throws boost::system::system_error Thrown on failure.
0351    */
0352   void add(int signal_number)
0353   {
0354     boost::system::error_code ec;
0355     impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
0356     boost::asio::detail::throw_error(ec, "add");
0357   }
0358 
0359   /// Add a signal to a signal_set.
0360   /**
0361    * This function adds the specified signal to the set. It has no effect if the
0362    * signal is already in the set.
0363    *
0364    * @param signal_number The signal to be added to the set.
0365    *
0366    * @param ec Set to indicate what error occurred, if any.
0367    */
0368   BOOST_ASIO_SYNC_OP_VOID add(int signal_number,
0369       boost::system::error_code& ec)
0370   {
0371     impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
0372     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0373   }
0374 
0375   /// Add a signal to a signal_set with the specified flags.
0376   /**
0377    * This function adds the specified signal to the set. It has no effect if the
0378    * signal is already in the set.
0379    *
0380    * Flags other than flags::dont_care require OS support for the @c sigaction
0381    * call, and this function will fail with @c error::operation_not_supported if
0382    * this is unavailable.
0383    *
0384    * The specified flags will conflict with a prior, active registration of the
0385    * same signal, if either specified a flags value other than flags::dont_care.
0386    * In this case, the @c add will fail with @c error::invalid_argument.
0387    *
0388    * @param signal_number The signal to be added to the set.
0389    *
0390    * @param f Flags to modify the behaviour of the specified signal.
0391    *
0392    * @throws boost::system::system_error Thrown on failure.
0393    */
0394   void add(int signal_number, flags_t f)
0395   {
0396     boost::system::error_code ec;
0397     impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec);
0398     boost::asio::detail::throw_error(ec, "add");
0399   }
0400 
0401   /// Add a signal to a signal_set with the specified flags.
0402   /**
0403    * This function adds the specified signal to the set. It has no effect if the
0404    * signal is already in the set.
0405    *
0406    * Flags other than flags::dont_care require OS support for the @c sigaction
0407    * call, and this function will fail with @c error::operation_not_supported if
0408    * this is unavailable.
0409    *
0410    * The specified flags will conflict with a prior, active registration of the
0411    * same signal, if either specified a flags value other than flags::dont_care.
0412    * In this case, the @c add will fail with @c error::invalid_argument.
0413    *
0414    * @param signal_number The signal to be added to the set.
0415    *
0416    * @param f Flags to modify the behaviour of the specified signal.
0417    *
0418    * @param ec Set to indicate what error occurred, if any.
0419    */
0420   BOOST_ASIO_SYNC_OP_VOID add(int signal_number, flags_t f,
0421       boost::system::error_code& ec)
0422   {
0423     impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec);
0424     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0425   }
0426 
0427   /// Remove a signal from a signal_set.
0428   /**
0429    * This function removes the specified signal from the set. It has no effect
0430    * if the signal is not in the set.
0431    *
0432    * @param signal_number The signal to be removed from the set.
0433    *
0434    * @throws boost::system::system_error Thrown on failure.
0435    *
0436    * @note Removes any notifications that have been queued for the specified
0437    * signal number.
0438    */
0439   void remove(int signal_number)
0440   {
0441     boost::system::error_code ec;
0442     impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
0443     boost::asio::detail::throw_error(ec, "remove");
0444   }
0445 
0446   /// Remove a signal from a signal_set.
0447   /**
0448    * This function removes the specified signal from the set. It has no effect
0449    * if the signal is not in the set.
0450    *
0451    * @param signal_number The signal to be removed from the set.
0452    *
0453    * @param ec Set to indicate what error occurred, if any.
0454    *
0455    * @note Removes any notifications that have been queued for the specified
0456    * signal number.
0457    */
0458   BOOST_ASIO_SYNC_OP_VOID remove(int signal_number,
0459       boost::system::error_code& ec)
0460   {
0461     impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
0462     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0463   }
0464 
0465   /// Remove all signals from a signal_set.
0466   /**
0467    * This function removes all signals from the set. It has no effect if the set
0468    * is already empty.
0469    *
0470    * @throws boost::system::system_error Thrown on failure.
0471    *
0472    * @note Removes all queued notifications.
0473    */
0474   void clear()
0475   {
0476     boost::system::error_code ec;
0477     impl_.get_service().clear(impl_.get_implementation(), ec);
0478     boost::asio::detail::throw_error(ec, "clear");
0479   }
0480 
0481   /// Remove all signals from a signal_set.
0482   /**
0483    * This function removes all signals from the set. It has no effect if the set
0484    * is already empty.
0485    *
0486    * @param ec Set to indicate what error occurred, if any.
0487    *
0488    * @note Removes all queued notifications.
0489    */
0490   BOOST_ASIO_SYNC_OP_VOID clear(boost::system::error_code& ec)
0491   {
0492     impl_.get_service().clear(impl_.get_implementation(), ec);
0493     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0494   }
0495 
0496   /// Cancel all operations associated with the signal set.
0497   /**
0498    * This function forces the completion of any pending asynchronous wait
0499    * operations against the signal set. The handler for each cancelled
0500    * operation will be invoked with the boost::asio::error::operation_aborted
0501    * error code.
0502    *
0503    * Cancellation does not alter the set of registered signals.
0504    *
0505    * @throws boost::system::system_error Thrown on failure.
0506    *
0507    * @note If a registered signal occurred before cancel() is called, then the
0508    * handlers for asynchronous wait operations will:
0509    *
0510    * @li have already been invoked; or
0511    *
0512    * @li have been queued for invocation in the near future.
0513    *
0514    * These handlers can no longer be cancelled, and therefore are passed an
0515    * error code that indicates the successful completion of the wait operation.
0516    */
0517   void cancel()
0518   {
0519     boost::system::error_code ec;
0520     impl_.get_service().cancel(impl_.get_implementation(), ec);
0521     boost::asio::detail::throw_error(ec, "cancel");
0522   }
0523 
0524   /// Cancel all operations associated with the signal set.
0525   /**
0526    * This function forces the completion of any pending asynchronous wait
0527    * operations against the signal set. The handler for each cancelled
0528    * operation will be invoked with the boost::asio::error::operation_aborted
0529    * error code.
0530    *
0531    * Cancellation does not alter the set of registered signals.
0532    *
0533    * @param ec Set to indicate what error occurred, if any.
0534    *
0535    * @note If a registered signal occurred before cancel() is called, then the
0536    * handlers for asynchronous wait operations will:
0537    *
0538    * @li have already been invoked; or
0539    *
0540    * @li have been queued for invocation in the near future.
0541    *
0542    * These handlers can no longer be cancelled, and therefore are passed an
0543    * error code that indicates the successful completion of the wait operation.
0544    */
0545   BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
0546   {
0547     impl_.get_service().cancel(impl_.get_implementation(), ec);
0548     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
0549   }
0550 
0551   /// Start an asynchronous operation to wait for a signal to be delivered.
0552   /**
0553    * This function may be used to initiate an asynchronous wait against the
0554    * signal set. It is an initiating function for an @ref
0555    * asynchronous_operation, and always returns immediately.
0556    *
0557    * For each call to async_wait(), the completion handler will be called
0558    * exactly once. The completion handler will be called when:
0559    *
0560    * @li One of the registered signals in the signal set occurs; or
0561    *
0562    * @li The signal set was cancelled, in which case the handler is passed the
0563    * error code boost::asio::error::operation_aborted.
0564    *
0565    * @param token The @ref completion_token that will be used to produce a
0566    * completion handler, which will be called when the wait completes.
0567    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0568    * @ref yield_context, or a function object with the correct completion
0569    * signature. The function signature of the completion handler must be:
0570    * @code void handler(
0571    *   const boost::system::error_code& error, // Result of operation.
0572    *   int signal_number // Indicates which signal occurred.
0573    * ); @endcode
0574    * Regardless of whether the asynchronous operation completes immediately or
0575    * not, the completion handler will not be invoked from within this function.
0576    * On immediate completion, invocation of the handler will be performed in a
0577    * manner equivalent to using boost::asio::post().
0578    *
0579    * @par Completion Signature
0580    * @code void(boost::system::error_code, int) @endcode
0581    *
0582    * @par Per-Operation Cancellation
0583    * This asynchronous operation supports cancellation for the following
0584    * boost::asio::cancellation_type values:
0585    *
0586    * @li @c cancellation_type::terminal
0587    *
0588    * @li @c cancellation_type::partial
0589    *
0590    * @li @c cancellation_type::total
0591    */
0592   template <
0593     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, int))
0594       SignalToken = default_completion_token_t<executor_type>>
0595   auto async_wait(
0596       SignalToken&& token = default_completion_token_t<executor_type>())
0597     -> decltype(
0598       async_initiate<SignalToken, void (boost::system::error_code, int)>(
0599         declval<initiate_async_wait>(), token))
0600   {
0601     return async_initiate<SignalToken, void (boost::system::error_code, int)>(
0602         initiate_async_wait(this), token);
0603   }
0604 
0605 private:
0606   // Disallow copying and assignment.
0607   basic_signal_set(const basic_signal_set&) = delete;
0608   basic_signal_set& operator=(const basic_signal_set&) = delete;
0609 
0610   class initiate_async_wait
0611   {
0612   public:
0613     typedef Executor executor_type;
0614 
0615     explicit initiate_async_wait(basic_signal_set* self)
0616       : self_(self)
0617     {
0618     }
0619 
0620     const executor_type& get_executor() const noexcept
0621     {
0622       return self_->get_executor();
0623     }
0624 
0625     template <typename SignalHandler>
0626     void operator()(SignalHandler&& handler) const
0627     {
0628       // If you get an error on the following line it means that your handler
0629       // does not meet the documented type requirements for a SignalHandler.
0630       BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;
0631 
0632       detail::non_const_lvalue<SignalHandler> handler2(handler);
0633       self_->impl_.get_service().async_wait(
0634           self_->impl_.get_implementation(),
0635           handler2.value, self_->impl_.get_executor());
0636     }
0637 
0638   private:
0639     basic_signal_set* self_;
0640   };
0641 
0642   detail::io_object_impl<detail::signal_set_service, Executor> impl_;
0643 };
0644 
0645 } // namespace asio
0646 } // namespace boost
0647 
0648 #include <boost/asio/detail/pop_options.hpp>
0649 
0650 #endif // BOOST_ASIO_BASIC_SIGNAL_SET_HPP