diff options
-rw-r--r-- | gdb/ChangeLog | 23 | ||||
-rw-r--r-- | gdb/defs.h | 20 | ||||
-rw-r--r-- | gdb/event-loop.c | 16 | ||||
-rw-r--r-- | gdb/event-loop.h | 9 | ||||
-rw-r--r-- | gdb/remote.c | 40 | ||||
-rw-r--r-- | gdb/target-delegates.c | 26 | ||||
-rw-r--r-- | gdb/target.c | 8 | ||||
-rw-r--r-- | gdb/target.h | 10 | ||||
-rw-r--r-- | gdb/utils.c | 12 |
9 files changed, 143 insertions, 21 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 49f491d..a8735a2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,26 @@ +2015-08-24 Pedro Alves <palves@redhat.com> + + * defs.h (maybe_quit): Declare. + (QUIT): Now calls maybe_quit. + * event-loop.c (clear_async_signal_handler) + (async_signal_handler_is_marked): New functions. + * event-loop.h (async_signal_handler_is_marked) + (clear_async_signal_handler): New declarations. + * remote.c (remote_check_pending_interrupt): New function. + (interrupt_query): Use make_cleanup_restore_target_terminal. No + longer check whether the target is async. If waiting for a stop + reply, and a Ctrl-C as been sent to the target, offer to + disconnect, and throw TARGET_CLOSE_ERROR instead of a quit. + Otherwise do not disconnect and throw a quit. + (_initialize_remote): Install remote_check_pending_interrupt as + to_check_pending_interrupt. + * target.c (target_check_pending_interrupt): New function. + * target.h (struct target_ops) <to_check_pending_interrupt>: New + field. + (target_check_pending_interrupt): New declaration. + * utils.c (maybe_quit): New function. + * target-delegates.c: Regenerate. + 2015-08-25 Yao Qi <yao.qi@linaro.org> * nat/aarch64-linux-hw-point.c (debug_reg_change_callback): @@ -149,17 +149,15 @@ extern int immediate_quit; extern void quit (void); -/* FIXME: cagney/2000-03-13: It has been suggested that the peformance - benefits of having a ``QUIT'' macro rather than a function are - marginal. If the overhead of a QUIT function call is proving - significant then its calling frequency should probably be reduced - [kingdon]. A profile analyzing the current situtation is - needed. */ - -#define QUIT { \ - if (check_quit_flag () || sync_quit_force_run) quit (); \ - if (deprecated_interactive_hook) deprecated_interactive_hook (); \ -} +/* Helper for the QUIT macro. */ + +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. */ +#define QUIT maybe_quit () /* * Languages represented in the symbol table and elsewhere. This should probably be in language.h, but since enum's can't diff --git a/gdb/event-loop.c b/gdb/event-loop.c index df569be..aee37bb 100644 --- a/gdb/event-loop.c +++ b/gdb/event-loop.c @@ -908,6 +908,22 @@ mark_async_signal_handler (async_signal_handler * async_handler_ptr) async_handler_ptr->ready = 1; } +/* See event-loop.h. */ + +void +clear_async_signal_handler (async_signal_handler *async_handler_ptr) +{ + async_handler_ptr->ready = 0; +} + +/* See event-loop.h. */ + +int +async_signal_handler_is_marked (async_signal_handler *async_handler_ptr) +{ + return async_handler_ptr->ready; +} + /* Call all the handlers that are ready. Returns true if any was indeed ready. */ static int diff --git a/gdb/event-loop.h b/gdb/event-loop.h index 6ae4013..598d0da 100644 --- a/gdb/event-loop.h +++ b/gdb/event-loop.h @@ -102,6 +102,15 @@ void call_async_signal_handler (struct async_signal_handler *handler); below, with IMMEDIATE_P == 0. */ void mark_async_signal_handler (struct async_signal_handler *handler); +/* Returns true if HANDLER is marked ready. */ + +extern int + async_signal_handler_is_marked (struct async_signal_handler *handler); + +/* Mark HANDLER as NOT ready. */ + +extern void clear_async_signal_handler (struct async_signal_handler *handler); + /* Wrapper for the body of signal handlers. Call this function from any SIGINT handler which needs to access GDB data structures or escape via longjmp. If IMMEDIATE_P is set, this triggers either diff --git a/gdb/remote.c b/gdb/remote.c index f2968eb..e019277 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -5281,6 +5281,20 @@ async_handle_remote_sigint_twice (int sig) gdb_call_async_signal_handler (async_sigint_remote_twice_token, 0); } +/* Implementation of to_check_pending_interrupt. */ + +static void +remote_check_pending_interrupt (struct target_ops *self) +{ + struct async_signal_handler *token = async_sigint_remote_twice_token; + + if (async_signal_handler_is_marked (token)) + { + clear_async_signal_handler (token); + call_async_signal_handler (token); + } +} + /* Perform the real interruption of the target execution, in response to a ^C. */ static void @@ -5453,24 +5467,29 @@ remote_interrupt (struct target_ops *self, ptid_t ptid) static void interrupt_query (void) { + struct remote_state *rs = get_remote_state (); + struct cleanup *old_chain; + + old_chain = make_cleanup_restore_target_terminal (); target_terminal_ours (); - if (target_is_async_p ()) - { - signal (SIGINT, handle_sigint); - quit (); - } - else + if (rs->waiting_for_stop_reply && rs->ctrlc_pending_p) { - if (query (_("Interrupted while waiting for the program.\n\ -Give up (and stop debugging it)? "))) + if (query (_("The target is not responding to interrupt requests.\n" + "Stop debugging it? "))) { remote_unpush_target (); - quit (); + throw_error (TARGET_CLOSE_ERROR, _("Disconnected from target.")); } } + else + { + if (query (_("Interrupted while waiting for the program.\n" + "Give up waiting? "))) + quit (); + } - target_terminal_inferior (); + do_cleanups (old_chain); } /* Enable/disable target terminal ownership. Most targets can use @@ -12530,6 +12549,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_get_ada_task_ptid = remote_get_ada_task_ptid; remote_ops.to_stop = remote_stop; remote_ops.to_interrupt = remote_interrupt; + remote_ops.to_check_pending_interrupt = remote_check_pending_interrupt; remote_ops.to_xfer_partial = remote_xfer_partial; remote_ops.to_rcmd = remote_rcmd; remote_ops.to_pid_to_exec_file = remote_pid_to_exec_file; diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c index 892cf9d..ddcad94 100644 --- a/gdb/target-delegates.c +++ b/gdb/target-delegates.c @@ -1561,6 +1561,28 @@ debug_interrupt (struct target_ops *self, ptid_t arg1) } static void +delegate_check_pending_interrupt (struct target_ops *self) +{ + self = self->beneath; + self->to_check_pending_interrupt (self); +} + +static void +tdefault_check_pending_interrupt (struct target_ops *self) +{ +} + +static void +debug_check_pending_interrupt (struct target_ops *self) +{ + fprintf_unfiltered (gdb_stdlog, "-> %s->to_check_pending_interrupt (...)\n", debug_target.to_shortname); + debug_target.to_check_pending_interrupt (&debug_target); + fprintf_unfiltered (gdb_stdlog, "<- %s->to_check_pending_interrupt (", debug_target.to_shortname); + target_debug_print_struct_target_ops_p (&debug_target); + fputs_unfiltered (")\n", gdb_stdlog); +} + +static void delegate_rcmd (struct target_ops *self, const char *arg1, struct ui_file *arg2) { self = self->beneath; @@ -4042,6 +4064,8 @@ install_delegators (struct target_ops *ops) ops->to_stop = delegate_stop; if (ops->to_interrupt == NULL) ops->to_interrupt = delegate_interrupt; + if (ops->to_check_pending_interrupt == NULL) + ops->to_check_pending_interrupt = delegate_check_pending_interrupt; if (ops->to_rcmd == NULL) ops->to_rcmd = delegate_rcmd; if (ops->to_pid_to_exec_file == NULL) @@ -4280,6 +4304,7 @@ install_dummy_methods (struct target_ops *ops) ops->to_thread_name = tdefault_thread_name; ops->to_stop = tdefault_stop; ops->to_interrupt = tdefault_interrupt; + ops->to_check_pending_interrupt = tdefault_check_pending_interrupt; ops->to_rcmd = default_rcmd; ops->to_pid_to_exec_file = tdefault_pid_to_exec_file; ops->to_log_command = tdefault_log_command; @@ -4430,6 +4455,7 @@ init_debug_target (struct target_ops *ops) ops->to_thread_name = debug_thread_name; ops->to_stop = debug_stop; ops->to_interrupt = debug_interrupt; + ops->to_check_pending_interrupt = debug_check_pending_interrupt; ops->to_rcmd = debug_rcmd; ops->to_pid_to_exec_file = debug_pid_to_exec_file; ops->to_log_command = debug_log_command; diff --git a/gdb/target.c b/gdb/target.c index a0a55d9..5ce7f46 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -3309,6 +3309,14 @@ target_interrupt (ptid_t ptid) (*current_target.to_interrupt) (¤t_target, ptid); } +/* See target.h. */ + +void +target_check_pending_interrupt (void) +{ + (*current_target.to_check_pending_interrupt) (¤t_target); +} + /* See target/target.h. */ void diff --git a/gdb/target.h b/gdb/target.h index 1fdaf00..37e4edb 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -642,6 +642,8 @@ struct target_ops TARGET_DEFAULT_IGNORE (); void (*to_interrupt) (struct target_ops *, ptid_t) TARGET_DEFAULT_IGNORE (); + void (*to_check_pending_interrupt) (struct target_ops *) + TARGET_DEFAULT_IGNORE (); void (*to_rcmd) (struct target_ops *, const char *command, struct ui_file *output) TARGET_DEFAULT_FUNC (default_rcmd); @@ -1684,6 +1686,14 @@ extern void target_stop (ptid_t ptid); extern void target_interrupt (ptid_t ptid); +/* Some targets install their own SIGINT handler while the target is + running. This method is called from the QUIT macro to give such + targets a chance to process a Ctrl-C. The target may e.g., choose + to interrupt the (potentially) long running operation, or give up + waiting and disconnect. */ + +extern void target_check_pending_interrupt (void); + /* Send the specified COMMAND to the target's monitor (shell,interpreter) for execution. The result of the query is placed in OUTBUF. */ diff --git a/gdb/utils.c b/gdb/utils.c index a3c7076..3a05680 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1041,6 +1041,18 @@ quit (void) #endif } +/* See defs.h. */ + +void +maybe_quit (void) +{ + if (check_quit_flag () || sync_quit_force_run) + quit (); + if (deprecated_interactive_hook) + deprecated_interactive_hook (); + target_check_pending_interrupt (); +} + /* Called when a memory allocation fails, with the number of bytes of memory requested in SIZE. */ |