summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog23
-rw-r--r--gdb/defs.h20
-rw-r--r--gdb/event-loop.c16
-rw-r--r--gdb/event-loop.h9
-rw-r--r--gdb/remote.c40
-rw-r--r--gdb/target-delegates.c26
-rw-r--r--gdb/target.c8
-rw-r--r--gdb/target.h10
-rw-r--r--gdb/utils.c12
9 files changed, 143 insertions, 21 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 49f491d9681..a8735a28b84 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):
diff --git a/gdb/defs.h b/gdb/defs.h
index f4951abb223..03f7e8a0503 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -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 df569be2c09..aee37bb6388 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 6ae4013b066..598d0da2e0e 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 f2968ebdb27..e01927719b0 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 892cf9d0805..ddcad9426d6 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 a0a55d909d7..5ce7f4675f6 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3309,6 +3309,14 @@ target_interrupt (ptid_t ptid)
(*current_target.to_interrupt) (&current_target, ptid);
}
+/* See target.h. */
+
+void
+target_check_pending_interrupt (void)
+{
+ (*current_target.to_check_pending_interrupt) (&current_target);
+}
+
/* See target/target.h. */
void
diff --git a/gdb/target.h b/gdb/target.h
index 1fdaf00ac22..37e4edbddcc 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 a3c707658a9..3a05680161e 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. */