Patchwork [v3,12/17] Fix interrupt-noterm.exp on targets always in non-stop

login
register
mail settings
Submitter Pedro Alves
Date April 17, 2015, 10:45 a.m.
Message ID <1429267521-21047-13-git-send-email-palves@redhat.com>
Download mbox | patch
Permalink /patch/6291/
State New
Headers show

Comments

Pedro Alves - April 17, 2015, 10:45 a.m.
With "maint set target-non-stop on" we get:

 @@ -66,13 +66,16 @@ Continuing.
  interrupt
  (gdb) PASS: gdb.base/interrupt-noterm.exp: interrupt

 -Program received signal SIGINT, Interrupt.
 -PASS: gdb.base/interrupt-noterm.exp: inferior received SIGINT
 -testcase src/gdb/testsuite/gdb.base/interrupt-noterm.exp completed in 0 seconds
 +[process 12119] #1 stopped.
 +0x0000003615ebc6d0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:81
 +81     T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
 +FAIL: gdb.base/interrupt-noterm.exp: inferior received SIGINT (timeout)
 +testcase src/gdb/testsuite/gdb.base/interrupt-noterm.exp completed in 10 seconds

That is, we get "[$thread] #1 stopped" instead of SIGINT.

The issue is that we don't currently distinguish send
"interrupt/ctrl-c" to target terminal vs "stop/pause" thread well;
both cases go through "target_stop".

And then, the native Linux backend (linux-nat.c) implements
target_stop with SIGSTOP in non-stop mode, and SIGINT in all-stop
mode.  Since "maint set target-non-stop on" forces the backend to be
always running in non-stop mode, even though the user-visible behavior
is "set non-stop" is "off", "interrupt" causes a SIGSTOP instead of
the SIGINT the test expects.

Fix this by introducing a target_interrupt method to use in the
"interrupt/ctrl-c" case, so "set non-stop off" can always work the
same irrespective of "maint set target-non-stop on/off".  I'm
explictly considering changing the "set non-stop on" behavior as out
of scope here.

Most of the patch is an across-the-board rename of to_stop hook
implementations to to_interrupt.  The only targets where something
more than a rename is being done are linux-nat.c and remote.c, which
are the only targets that support async, and thus are the only ones
the core side calls target_stop on.

gdb/ChangeLog:
2015-04-17  Pedro Alves  <palves@redhat.com>

	* darwin-nat.c (darwin_stop): Rename to ...
	(darwin_interrupt): ... this.
	(_initialize_darwin_inferior): Adjust.
	* gnu-nat.c (gnu_stop): Delete.
	(gnu_thread_alive): Don't install gnu_stop.
	* inf-ptrace.c (inf_ptrace_stop): Rename to ...
	(inf_ptrace_interrupt): ... this.
	(inf_ptrace_target): Adjust.
	* infcmd.c (interrupt_target_1): Use target_interrupt instead of
	target_stop.
	* linux-nat (linux_nat_stop): Rename to ...
	(linux_nat_interrupt): ... this.
	(linux_nat_stop): Reimplement.
	(linux_nat_add_target): Install linux_nat_interrupt.
	* monitor.c (monitor_stop): Rename to ...
	(monitor_interrupt): ... this.
	(init_base_monitor_ops): Adjust.
	* nto-procfs.c (nto_interrupt_twice): Rename to ...
	(nto_handle_sigint_twice): ... this.
	(nto_interrupt): Rename to ...
	(nto_handle_sigint): ... this.  Call target_interrupt instead of
	target_stop.
	(procfs_wait, init_procfs_targets): Adjust.
	* procfs.c (procfs_target): Adjust.
	(procfs_stop): Rename to ...
	(procfs_interrupt): ... this.
	* remote-m32r-sdi.c (m32r_stop): Rename to ...
	(m32r_interrupt): ... this.
	(init_m32r_ops): Adjust.
	* remote-sim.c (gdbsim_stop_inferior): Rename to ...
	(gdbsim_interrupt_inferior): ... this.
	(gdbsim_stop): Rename to ...
	(gdbsim_interrupt): ... this.
	(gdbsim_cntrl_c): Adjust.
	(init_gdbsim_ops): Adjust.
	* remote.c (sync_remote_interrupt): Adjust comments.
	(remote_stop_as): Rename to ...
	(remote_interrupt_as): ... this.
	(remote_stop): Adjust comment.
	(remote_interrupt): New function.
	(init_remote_ops): Install remote_interrupt.
	* target.c (target_interrupt): New function.
	* target.h (struct target_ops) <to_interrupt>: New field.
	(target_interrupt): New declaration.
	* windows-nat.c (windows_stop): Rename to ...
	(windows_interrupt): ... this.
	* target-delegates.c: Regenerate.

