|
||||
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
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |