Pass Ctrl-C to the target in target_terminal_inferior
authorPedro Alves <palves@redhat.com>
Tue, 12 Apr 2016 15:49:31 +0000 (16:49 +0100)
committerPedro Alves <palves@redhat.com>
Tue, 12 Apr 2016 15:57:10 +0000 (16:57 +0100)
If the user presses Ctrl-C immediately before target_terminal_inferior
is called and the target is resumed, instead of after, the Ctrl-C ends
up pending in the quit flag until the target next stops.

remote.c has this bit to handle this:

      if (!target_is_async_p ())
{
  ofunc = signal (SIGINT, sync_remote_interrupt);
  /* If the user hit C-c before this packet, or between packets,
     pretend that it was hit right here.  */
  if (check_quit_flag ())
    sync_remote_interrupt (SIGINT);
}

But that's only reachable if async is off, while async is on by
default nowadays.  It's also obviously not reacheable on native
targets.

This patch generalizes that to all targets.

We can't remove that remote.c bit yet, until we get rid of the sync
SIGINT handler though.  That'll be done later in the series.

gdb/ChangeLog:
2016-04-12  Pedro Alves  <palves@redhat.com>

* remote.c (remote_pass_ctrlc): New function.
(init_remote_ops): Install it.
* target.c (target_terminal_inferior): Pass pending Ctrl-C to the
target.
(target_pass_ctrlc, default_target_pass_ctrlc): New functions.
* target.h (struct target_ops) <to_pass_ctrlc>: New method.
(target_pass_ctrlc, default_target_pass_ctrlc): New declarations.
* target-delegates.c: Regenerate.

gdb/ChangeLog
gdb/remote.c
gdb/target-delegates.c
gdb/target.c
gdb/target.h

index 2a05df21525cc9979c847c38a9b565f1a29f2d63..ac6c2819df25ce6b3355170f674a9fda0a308ab7 100644 (file)
@@ -1,3 +1,14 @@
+2016-04-12  Pedro Alves  <palves@redhat.com>
+
+       * remote.c (remote_pass_ctrlc): New function.
+       (init_remote_ops): Install it.
+       * target.c (target_terminal_inferior): Pass pending Ctrl-C to the
+       target.
+       (target_pass_ctrlc, default_target_pass_ctrlc): New functions.
+       * target.h (struct target_ops) <to_pass_ctrlc>: New method.
+       (target_pass_ctrlc, default_target_pass_ctrlc): New declarations.
+       * target-delegates.c: Regenerate.
+
 2016-04-12  Pedro Alves  <palves@redhat.com>
 
        * infcmd.c (interrupt_target_1): Call target_stop is in non-stop
index 1bd2bcfe29660bd36617f289f2facc3a4a4c573a..0b2d25fde37729832228cc5f3f417d5ebfe7de4a 100644 (file)
@@ -5875,6 +5875,27 @@ remote_interrupt (struct target_ops *self, ptid_t ptid)
     remote_interrupt_as ();
 }
 
+/* Implement the to_pass_ctrlc function for the remote targets.  */
+
+static void
+remote_pass_ctrlc (struct target_ops *self)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_pass_ctrlc called\n");
+
+  /* If we're starting up, we're not fully synced yet.  Quit
+     immediately.  */
+  if (rs->starting_up)
+    quit ();
+  /* If ^C has already been sent once, offer to disconnect.  */
+  else if (rs->ctrlc_pending_p)
+    interrupt_query ();
+  else
+    target_interrupt (inferior_ptid);
+}
+
 /* Ask the user what to do when an interrupt is received.  */
 
 static void
@@ -13056,6 +13077,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_pass_ctrlc = remote_pass_ctrlc;
   remote_ops.to_check_pending_interrupt = remote_check_pending_interrupt;
   remote_ops.to_xfer_partial = remote_xfer_partial;
   remote_ops.to_rcmd = remote_rcmd;