v3, v2:

	- No changes.
---
 gdb/darwin-nat.c       |  6 +++---
 gdb/gnu-nat.c          |  7 -------
 gdb/inf-ptrace.c       |  6 +++---
 gdb/infcmd.c           |  2 +-
 gdb/linux-nat.c        | 12 +++++++++---
 gdb/monitor.c          |  4 ++--
 gdb/nto-procfs.c       | 14 +++++++-------
 gdb/procfs.c           |  4 ++--
 gdb/remote-m32r-sdi.c  |  6 +++---
 gdb/remote-sim.c       | 20 ++++++++++----------
 gdb/remote.c           | 44 +++++++++++++++++++++++++++++++++-----------
 gdb/target-delegates.c | 28 ++++++++++++++++++++++++++++
 gdb/target.c           | 12 ++++++++++++
 gdb/target.h           |  8 ++++++++
 gdb/windows-nat.c      |  6 +++---
 15 files changed, 124 insertions(+), 55 deletions(-)
Yao Qi - April 21, 2015, 11:40 a.m.
Pedro Alves <palves@redhat.com> writes:

> Most of the patch is an across-the-board rename of to_stop hook
> implementations to to_interrupt.  The only targets where something

except on gnu-nat.c,

> more than a rename is being done are linux-nat.c and remote.c, which
> are the only targets that support async, and thus are the only ones
> the core side calls target_stop on.
>
> gdb/ChangeLog:
> 2015-04-17  Pedro Alves  <palves@redhat.com>
>
> 	* darwin-nat.c (darwin_stop): Rename to ...
> 	(darwin_interrupt): ... this.
> 	(_initialize_darwin_inferior): Adjust.
> 	* gnu-nat.c (gnu_stop): Delete.
> 	(gnu_thread_alive): Don't install gnu_stop.
        ^^^^^^^^^^^^^^^^^ gnu_target

> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
> index d830773..4753634 100644
> --- a/gdb/gnu-nat.c
> +++ b/gdb/gnu-nat.c
> @@ -2271,12 +2271,6 @@ gnu_terminal_init (struct target_ops *self)
>    child_terminal_init_with_pgrp (gnu_current_inf->pid);
>  }
>  
> -static void
> -gnu_stop (struct target_ops *self, ptid_t ptid)
> -{
> -  error (_("to_stop target function not implemented"));
> -}
> -
>  static int
>  gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
>  {
> @@ -2686,7 +2680,6 @@ gnu_target (void)
>    t->to_mourn_inferior = gnu_mourn_inferior;
>    t->to_thread_alive = gnu_thread_alive;
>    t->to_pid_to_str = gnu_pid_to_str;
> -  t->to_stop = gnu_stop;
>  
>    return t;
>  }

Any reason you don't install to_interrupt for gnu-nat?
Pedro Alves - April 22, 2015, 8:03 p.m.
On 04/21/2015 12:40 PM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> Most of the patch is an across-the-board rename of to_stop hook
>> implementations to to_interrupt.  The only targets where something
> 
> except on gnu-nat.c,

Ah, yes.

> 
>> more than a rename is being done are linux-nat.c and remote.c, which
>> are the only targets that support async, and thus are the only ones
>> the core side calls target_stop on.
>>
>> gdb/ChangeLog:
>> 2015-04-17  Pedro Alves  <palves@redhat.com>
>>
>> 	* darwin-nat.c (darwin_stop): Rename to ...
>> 	(darwin_interrupt): ... this.
>> 	(_initialize_darwin_inferior): Adjust.
>> 	* gnu-nat.c (gnu_stop): Delete.
>> 	(gnu_thread_alive): Don't install gnu_stop.
>         ^^^^^^^^^^^^^^^^^ gnu_target

Whoops, fixed.

