+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):
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
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
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
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
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
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;
fputs_unfiltered (")\n", gdb_stdlog);
}
+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)
{
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)
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;
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;
(*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
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);
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. */
#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 ();
+}
+
\f
/* Called when a memory allocation fails, with the number of bytes of
memory requested in SIZE. */