index d23bc759e5a777a034488b2654e6f7d146272189..640803a34024868860b5a33f9dca5dfc7ebb9110 100644 (file)
@@ -1607,6 +1607,23 @@ debug_interrupt (struct target_ops *self, ptid_t arg1)
   fputs_unfiltered (")\n", gdb_stdlog);
 }
 
+static void
+delegate_pass_ctrlc (struct target_ops *self)
+{
+  self = self->beneath;
+  self->to_pass_ctrlc (self);
+}
+
+static void
+debug_pass_ctrlc (struct target_ops *self)
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->to_pass_ctrlc (...)\n", debug_target.to_shortname);
+  debug_target.to_pass_ctrlc (&debug_target);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->to_pass_ctrlc (", debug_target.to_shortname);
+  target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (")\n", gdb_stdlog);
+}
+
 static void
 delegate_check_pending_interrupt (struct target_ops *self)
 {
@@ -4194,6 +4211,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_pass_ctrlc == NULL)
+    ops->to_pass_ctrlc = delegate_pass_ctrlc;
   if (ops->to_check_pending_interrupt == NULL)
     ops->to_check_pending_interrupt = delegate_check_pending_interrupt;
   if (ops->to_rcmd == NULL)
@@ -4442,6 +4461,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_pass_ctrlc = default_target_pass_ctrlc;
   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;
@@ -4598,6 +4618,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_pass_ctrlc = debug_pass_ctrlc;
   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;
index ac66a3a8993407219dddfa59318df78b5d83cd39..d580983c4fa6b4ded042fe63799fa3c1176aae8c 100644 (file)
@@ -491,6 +491,11 @@ target_terminal_inferior (void)
      inferior's terminal modes.  */
   (*current_target.to_terminal_inferior) (&current_target);
   terminal_state = terminal_is_inferior;
+
+  /* If the user hit C-c before, pretend that it was hit right
+     here.  */
+  if (check_quit_flag ())
+    target_pass_ctrlc ();
 }
 
 /* See target.h.  */
@@ -3359,6 +3364,22 @@ target_interrupt (ptid_t ptid)
 
 /* See target.h.  */
 
+void
+target_pass_ctrlc (void)
+{
+  (*current_target.to_pass_ctrlc) (&current_target);
+}
+
+/* See target.h.  */
+
+void
+default_target_pass_ctrlc (struct target_ops *ops)
+{
+  target_interrupt (inferior_ptid);
+}
+
+/* See target.h.  */
+
 void
 target_check_pending_interrupt (void)
 {
index 26c857938e5e7a0fbe1e5adaff2bd05ca6b61c69..00625fec63c4f73d08c33eafb2839953143b5f62 100644 (file)
@@ -645,6 +645,8 @@ struct target_ops
       TARGET_DEFAULT_IGNORE ();
     void (*to_interrupt) (struct target_ops *, ptid_t)
       TARGET_DEFAULT_IGNORE ();
+    void (*to_pass_ctrlc) (struct target_ops *)
+      TARGET_DEFAULT_FUNC (default_target_pass_ctrlc);
     void (*to_check_pending_interrupt) (struct target_ops *)
       TARGET_DEFAULT_IGNORE ();
     void (*to_rcmd) (struct target_ops *,
@@ -1716,6 +1718,17 @@ extern void target_stop (ptid_t ptid);
 
 extern void target_interrupt (ptid_t ptid);
 
+/* Pass a ^C, as determined to have been pressed by checking the quit
+   flag, to the target.  Normally calls target_interrupt, but remote
+   targets may take the opportunity to detect the remote side is not
+   responding and offer to disconnect.  */
+
+extern void target_pass_ctrlc (void);
+
+/* The default target_ops::to_pass_ctrlc implementation.  Simply calls
+   target_interrupt.  */
+extern void default_target_pass_ctrlc (struct target_ops *ops);
+
 /* 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