8 #define SCARAB_API_EXPORTS 35 LOGGER( slog,
"signal_handler" );
37 int signal_handler::s_ref_count = 0;
39 bool signal_handler::s_exited =
false;
42 bool signal_handler::s_handling_sig_abrt =
false;
43 bool signal_handler::s_handling_sig_term =
false;
44 bool signal_handler::s_handling_sig_int =
false;
45 bool signal_handler::s_handling_sig_quit =
false;
48 struct sigaction signal_handler::s_old_sig_abrt_action;
49 struct sigaction signal_handler::s_old_sig_term_action;
50 struct sigaction signal_handler::s_old_sig_int_action;
51 struct sigaction signal_handler::s_old_sig_quit_action;
53 signal_handler::handler_t signal_handler::s_old_sig_abrt_handler = SIG_DFL;
54 signal_handler::handler_t signal_handler::s_old_sig_term_handler = SIG_DFL;
55 signal_handler::handler_t signal_handler::s_old_sig_int_handler = SIG_DFL;
56 signal_handler::handler_t signal_handler::s_old_sig_quit_handler = SIG_DFL;
65 ++signal_handler::s_ref_count;
73 --signal_handler::s_ref_count;
74 if( signal_handler::s_ref_count == 0 )
82 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
83 s_cancelers.insert( std::make_pair(a_cancelable.get(),
cancelable_wptr_t(a_cancelable) ) );
89 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
90 s_cancelers.erase( a_cancelable.get() );
96 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
97 s_cancelers.erase( a_cancelable );
103 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
106 LOGGER( slog_constr,
"signal_handler handle_signals" );
108 LDEBUG( slog_constr,
"Taking over signal handling for SIGABRT, SIGTERM, SIGINT, and SIGQUIT" );
110 #ifndef _WIN32 // on a POSIX system we use sigaction 112 struct sigaction t_exit_error_action, t_exit_success_action;
115 sigemptyset(&t_exit_error_action.sa_mask);
116 t_exit_error_action.sa_flags = 0;
119 sigemptyset(&t_exit_success_action.sa_mask);
120 t_exit_success_action.sa_flags = 0;
123 if( ! s_handling_sig_abrt && sigaction( SIGABRT, &t_exit_error_action, &s_old_sig_abrt_action ) != 0 )
125 LWARN( slog_constr,
"Unable to setup handling of SIGABRT: abort() and unhandled exceptions will result in an unclean exit" );
129 LTRACE( slog_constr,
"Handling SIGABRT (abort() and unhandled exceptions)" );
130 s_handling_sig_abrt =
true;
134 if( ! s_handling_sig_term && sigaction( SIGTERM, &t_exit_error_action, &s_old_sig_term_action ) != 0 )
136 LWARN( slog_constr,
"Unable to setup handling of SIGTERM: SIGTERM will result in an unclean exit" );
140 LTRACE( slog_constr,
"Handling SIGTERM" );
141 s_handling_sig_term =
true;
145 if( ! s_handling_sig_int && sigaction( SIGINT, &t_exit_success_action, &s_old_sig_int_action ) != 0 )
147 LWARN( slog_constr,
"Unable to setup handling of SIGINT: ctrl-c cancellation will result in an unclean exit" );
151 LTRACE( slog_constr,
"Handling SIGINT (ctrl-c)" );
152 s_handling_sig_int =
true;
156 if( ! s_handling_sig_quit && sigaction( SIGQUIT, &t_exit_success_action, &s_old_sig_quit_action ) != 0 )
158 LWARN( slog_constr,
"Unable to setup handling of SIGQUIT: ctrl-\\ cancellation will result in an unclean exit" );
162 LTRACE( slog_constr,
"Handling SIGQUIT (ctrl-\\)" );
163 s_handling_sig_quit =
true;
166 if( signal(SIGPIPE, SIG_IGN) == SIG_ERR )
168 throw error() <<
"Unable to ignore SIGPIPE\n";
171 #else // _WIN32; on a Windows system we use std::signal 174 if( ! s_handling_sig_abrt )
177 if( t_sig_ret == SIG_ERR )
179 LWARN( slog_constr,
"Unable to setup handling of SIGABRT: abort() and unhandled exceptions will result in an unclean exit" );
183 s_handling_sig_abrt =
true;
184 s_old_sig_abrt_handler = t_sig_ret;
187 if( s_handling_sig_abrt )
LTRACE( slog_constr,
"Handling SIGABRT (abort() and unhandled exceptions)" );
191 if( ! s_handling_sig_term )
194 if( t_sig_ret == SIG_ERR )
196 LWARN( slog_constr,
"Unable to setup handling of SIGTERM: SIGTERM will result in an unclean exit" );
200 s_handling_sig_term =
true;
201 s_old_sig_abrt_handler = t_sig_ret;
204 if( s_handling_sig_term )
LTRACE( slog_constr,
"Handling SIGTERM" );
207 if( ! s_handling_sig_int )
210 if( t_sig_ret == SIG_ERR )
212 LWARN( slog_constr,
"Unable to setup handling of SIGINT: ctrl-c cancellation will result in an unclean exit" );
216 s_handling_sig_int =
true;
217 s_old_sig_abrt_handler = t_sig_ret;
220 if( s_handling_sig_int )
LTRACE( slog_constr,
"Handling SIGINT (ctrl-c))" );
228 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
230 LDEBUG( slog,
"Returning signal handling for SIGABRT, SIGTERM, SIGINT, and SIGQUIT" );
234 if( s_handling_sig_abrt && sigaction( SIGABRT, &s_old_sig_abrt_action,
nullptr ) != 0 )
236 LWARN( slog,
"Unable to switch SIGABRT to previous handler" );
240 s_handling_sig_abrt =
false;
243 if( s_handling_sig_term && sigaction( SIGTERM, &s_old_sig_term_action,
nullptr ) != 0 )
245 LWARN( slog,
"Unable to switch SIGTERM to previous handler" );
249 s_handling_sig_term =
false;
252 if( s_handling_sig_int && sigaction( SIGINT, &s_old_sig_int_action,
nullptr ) != 0 )
254 LWARN( slog,
"Unable to switch SIGINT to previous handler" );
258 s_handling_sig_int =
false;
261 if( s_handling_sig_quit && sigaction( SIGQUIT, &s_old_sig_quit_action,
nullptr ) != 0 )
263 LWARN( slog,
"Unable to switch SIGQUIT to previous handler" );
267 s_handling_sig_quit =
false;
272 if( s_handling_sig_abrt && signal( SIGABRT, s_old_sig_abrt_handler ) == SIG_ERR )
274 LWARN( slog,
"Unable to switch SIGABRT to previous handler" );
278 s_handling_sig_abrt =
false;
281 if( s_handling_sig_term && signal( SIGTERM, s_old_sig_term_handler ) == SIG_ERR )
283 LWARN( slog,
"Unable to switch SIGTERM to previous handler" );
287 s_handling_sig_term =
false;
290 if( s_handling_sig_int && signal( SIGINT, s_old_sig_int_handler ) == SIG_ERR )
292 LWARN( slog,
"Unable to switch SIGINT to previous handler" );
296 s_handling_sig_int =
false;
305 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
307 bool t_is_handled =
false;
311 if( s_handling_sig_abrt) t_is_handled =
true;
314 if( s_handling_sig_term) t_is_handled =
true;
317 if( s_handling_sig_int) t_is_handled =
true;
321 if( s_handling_sig_quit) t_is_handled =
true;
332 LDEBUG( slog,
"Resetting signal_handler" );
333 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
350 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
351 LERROR( slog,
"Handling signal <" << a_sig <<
"> as an error condition; return code: " <<
RETURN_ERROR );
358 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
366 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
367 print_current_exception(
false );
370 print_stack_trace(
false );
372 std::cerr <<
"Exiting abruptly" << std::endl;
373 std::_Exit( a_code );
378 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
380 s_return_code = a_code;
381 print_current_exception(
true );
384 print_stack_trace(
true );
386 cancel_all( a_code );
395 if(
auto t_exc_ptr = std::current_exception() )
400 if( a_use_logging ) {
LDEBUG( slog,
"Rethrowing current exception" ); }
401 else { std::cerr <<
"Rethrowing current exception" << std::endl; }
402 std::rethrow_exception( t_exc_ptr );
404 catch(
const std::exception& e ) {
405 if( a_use_logging ) {
LERROR( slog,
"Caught unhandled exception. what(): " << e.what() ); }
406 else { std::cerr <<
"Caught unhandled exception. what(): " << e.what() << std::endl; }
409 if( a_use_logging )
LERROR( slog,
"Caught unknown (non-std::exception) & unhandled exception." )
410 else { std::cerr <<
"Caught unknown (non-std::exception) & unhandled exception." << std::endl; }
419 #ifndef _WIN32 // stack trace printing not implemented for windows 420 void* t_bt_array[50];
421 int t_size = backtrace( t_bt_array, 50 );
423 if( a_use_logging ) {
LERROR( slog,
"Backtrace returned " << t_size <<
" frames\n" ); }
424 else { std::cerr <<
"Backtrace returned " << t_size <<
" frames\n" << std::endl; }
426 char** t_messages = backtrace_symbols( t_bt_array, t_size );
428 std::stringstream t_bt_str;
429 for(
int i = 0; i < t_size && t_messages !=
nullptr; ++i )
431 t_bt_str <<
"[bt]: (" << i <<
") " << t_messages[i] <<
'\n';
433 if( a_use_logging ) {
LERROR( slog,
"Backtrace:\n" << t_bt_str.str() ); }
434 else { std::cerr <<
"Backtrace:\n" << t_bt_str.str() << std::endl; }
443 std::unique_lock< std::recursive_mutex > t_lock( s_mutex );
444 LDEBUG( slog,
"Canceling all cancelables" );
446 while( ! s_cancelers.empty() )
448 auto t_canceler_it = s_cancelers.begin();
449 if( ! t_canceler_it->second.expired() )
451 t_canceler_it->second.lock()->cancel( a_code );
453 s_cancelers.erase( t_canceler_it );
454 std::this_thread::sleep_for( std::chrono::seconds(1) );
458 ExitProcess( a_code );
std::weak_ptr< cancelable > cancelable_wptr_t
static void terminate(int a_code) noexcept
Main terminate function – does not cleanup memory or threads.
static bool is_handling(int a_signal)
Check if a signal is handled.
static void add_cancelable(std::shared_ptr< cancelable > a_cancelable)
Static version: add a cancelable object.
static cancelers s_cancelers
std::map< cancelable *, cancelable_wptr_t > cancelers
LOGGER(mtlog, "authentication")
static std::recursive_mutex s_mutex
Contains the logger class and macros, based on Kasper's KLogger class.
static void print_current_exception(bool a_use_logging)
Prints the current exception, if there is one.
static void cancel_all(int a_code)
Asynchronous call to cancel all cancelables with the given exit code.
static void exit(int a_code)
Main exit function – cleanly exits.
static void handle_exit_error(int a_sig)
Handler for error signals – cleanly exits.
Base class for a cancelable object (i.e. an object that can be canceled by scarab::signal_handler or ...
static void remove_cancelable(std::shared_ptr< cancelable > a_cancelable)
Static version: remove a cancelable object.
static void unhandle_signals()
Stop handling signals.
static void reset()
Remove all cancelables and signal handling.
static void handle_exit_success(int a_sig)
Handler for success signals – cleanly exits.
virtual ~signal_handler()
static void handle_terminate() noexcept
Handler for std::terminate – does not cleanup memory or threads.
static void print_stack_trace(bool a_use_logging)
Prints the stack trace.
static void handle_signals()
Start handling signals.