> 
>> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
>> index d830773..4753634 100644
>> --- a/gdb/gnu-nat.c
>> +++ b/gdb/gnu-nat.c
>> @@ -2271,12 +2271,6 @@ gnu_terminal_init (struct target_ops *self)
>>    child_terminal_init_with_pgrp (gnu_current_inf->pid);
>>  }
>>  
>> -static void
>> -gnu_stop (struct target_ops *self, ptid_t ptid)
>> -{
>> -  error (_("to_stop target function not implemented"));
>> -}
>> -
>>  static int
>>  gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
>>  {
>> @@ -2686,7 +2680,6 @@ gnu_target (void)
>>    t->to_mourn_inferior = gnu_mourn_inferior;
>>    t->to_thread_alive = gnu_thread_alive;
>>    t->to_pid_to_str = gnu_pid_to_str;
>> -  t->to_stop = gnu_stop;
>>  
>>    return t;
>>  }
> 
> Any reason you don't install to_interrupt for gnu-nat?

I'll sent the gnu-nat change as a separate patch, along with
the rationale.

Patch

diff --git a/gdb/darwin-nat.c b/gdb/darwin-nat.c
index e1acc05..30e968f 100644
--- a/gdb/darwin-nat.c
+++ b/gdb/darwin-nat.c
@@ -83,7 +83,7 @@ 
 #define PTRACE(CMD, PID, ADDR, SIG) \
  darwin_ptrace(#CMD, CMD, (PID), (ADDR), (SIG))
 
-static void darwin_stop (struct target_ops *self, ptid_t);
+static void darwin_interrupt (struct target_ops *self, ptid_t);
 
 static void darwin_resume_to (struct target_ops *ops, ptid_t ptid, int step,
                               enum gdb_signal signal);
@@ -1198,7 +1198,7 @@  darwin_wait_to (struct target_ops *ops,
 }
 
 static void
-darwin_stop (struct target_ops *self, ptid_t t)
+darwin_interrupt (struct target_ops *self, ptid_t t)
 {
   struct inferior *inf = current_inferior ();
 
@@ -2156,7 +2156,7 @@  _initialize_darwin_inferior (void)
   darwin_ops->to_wait = darwin_wait_to;
   darwin_ops->to_mourn_inferior = darwin_mourn_inferior;
   darwin_ops->to_kill = darwin_kill_inferior;
-  darwin_ops->to_stop = darwin_stop;
+  darwin_ops->to_interrupt = darwin_interrupt;
   darwin_ops->to_resume = darwin_resume_to;
   darwin_ops->to_thread_alive = darwin_thread_alive;
   darwin_ops->to_pid_to_str = darwin_pid_to_str;
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index d830773..4753634 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2271,12 +2271,6 @@  gnu_terminal_init (struct target_ops *self)
   child_terminal_init_with_pgrp (gnu_current_inf->pid);
 }
 
-static void
-gnu_stop (struct target_ops *self, ptid_t ptid)
-{
-  error (_("to_stop target function not implemented"));
-}
-
 static int
 gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
@@ -2686,7 +2680,6 @@  gnu_target (void)
   t->to_mourn_inferior = gnu_mourn_inferior;
   t->to_thread_alive = gnu_thread_alive;
   t->to_pid_to_str = gnu_pid_to_str;
-  t->to_stop = gnu_stop;
 
   return t;
 }
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index cd58dfb..17ba903 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -288,10 +288,10 @@  inf_ptrace_kill (struct target_ops *ops)
   target_mourn_inferior ();
 }
 
-/* Stop the inferior.  */
+/* Interrupt the inferior.  */
 
 static void
