diff --git a/third-party/rsutils/include/rsutils/concurrency/control-c-handler.h b/third-party/rsutils/include/rsutils/concurrency/control-c-handler.h index da69fd90a3..54d9195fb8 100644 --- a/third-party/rsutils/include/rsutils/concurrency/control-c-handler.h +++ b/third-party/rsutils/include/rsutils/concurrency/control-c-handler.h @@ -7,7 +7,9 @@ namespace rsutils { namespace concurrency { -// A Python Event-like implementation, simplifying condition-variable and mutex access +// A handler for catching Control-C input from the user +// +// NOTE: only a single instance should be in use: using more than one has undefined behavior // class control_c_handler { @@ -15,8 +17,14 @@ class control_c_handler control_c_handler(); ~control_c_handler(); + // Return true if a Control-C happened bool was_pressed() const; + // Make was_pressed() return false + void reset(); + + // Block until a Control-C happens + // If already was_pressed(), the state is cleared and a new Control-C is waited on void wait(); }; diff --git a/third-party/rsutils/src/control-c-handler.cpp b/third-party/rsutils/src/control-c-handler.cpp index 720f3338e0..7d73013ce7 100644 --- a/third-party/rsutils/src/control-c-handler.cpp +++ b/third-party/rsutils/src/control-c-handler.cpp @@ -1,75 +1,86 @@ -// License: Apache 2.0. See LICENSE file in root directory. -// Copyright(c) 2024 Intel Corporation. All Rights Reserved. -#include -#include -#include - -#include - - -namespace rsutils { -namespace concurrency { - - -namespace { - -event sigint_ev; - - -void handle_signal( int signal ) -{ - switch( signal ) - { - case SIGINT: - sigint_ev.set(); - break; - } -} - -} // namespace - - -control_c_handler::control_c_handler() -{ -#ifdef _WIN32 - signal( SIGINT, handle_signal ); -#else - struct sigaction sa; - sa.sa_handler = &handle_signal; - sa.sa_flags = SA_RESTART; - sigfillset( &sa.sa_mask ); - if( sigaction( SIGINT, &sa, NULL ) == -1 ) - LOG_ERROR( "Cannot install SIGINT handler" ); -#endif -} - - -control_c_handler::~control_c_handler() -{ -#ifdef _WIN32 - signal( SIGINT, SIG_DFL ); -#else - struct sigaction sa; - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_RESTART; - sigfillset( &sa.sa_mask ); - if( sigaction( SIGINT, &sa, NULL ) == -1 ) - LOG_DEBUG( "cannot uninstall SIGINT handler" ); -#endif -} - - -bool control_c_handler::was_pressed() const -{ - return sigint_ev.is_set(); -} - - -void control_c_handler::wait() -{ - sigint_ev.clear_and_wait(); -} - - -} // namespace concurrency -} // namespace rsutils +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2024 Intel Corporation. All Rights Reserved. +#include +#include +#include + +#include +#include + + +namespace rsutils { +namespace concurrency { + + +namespace { + +event sigint_ev; +std::atomic_bool in_use( false ); + + +void handle_signal( int signal ) +{ + switch( signal ) + { + case SIGINT: + sigint_ev.set(); + break; + } +} + +} // namespace + + +control_c_handler::control_c_handler() +{ + if( in_use.exchange( true ) ) + throw std::runtime_error( "a Control-C handler is already in effect" ); +#ifdef _WIN32 + signal( SIGINT, handle_signal ); +#else + struct sigaction sa; + sa.sa_handler = &handle_signal; + sa.sa_flags = SA_RESTART; + sigfillset( &sa.sa_mask ); + if( sigaction( SIGINT, &sa, NULL ) == -1 ) + LOG_ERROR( "Cannot install SIGINT handler" ); +#endif +} + + +control_c_handler::~control_c_handler() +{ +#ifdef _WIN32 + signal( SIGINT, SIG_DFL ); +#else + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sa.sa_flags = SA_RESTART; + sigfillset( &sa.sa_mask ); + if( sigaction( SIGINT, &sa, NULL ) == -1 ) + LOG_DEBUG( "cannot uninstall SIGINT handler" ); +#endif + in_use = false; +} + + +bool control_c_handler::was_pressed() const +{ + return sigint_ev.is_set(); +} + + +void control_c_handler::reset() +{ + sigint_ev.clear(); +} + + +void control_c_handler::wait() +{ + sigint_ev.clear_and_wait(); +} + + +} // namespace concurrency +} // namespace rsutils