From 048094accce2110432bf7d44c34acc17865cf85a Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 12 Apr 2016 16:49:32 +0100 Subject: target remote: Don't rely on immediate_quit (introduce quit handlers) remote.c is the last user of immediate_quit. It's relied on to immediately break the initial remote connection sync up, if the user does Ctrl-C, assuming that was because the target isn't responding. At that stage, since the connection isn't synced yet, disconnecting is the only safe thing to do. This commit reworks that, to not rely on throwing from the SIGINT signal handler. So, this commit: - Introduces the concept of a "quit handler". This is used to override what does the QUIT macro do when the quit flag is set. - Makes the "struct serial" reachar / write code call QUIT in the partial read/write loops, so the current quit handler is invoked whenever a serial->read_prim / serial->write_prim returns EINTR. - Makes the "struct serial" reachar / write code call interruptible_select instead of gdb_select, so that QUITs are detected in a race-free manner. - Stops remote.c from setting immediate_quit during the initial connection. - Instead, we install a custom quit handler whenever we're calling into the serial code. This custom quit handler knows to immediately throw a quit when we're in the initial connection setup, and otherwise defer handling the quit/Ctrl-C request to later, when we're safely out of a packet command/response sequence. This also is what is now responsible for handling "double Ctrl-C because target connection is stuck/wedged." - remote.c no longer installs a specialized SIGINT handlers, and instead re-uses the quit flag. Since we want to rely on the QUIT macro, the SIGINT handler must also set the quit. And the easiest is just to not install custom SIGINT handler in remote.c. Let the standard SIGINT handler do its job of setting the quit flag. Centralizing SIGINT handlers seems like a good thing to me, anyway. gdb/ChangeLog: 2016-04-12 Pedro Alves * defs.h (quit_handler_ftype, quit_handler) (make_cleanup_override_quit_handler, default_quit_handler): New. (QUIT): Adjust comments. * event-top.c (default_quit_handler): New function. (quit_handler): New global. (struct quit_handler_cleanup_data): New. (restore_quit_handler, restore_quit_handler_dtor) (make_cleanup_override_quit_handler): New. (async_request_quit): Call QUIT. * remote.c (struct remote_state) : New field. (async_sigint_remote_twice_token, async_sigint_remote_token): Delete. (remote_close): Update comments. (remote_start_remote): Don't set immediate_quit. Set starting_up earlier. (remote_serial_quit_handler, remote_unpush_and_throw): New functions. (remote_open_1): Clear got_ctrlc_during_io. Set remote_async_terminal_ours_p unconditionally. (async_initialize_sigint_signal_handler) (async_handle_remote_sigint, async_handle_remote_sigint_twice) (remote_check_pending_interrupt, async_remote_interrupt) (async_remote_interrupt_twice) (async_cleanup_sigint_signal_handler, ofunc) (sync_remote_interrupt, sync_remote_interrupt_twice): Delete. (remote_terminal_inferior, remote_terminal_ours): Remove async checks. (remote_wait_as): Don't install a SIGINT handler in sync mode. (readchar, remote_serial_write): Override the quit handler with remote_serial_quit_handler. (getpkt_or_notif_sane_1): Don't call QUIT. (initialize_remote_ops): Don't install remote_check_pending_interrupt. (_initialize_remote): Don't create async_sigint_remote_token and async_sigint_remote_twice_token. * ser-base.c (ser_base_wait_for): Call QUIT and use interruptible_select. (ser_base_write): Call QUIT. * ser-go32.c (dos_readchar, dos_write): Call QUIT. * ser-unix.c (wait_for): Don't use VTIME. Always take the gdb_select path, but call QUIT and interruptible_select. * utils.c (maybe_quit): Call the current quit handler. Don't call target_check_pending_interrupt. (defaulted_query, prompt_for_continue): Override the quit handler with the default quit handler. --- gdb/defs.h | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'gdb/defs.h') diff --git a/gdb/defs.h b/gdb/defs.h index 006f660..83e4e11 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -145,6 +145,34 @@ extern int check_quit_flag (void); /* * Set the quit flag. */ extern void set_quit_flag (void); +/* The current quit handler (and its type). This is called from the + QUIT macro. See default_quit_handler below for default behavior. + Parts of GDB temporarily override this to e.g., completely suppress + Ctrl-C because it would not be safe to throw. E.g., normally, you + wouldn't want to quit between a RSP command and its response, as + that would break the communication with the target, but you may + still want to intercept the Ctrl-C and offer to disconnect if the + user presses Ctrl-C multiple times while the target is stuck + waiting for the wedged remote stub. */ +typedef void (quit_handler_ftype) (void); +extern quit_handler_ftype *quit_handler; + +/* Override the current quit handler. Sets NEW_QUIT_HANDLER as + current quit handler, and installs a cleanup that when run restores + the previous quit handler. */ +struct cleanup * + make_cleanup_override_quit_handler (quit_handler_ftype *new_quit_handler); + +/* The default quit handler. Checks whether Ctrl-C was pressed, and + if so: + + - If GDB owns the terminal, throws a quit exception. + + - If GDB does not own the terminal, forwards the Ctrl-C to the + target. +*/ +extern void default_quit_handler (void); + /* Flag that function quit should call quit_force. */ extern volatile int sync_quit_force_run; @@ -156,10 +184,8 @@ extern void quit (void); extern void maybe_quit (void); -/* Check whether a Ctrl-C was typed, and if so, call quit. The target - is given a chance to process the Ctrl-C. E.g., it may detect that - repeated Ctrl-C requests were issued, and choose to close the - connection. */ +/* Check whether a Ctrl-C was typed, and if so, call the current quit + handler. */ #define QUIT maybe_quit () /* Set the serial event associated with the quit flag. */ -- cgit v1.1