From f32bcfef42a0b355b47a4c0d4d5a782d0eb7b628 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Fri, 1 Apr 2022 10:09:19 -0500 Subject: [PATCH] compositor: Use sigaction to trap SIGINT signalfd interacts badly with gdb's signal trapping - when hitting ctrl-c in a debugger attached to weston, weston will receive the signal. This results in weston exiting cleanly when the intent was to use gdb to interfere with its operation. Trapping SIGINT was introduced in commit 50dc6989 which ensured we would call wl_display_terminate() on SIGINT or SIGTERM to clean up our socket. Killing weston with SIGINT is quite common for several developers, so it's important to preserve this clean shutdown behaviour, so we can't naively stop trapping SIGINT entirely. Instead, use the sigaction() function to trap SIGINT, and have the SIGINT handler send weston SIGUSR2 (SIGUSR1 is already used by xwayland). SIGUSR2 can be trapped in the proper wayland way via wl_event_loop_add_signal(). This way we can properly break our event loop and clean up on SIGINT, but we can also have gdb intercept SIGINT. There are other ways around this, but I'm hoping this one allows people to continue using ctrl-c to stop weston, and doesn't require additional project specific gdb knowledge. Signed-off-by: Derek Foreman --- compositor/main.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/compositor/main.c b/compositor/main.c index 62a7c48b..cba8dfd5 100644 --- a/compositor/main.c +++ b/compositor/main.c @@ -3175,6 +3175,12 @@ weston_log_subscribe_to_scopes(struct weston_log_context *log_ctx, weston_log_setup_scopes(log_ctx, flight_rec, flight_rec_scopes); } +static void +sigint_helper(int sig) +{ + raise(SIGUSR2); +} + WL_EXPORT int wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data) { @@ -3211,6 +3217,7 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data) struct weston_log_subscriber *logger = NULL; struct weston_log_subscriber *flight_rec = NULL; sigset_t mask; + struct sigaction action; bool wait_for_debugger = false; struct wl_protocol_logger *protologger = NULL; @@ -3301,13 +3308,27 @@ wet_main(int argc, char *argv[], const struct weston_testsuite_data *test_data) loop = wl_display_get_event_loop(display); signals[0] = wl_event_loop_add_signal(loop, SIGTERM, on_term_signal, display); - signals[1] = wl_event_loop_add_signal(loop, SIGINT, on_term_signal, + signals[1] = wl_event_loop_add_signal(loop, SIGUSR2, on_term_signal, display); wl_list_init(&wet.child_process_list); signals[2] = wl_event_loop_add_signal(loop, SIGCHLD, sigchld_handler, &wet); + /* When debugging weston, if use wl_event_loop_add_signal() to catch + * SIGINT, the debugger can't catch it, and attempting to stop + * weston from within the debugger results in weston exiting + * cleanly. + * + * Instead, use the sigaction() function, which sets up the signal + * in a way that gdb can successfully catch, but have the handler + * for SIGINT send SIGUSR2 (xwayland uses SIGUSR1), which we catch + * via wl_event_loop_add_signal(). + */ + action.sa_handler = sigint_helper; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + sigaction(SIGINT, &action, NULL); if (!signals[0] || !signals[1] || !signals[2]) goto out_signals;