-inf_ptrace_stop (struct target_ops *self, ptid_t ptid)
+inf_ptrace_interrupt (struct target_ops *self, ptid_t ptid)
 {
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  Note that using a
@@ -686,7 +686,7 @@  inf_ptrace_target (void)
   t->to_mourn_inferior = inf_ptrace_mourn_inferior;
   t->to_thread_alive = inf_ptrace_thread_alive;
   t->to_pid_to_str = inf_ptrace_pid_to_str;
-  t->to_stop = inf_ptrace_stop;
+  t->to_interrupt = inf_ptrace_interrupt;
   t->to_xfer_partial = inf_ptrace_xfer_partial;
 #if defined (PT_IO) && defined (PIOD_READ_AUXV)
   t->to_auxv_parse = inf_ptrace_auxv_parse;
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 3505b1b..0a3c515 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2805,7 +2805,7 @@  interrupt_target_1 (int all_threads)
     ptid = minus_one_ptid;
   else
     ptid = inferior_ptid;
-  target_stop (ptid);
+  target_interrupt (ptid);
 
   /* Tag the thread as having been explicitly requested to stop, so
      other parts of gdb know not to resume this thread automatically,
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b449485..d6fd40d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4787,10 +4787,16 @@  linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 static void
 linux_nat_stop (struct target_ops *self, ptid_t ptid)
 {
-  if (target_is_non_stop_p ())
+  iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
+}
+
+static void
+linux_nat_interrupt (struct target_ops *self, ptid_t ptid)
+{
+  if (non_stop)
     iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
   else
-    linux_ops->to_stop (linux_ops, ptid);
+    linux_ops->to_interrupt (linux_ops, ptid);
 }
 
 static void
@@ -4894,8 +4900,8 @@  linux_nat_add_target (struct target_ops *t)
   super_close = t->to_close;
   t->to_close = linux_nat_close;
 
-  /* Methods for non-stop support.  */
   t->to_stop = linux_nat_stop;
+  t->to_interrupt = linux_nat_interrupt;
 
   t->to_supports_multi_process = linux_nat_supports_multi_process;
 
diff --git a/gdb/monitor.c b/gdb/monitor.c
index 548dae3..e47d479 100644
--- a/gdb/monitor.c
+++ b/gdb/monitor.c
@@ -2267,7 +2267,7 @@  monitor_load (struct target_ops *self, const char *args, int from_tty)
 }
 
 static void
-monitor_stop (struct target_ops *self, ptid_t ptid)
+monitor_interrupt (struct target_ops *self, ptid_t ptid)
 {
   monitor_debug ("MON stop\n");
   if ((current_monitor->flags & MO_SEND_BREAK_ON_STOP) != 0)
@@ -2375,7 +2375,7 @@  init_base_monitor_ops (void)
   monitor_ops.to_load = monitor_load;
   monitor_ops.to_create_inferior = monitor_create_inferior;
   monitor_ops.to_mourn_inferior = monitor_mourn_inferior;
-  monitor_ops.to_stop = monitor_stop;
+  monitor_ops.to_interrupt = monitor_interrupt;
   monitor_ops.to_rcmd = monitor_rcmd;
   monitor_ops.to_log_command = serial_log_command;
   monitor_ops.to_thread_alive = monitor_thread_alive;
diff --git a/gdb/nto-procfs.c b/gdb/nto-procfs.c
index 7312060..c318f19 100644
--- a/gdb/nto-procfs.c
+++ b/gdb/nto-procfs.c
@@ -692,20 +692,20 @@  Give up (and stop debugging it)? ")))
 
 /* The user typed ^C twice.  */
 static void
-nto_interrupt_twice (int signo)
+nto_handle_sigint_twice (int signo)
 {
   signal (signo, ofunc);
   interrupt_query ();
-  signal (signo, nto_interrupt_twice);
+  signal (signo, nto_handle_sigint_twice);
 }
 
 static void
-nto_interrupt (int signo)
+nto_handle_sigint (int signo)
 {
   /* If this doesn't work, try more severe steps.  */
-  signal (signo, nto_interrupt_twice);
+  signal (signo, nto_handle_sigint_twice);
 
-  target_stop (inferior_ptid);
+  target_interrupt (inferior_ptid);
 }
 
 static ptid_t
@@ -733,7 +733,7 @@  procfs_wait (struct target_ops *ops,
   devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
   while (!(status.flags & _DEBUG_FLAG_ISTOP))
     {
-      ofunc = (void (*)()) signal (SIGINT, nto_interrupt);
+      ofunc = (void (*)()) signal (SIGINT, nto_handle_sigint);
       sigwaitinfo (&set, &info);
       signal (SIGINT, ofunc);
       devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
@@ -1444,7 +1444,7 @@  init_procfs_targets (void)
   t->to_thread_alive = procfs_thread_alive;
   t->to_update_thread_list = procfs_update_thread_list;
   t->to_pid_to_str = procfs_pid_to_str;
-  t->to_stop = procfs_stop;
+  t->to_interrupt = procfs_interrupt;
   t->to_have_continuable_watchpoint = 1;
   t->to_extra_thread_info = nto_extra_thread_info;
 
diff --git a/gdb/procfs.c b/gdb/procfs.c
index b62539f..e540e2a 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -194,7 +194,7 @@  procfs_target (void)
   t->to_xfer_partial = procfs_xfer_partial;
   t->to_pass_signals = procfs_pass_signals;
   t->to_files_info = procfs_files_info;
-  t->to_stop = procfs_stop;
+  t->to_interrupt = procfs_interrupt;
 
   t->to_update_thread_list = procfs_update_thread_list;
   t->to_thread_alive = procfs_thread_alive;
@@ -4204,7 +4204,7 @@  procfs_files_info (struct target_ops *ignore)
    kill(SIGINT) to the child's process group.  */
 
 static void
-procfs_stop (struct target_ops *self, ptid_t ptid)
+procfs_interrupt (struct target_ops *self, ptid_t ptid)
 {
   kill (-inferior_process_group (), SIGINT);
 }
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index 01cb5b6..b246cd9 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1407,10 +1407,10 @@  m32r_load (struct target_ops *self, const char *args, int from_tty)
 }
 
 static void
-m32r_stop (struct target_ops *self, ptid_t ptid)
+m32r_interrupt (struct target_ops *self, ptid_t ptid)
 {
   if (remote_debug)
-    fprintf_unfiltered (gdb_stdlog, "m32r_stop()\n");
+    fprintf_unfiltered (gdb_stdlog, "m32r_interrupt()\n");
 
   send_cmd (SDI_STOP_CPU);
 
@@ -1664,7 +1664,7 @@  init_m32r_ops (void)
   m32r_ops.to_load = m32r_load;
   m32r_ops.to_create_inferior = m32r_create_inferior;
   m32r_ops.to_mourn_inferior = m32r_mourn_inferior;
-  m32r_ops.to_stop = m32r_stop;
+  m32r_ops.to_interrupt = m32r_interrupt;
   m32r_ops.to_log_command = serial_log_command;
   m32r_ops.to_thread_alive = m32r_thread_alive;
   m32r_ops.to_pid_to_str = m32r_pid_to_str;
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index fd2fd58..766356a 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -87,7 +87,7 @@  static void gdbsim_files_info (struct target_ops *target);
 
 static void gdbsim_mourn_inferior (struct target_ops *target);
 
-static void gdbsim_stop (struct target_ops *self, ptid_t ptid);
+static void gdbsim_interrupt (struct target_ops *self, ptid_t ptid);
 
 void simulator_command (char *args, int from_tty);
 
@@ -888,17 +888,17 @@  gdbsim_resume (struct target_ops *ops,
     error (_("The program is not being run."));
 }
 
-/* Notify the simulator of an asynchronous request to stop.
+/* Notify the simulator of an asynchronous request to interrupt.
 
-   The simulator shall ensure that the stop request is eventually
+   The simulator shall ensure that the interrupt request is eventually
    delivered to the simulator.  If the call is made while the
-   simulator is not running then the stop request is processed when
+   simulator is not running then the interrupt request is processed when
    the simulator is next resumed.
 
    For simulators that do not support this operation, just abort.  */
 
 static int
-gdbsim_stop_inferior (struct inferior *inf, void *arg)
+gdbsim_interrupt_inferior (struct inferior *inf, void *arg)
 {
   struct sim_inferior_data *sim_data
     = get_sim_inferior_data (inf, SIM_INSTANCE_NEEDED);
@@ -918,13 +918,13 @@  gdbsim_stop_inferior (struct inferior *inf, void *arg)
 }
 
 static void
-gdbsim_stop (struct target_ops *self, ptid_t ptid)
+gdbsim_interrupt (struct target_ops *self, ptid_t ptid)
 {
   struct sim_inferior_data *sim_data;
 
   if (ptid_equal (ptid, minus_one_ptid))
     {
-      iterate_over_inferiors (gdbsim_stop_inferior, NULL);
+      iterate_over_inferiors (gdbsim_interrupt_inferior, NULL);
     }
   else
     {
@@ -934,7 +934,7 @@  gdbsim_stop (struct target_ops *self, ptid_t ptid)
 	error (_("Can't stop pid %d.  No inferior found."),
 	       ptid_get_pid (ptid));
 
-      gdbsim_stop_inferior (inf, NULL);
+      gdbsim_interrupt_inferior (inf, NULL);
     }
 }
 
@@ -962,7 +962,7 @@  gdb_os_poll_quit (host_callback *p)
 static void
 gdbsim_cntrl_c (int signo)
 {
-  gdbsim_stop (NULL, minus_one_ptid);
+  gdbsim_interrupt (NULL, minus_one_ptid);
 }
 
 static ptid_t
@@ -1320,7 +1320,7 @@  init_gdbsim_ops (void)
   gdbsim_ops.to_load = gdbsim_load;
   gdbsim_ops.to_create_inferior = gdbsim_create_inferior;
   gdbsim_ops.to_mourn_inferior = gdbsim_mourn_inferior;
-  gdbsim_ops.to_stop = gdbsim_stop;
+  gdbsim_ops.to_interrupt = gdbsim_interrupt;
   gdbsim_ops.to_thread_alive = gdbsim_thread_alive;
   gdbsim_ops.to_pid_to_str = gdbsim_pid_to_str;
   gdbsim_ops.to_stratum = process_stratum;
diff --git a/gdb/remote.c b/gdb/remote.c
index 18492bf..3d61869 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5002,11 +5002,12 @@  async_cleanup_sigint_signal_handler (void *dummy)
    packet.  */
 static void (*ofunc) (int);
 
-/* The command line interface's stop routine.  This function is installed
-   as a signal handler for SIGINT.  The first time a user requests a
-   stop, we call remote_stop to send a break or ^C.  If there is no
+/* The command line interface's interrupt routine.  This function is installed
+   as a signal handler for SIGINT.  The first time a user requests an
+   interrupt, we call remote_interrupt to send a break or ^C.  If there is no
    response from the target (it didn't stop when the user requested it),
    we ask the user if he'd like to detach from the target.  */
+
 static void
 sync_remote_interrupt (int signo)
 {
@@ -5077,12 +5078,12 @@  remote_stop_ns (ptid_t ptid)
     error (_("Stopping %s failed: %s"), target_pid_to_str (ptid), rs->buf);
 }
 
-/* All-stop version of target_stop.  Sends a break or a ^C to stop the
-   remote target.  It is undefined which thread of which process
-   reports the stop.  */
+/* All-stop version of target_interrupt.  Sends a break or a ^C to
+   interrupt the remote target.  It is undefined which thread of which
+   process reports the interrupt.  */
 
 static void
-remote_stop_as (ptid_t ptid)
+remote_interrupt_as (ptid_t ptid)
 {
   struct remote_state *rs = get_remote_state ();
 
@@ -5098,9 +5099,7 @@  remote_stop_as (ptid_t ptid)
   send_interrupt_sequence ();
 }
 
-/* This is the generic stop called via the target vector.  When a target
-   interrupt is requested, either by the command line or the GUI, we
-   will eventually end up here.  */
+/* Implement the to_stop function for the remote targets.  */
 
 static void
 remote_stop (struct target_ops *self, ptid_t ptid)
@@ -5111,7 +5110,29 @@  remote_stop (struct target_ops *self, ptid_t ptid)
   if (non_stop)
     remote_stop_ns (ptid);
   else
-    remote_stop_as (ptid);
+    {
+      /* We don't currently have a way to transparently pause the
+	 remote target in all-stop mode.  Interrupt it instead.  */
+      remote_interrupt_as (ptid);
+    }
+}
+
+/* Implement the to_interrupt function for the remote targets.  */
+
+static void
+remote_interrupt (struct target_ops *self, ptid_t ptid)
+{
+  if (remote_debug)
+    fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
+
+  if (non_stop)
+    {
+      /* We don't currently have a way to ^C the remote target in
+	 non-stop mode.  Stop it (with no signal) instead.  */
+      remote_stop_ns (ptid);
+    }
+  else
+    remote_interrupt_as (ptid);
 }
 
 /* Ask the user what to do when an interrupt is received.  */
@@ -11739,6 +11760,7 @@  Specify the serial device it is connected to\n\
   remote_ops.to_extra_thread_info = remote_threads_extra_info;
   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_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 8a92acf..054ad32 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1537,6 +1537,30 @@  debug_stop (struct target_ops *self, ptid_t arg1)
 }
 
 static void
+delegate_interrupt (struct target_ops *self, ptid_t arg1)
+{
+  self = self->beneath;
+  self->to_interrupt (self, arg1);
+}
+
+static void
+tdefault_interrupt (struct target_ops *self, ptid_t arg1)
+{
+}
+
+static void
+debug_interrupt (struct target_ops *self, ptid_t arg1)
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->to_interrupt (...)\n", debug_target.to_shortname);
+  debug_target.to_interrupt (&debug_target, arg1);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->to_interrupt (", debug_target.to_shortname);
+  target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_ptid_t (arg1);
+  fputs_unfiltered (")\n", gdb_stdlog);
+}
+
+static void
 delegate_rcmd (struct target_ops *self, const char *arg1, struct ui_file *arg2)
 {
   self = self->beneath;
@@ -4016,6 +4040,8 @@  install_delegators (struct target_ops *ops)
     ops->to_thread_name = delegate_thread_name;
   if (ops->to_stop == NULL)
     ops->to_stop = delegate_stop;
+  if (ops->to_interrupt == NULL)
+    ops->to_interrupt = delegate_interrupt;
   if (ops->to_rcmd == NULL)
     ops->to_rcmd = delegate_rcmd;
   if (ops->to_pid_to_exec_file == NULL)
@@ -4253,6 +4279,7 @@  install_dummy_methods (struct target_ops *ops)
   ops->to_extra_thread_info = tdefault_extra_thread_info;
   ops->to_thread_name = tdefault_thread_name;
   ops->to_stop = tdefault_stop;
+  ops->to_interrupt = tdefault_interrupt;
   ops->to_rcmd = default_rcmd;
   ops->to_pid_to_exec_file = tdefault_pid_to_exec_file;
   ops->to_log_command = tdefault_log_command;
@@ -4402,6 +4429,7 @@  init_debug_target (struct target_ops *ops)
   ops->to_extra_thread_info = debug_extra_thread_info;
   ops->to_thread_name = debug_thread_name;
   ops->to_stop = debug_stop;
+  ops->to_interrupt = debug_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 ab6c977..2262131 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3244,6 +3244,18 @@  target_stop (ptid_t ptid)
   (*current_target.to_stop) (&current_target, ptid);
 }
 
+void
+target_interrupt (ptid_t ptid)
+{
+  if (!may_stop)
+    {
+      warning (_("May not interrupt or stop the target, ignoring attempt"));
+      return;
+    }
+
+  (*current_target.to_interrupt) (&current_target, ptid);
+}
+
 /* See target/target.h.  */
 
 void
diff --git a/gdb/target.h b/gdb/target.h
index 17dee43..276b5e2 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -611,6 +611,8 @@  struct target_ops
       TARGET_DEFAULT_RETURN (NULL);
     void (*to_stop) (struct target_ops *, ptid_t)
       TARGET_DEFAULT_IGNORE ();
+    void (*to_interrupt) (struct target_ops *, ptid_t)
+      TARGET_DEFAULT_IGNORE ();
     void (*to_rcmd) (struct target_ops *,
 		     const char *command, struct ui_file *output)
       TARGET_DEFAULT_FUNC (default_rcmd);
@@ -1635,6 +1637,12 @@  extern void target_update_thread_list (void);
 
 extern void target_stop (ptid_t ptid);
 
+/* Interrupt the target just like the user typed a ^C on the
+   inferior's controlling terminal.  (For instance, under Unix, this
+   should act like SIGINT).  This function is asynchronous.  */
+
+extern void target_interrupt (ptid_t ptid);
+
 /* 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/windows-nat.c b/gdb/windows-nat.c
index fd31083..46a378c 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -162,7 +162,7 @@  static int windows_initialization_done;
 #define DEBUG_MEM(x)	if (debug_memory)	printf_unfiltered x
 #define DEBUG_EXCEPT(x)	if (debug_exceptions)	printf_unfiltered x
 
-static void windows_stop (struct target_ops *self, ptid_t);
+static void windows_interrupt (struct target_ops *self, ptid_t);
 static int windows_thread_alive (struct target_ops *, ptid_t);
 static void windows_kill_inferior (struct target_ops *);
 
@@ -2294,7 +2294,7 @@  windows_mourn_inferior (struct target_ops *ops)
    ^C on the controlling terminal.  */
 
 static void
-windows_stop (struct target_ops *self, ptid_t ptid)
+windows_interrupt (struct target_ops *self, ptid_t ptid)
 {
   DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n"));
   CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId));
@@ -2488,7 +2488,7 @@  windows_target (void)
   t->to_mourn_inferior = windows_mourn_inferior;
   t->to_thread_alive = windows_thread_alive;
   t->to_pid_to_str = windows_pid_to_str;
-  t->to_stop = windows_stop;
+  t->to_interrupt = windows_interrupt;
   t->to_pid_to_exec_file = windows_pid_to_exec_file;
   t->to_get_ada_task_ptid = windows_get_ada_task_ptid;
   t->to_get_tib_address = windows_get_tib_address;