[1/7] Merge async and sync code paths some more

Message ID 1439398917-22761-2-git-send-email-palves@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves Aug. 12, 2015, 5:01 p.m. UTC
  This patch makes the execution control code use largely the same
mechanisms in both sync- and async-capable targets.  This means using
continuations and use the event loop to react to target events on sync
targets as well.  The trick is to immediately mark infrun's event loop
source after resume instead of calling wait_for_inferior.  Then
fetch_inferior_event is adjusted to do a blocking wait on sync
targets.

Tested on x86_64 Fedora 20, native and gdbserver, with and without
"maint set target-async off".

gdb/ChangeLog:
2015-08-12  Pedro Alves  <palves@redhat.com>

	* breakpoint.c (bpstat_do_actions_1, until_break_command): Don't
	check whether the target can async.
	* inf-loop.c (inferior_event_handler): Only call target_async if
	the target can async.
	* infcall.c: Include top.h and interps.h.
	(run_inferior_call): For the interpreter to sync mode while
	running the infcall.  Call wait_sync_command_done instead of
	wait_for_inferior plus normal_stop.
	* infcmd.c (prepare_execution_command): Don't check whether the
	target can async when running in the foreground.
	(step_1): Delete synchronous case handling.
	(step_once): Always install a continuation, even in sync mode.
	(until_next_command, finish_forward): Don't check whether the
	target can async.
	(attach_command_post_wait, notice_new_inferior): Always install a
	continuation, even in sync mode.
	* infrun.c (mark_infrun_async_event_handler): New function.
	(proceed): In sync mode, mark infrun's event source instead of
	waiting for events here.
	(fetch_inferior_event): If the target can't async, do a blocking
	wait.
	(prepare_to_wait): In sync mode, mark infrun's event source.
	(infrun_async_inferior_event_handler): No longer bail out if the
	target can't async.
	* infrun.h (mark_infrun_async_event_handler): New declaration.
	* linux-nat.c (linux_nat_wait_1): Remove calls to
	set_sigint_trap/clear_sigint_trap.
	(linux_nat_terminal_inferior): No longer check whether the target
	can async.
	* mi/mi-interp.c (mi_on_sync_execution_done): Update and simplify
	comment.
	(mi_execute_command_input_handler): No longer check whether the
	target is async.  Update and simplify comment.
	* target.c (default_target_wait): New function.
	* target.h (struct target_ops) <to_wait>: Now defaults to
	default_to_wait.
	(default_target_wait): Declare.
	* top.c (wait_sync_command_done): New function, factored out from
	...
	(maybe_wait_sync_command_done): ... this.
	* top.h (wait_sync_command_done): Declare.
---
 gdb/breakpoint.c   |   4 +-
 gdb/inf-loop.c     |   2 +-
 gdb/infcall.c      |  36 ++++++--------
 gdb/infcmd.c       | 142 +++++++++++++++++------------------------------------
 gdb/infrun.c       |  37 +++++++-------
 gdb/infrun.h       |   4 ++
 gdb/linux-nat.c    |  23 ---------
 gdb/mi/mi-interp.c |  32 +++---------
 gdb/target.c       |  11 +++++
 gdb/target.h       |   8 ++-
 gdb/top.c          |  16 ++++--
 gdb/top.h          |   3 ++
 12 files changed, 126 insertions(+), 192 deletions(-)
  

Comments

Simon Marchi Aug. 12, 2015, 7:48 p.m. UTC | #1
On 15-08-12 01:01 PM, Pedro Alves wrote:
> diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
> index 99ce385..bdd8e21 100644
> --- a/gdb/mi/mi-interp.c
> +++ b/gdb/mi/mi-interp.c
> @@ -309,16 +309,8 @@ mi_execute_command_wrapper (const char *cmd)
>  static void
>  mi_on_sync_execution_done (void)
>  {
> -  /* MI generally prints a prompt after a command, indicating it's
> -     ready for further input.  However, due to an historical wart, if
> -     MI async, and a (CLI) synchronous command was issued, then we
> -     will print the prompt right after printing "^running", even if we
> -     cannot actually accept any input until the target stops.  See
> -     mi_on_resume.  However, if the target is async but MI is sync,
> -     then we need to output the MI prompt now, to replicate gdb's
> -     behavior when neither the target nor MI are async.  (Note this
> -     observer is only called by the asynchronous target event handling
> -     code.)  */
> +  /* If we MI is sync, then output the MI prompt now, indicating we're
> +     ready for further input.  */

"If we MI is sync"
  
Pedro Alves Aug. 17, 2015, 5:54 p.m. UTC | #2
On 08/12/2015 08:48 PM, Simon Marchi wrote:

>> +  /* If we MI is sync, then output the MI prompt now, indicating we're
>> +     ready for further input.  */
> 
> "If we MI is sync"

Whoops.  I removed the stale "we" locally.

Do you intend to comment on the rest of the series?

Thanks,
Pedro Alves
  
Simon Marchi Aug. 17, 2015, 7:28 p.m. UTC | #3
On 15-08-17 01:54 PM, Pedro Alves wrote:
> On 08/12/2015 08:48 PM, Simon Marchi wrote:
> 
>>> +  /* If we MI is sync, then output the MI prompt now, indicating we're
>>> +     ready for further input.  */
>>
>> "If we MI is sync"
> 
> Whoops.  I removed the stale "we" locally.
> 
> Do you intend to comment on the rest of the series?

I tried to read and understand a bit from all the patches, but my brain
melted.  So, no I don't have any more comments.
  
Yao Qi Aug. 18, 2015, 10:48 a.m. UTC | #4
Pedro Alves <palves@redhat.com> writes:

> +  /* do only one step for now, before returning control to the event

s/do/Do

> +     loop.  Let the continuation figure out how many other steps we
> +     need to do, and handle them one at the time, through
> +     step_once.  */

> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index be7a915..fa8e5e3 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -3442,12 +3442,6 @@ linux_nat_wait_1 (struct target_ops *ops,
>  			    target_pid_to_str (lp->ptid));
>      }
>  
> -  if (!target_is_async_p ())
> -    {
> -      /* Causes SIGINT to be passed on to the attached process.  */
> -      set_sigint_trap ();
> -    }
> -

so SIGINT is handled by event-top.c:handle_sigint in event loop, right?

>    /* But if we don't find a pending event, we'll have to wait.  Always
>       pull all events out of the kernel.  We'll randomly select an
>       event LWP out of all that have events, to prevent starvation.  */
> @@ -3518,9 +3512,6 @@ linux_nat_wait_1 (struct target_ops *ops,
>  
>  	  ourstatus->kind = TARGET_WAITKIND_NO_RESUMED;
>  
> -	  if (!target_is_async_p ())
> -	    clear_sigint_trap ();
> -
>  	  restore_child_signals_mask (&prev_mask);
>  	  return minus_one_ptid;
>  	}

> diff --git a/gdb/target.c b/gdb/target.c
> index e41a338..210cc70 100644
> --- a/gdb/target.c
> +++ b/gdb/target.c
> @@ -2229,6 +2229,17 @@ target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
>    return (current_target.to_wait) (&current_target, ptid, status, options);
>  }
>  
> +/* See target.h.  */
> +
> +ptid_t
> +default_target_wait (ptid_t ptid,
> +		     struct target_waitstatus *status,
> +		     int options)
> +{
> +  status->kind = TARGET_WAITKIND_NO_RESUMED;
> +  return minus_one_ptid;
> +}
> +
>  char *
>  target_pid_to_str (ptid_t ptid)
>  {
> diff --git a/gdb/target.h b/gdb/target.h
> index e283c86..48e6857 100644
> --- a/gdb/target.h
> +++ b/gdb/target.h
> @@ -471,7 +471,7 @@ struct target_ops
>      ptid_t (*to_wait) (struct target_ops *,
>  		       ptid_t, struct target_waitstatus *,
>  		       int TARGET_DEBUG_PRINTER (target_debug_print_options))
> -      TARGET_DEFAULT_NORETURN (noprocess ());
> +      TARGET_DEFAULT_FUNC (default_to_wait);

s/default_to_wait/default_target_wait/ ?

Otherwise, the patch looks good to me.
  

Patch

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a6994c7..dbf69da 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4662,7 +4662,7 @@  bpstat_do_actions_1 (bpstat *bsp)
 
       if (breakpoint_proceeded)
 	{
-	  if (interpreter_async && target_can_async_p ())
+	  if (interpreter_async)
 	    /* If we are in async mode, then the target might be still
 	       running, not stopped at any breakpoint, so nothing for
 	       us to do here -- just return to the event loop.  */
@@ -11590,7 +11590,7 @@  until_break_command (char *arg, int from_tty, int anywhere)
      be deleted when the target stops.  Otherwise, we're already
      stopped and delete breakpoints via cleanup chain.  */
 
-  if (target_can_async_p () && is_running (inferior_ptid))
+  if (is_running (inferior_ptid))
     {
       struct until_break_command_continuation_args *args;
       args = xmalloc (sizeof (*args));
diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c
index eed881d..7b1f724 100644
--- a/gdb/inf-loop.c
+++ b/gdb/inf-loop.c
@@ -73,7 +73,7 @@  inferior_event_handler (enum inferior_event_type event_type,
 	  /* Unregister the inferior from the event loop.  This is done
 	     so that when the inferior is not running we don't get
 	     distracted by spurious inferior output.  */
-	  if (target_has_execution)
+	  if (target_has_execution && target_can_async_p ())
 	    target_async (0);
 	}
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 139c361..b19028d 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -36,6 +36,8 @@ 
 #include "gdbthread.h"
 #include "event-top.h"
 #include "observer.h"
+#include "top.h"
+#include "interps.h"
 
 /* If we can't find a function's name from its address,
    we print this instead.  */
@@ -388,10 +390,13 @@  run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
   ptid_t call_thread_ptid = call_thread->ptid;
   int saved_sync_execution = sync_execution;
   int was_running = call_thread->state == THREAD_RUNNING;
+  int saved_interpreter_async = interpreter_async;
 
   /* Infcalls run synchronously, in the foreground.  */
-  if (target_can_async_p ())
-    sync_execution = 1;
+  sync_execution = 1;
+  /* So that we don't print the prompt prematurely in
+     fetch_inferior_event.  */
+  interpreter_async = 0;
 
   call_thread->control.in_infcall = 1;
 
@@ -404,25 +409,11 @@  run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
 
   TRY
     {
-      int was_sync = sync_execution;
-
       proceed (real_pc, GDB_SIGNAL_0);
 
       /* Inferior function calls are always synchronous, even if the
-	 target supports asynchronous execution.  Do here what
-	 `proceed' itself does in sync mode.  */
-      if (target_can_async_p ())
-	{
-	  wait_for_inferior ();
-	  normal_stop ();
-	  /* If GDB was previously in sync execution mode, then ensure
-	     that it remains so.  normal_stop calls
-	     async_enable_stdin, so reset it again here.  In other
-	     cases, stdin will be re-enabled by
-	     inferior_event_handler, when an exception is thrown.  */
-	  if (was_sync)
-	    async_disable_stdin ();
-	}
+	 target supports asynchronous execution.  */
+      wait_sync_command_done ();
     }
   CATCH (e, RETURN_MASK_ALL)
     {
@@ -430,6 +421,13 @@  run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
     }
   END_CATCH
 
+  /* If GDB was previously in sync execution mode, then ensure that it
+     remains so.  normal_stop calls async_enable_stdin, so reset it
+     again here.  In other cases, stdin will be re-enabled by
+     inferior_event_handler, when an exception is thrown.  */
+  sync_execution = saved_sync_execution;
+  interpreter_async = saved_interpreter_async;
+
   /* At this point the current thread may have changed.  Refresh
      CALL_THREAD as it could be invalid if its thread has exited.  */
   call_thread = find_thread_ptid (call_thread_ptid);
@@ -470,8 +468,6 @@  run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
   if (call_thread != NULL)
     call_thread->control.in_infcall = saved_in_infcall;
 
-  sync_execution = saved_sync_execution;
-
   return caught_error;
 }
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 82399a4..3faff72 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -504,13 +504,12 @@  prepare_execution_command (struct target_ops *target, int background)
   if (background && !target->to_can_async_p (target))
     error (_("Asynchronous execution not supported on this target."));
 
-  /* If we don't get a request of running in the bg, then we need
-     to simulate synchronous (fg) execution.  */
-  if (!background && target->to_can_async_p (target))
+  if (!background)
     {
-      /* Simulate synchronous execution.  Note no cleanup is necessary
-	 for this.  stdin is re-enabled whenever an error reaches the
-	 top level.  */
+      /* If we get a request for running in the fg, then we need to
+	 simulate synchronous (fg) execution.  Note no cleanup is
+	 necessary for this.  stdin is re-enabled whenever an error
+	 reaches the top level.  */
       async_disable_stdin ();
     }
 }
@@ -937,44 +936,15 @@  step_1 (int skip_subroutines, int single_inst, char *count_string)
       make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
     }
 
-  /* In synchronous case, all is well; each step_once call will step once.  */
-  if (!target_can_async_p ())
-    {
-      for (; count > 0; count--)
-	{
-	  step_once (skip_subroutines, single_inst, count, thread);
-
-	  if (!target_has_execution)
-	    break;
-	  else
-	    {
-	      struct thread_info *tp = inferior_thread ();
+  /* do only one step for now, before returning control to the event
+     loop.  Let the continuation figure out how many other steps we
+     need to do, and handle them one at the time, through
+     step_once.  */
+  step_once (skip_subroutines, single_inst, count, thread);
 
-	      if (!tp->control.stop_step || !tp->step_multi)
-		{
-		  /* If we stopped for some reason that is not stepping
-		     there are no further steps to make.  */
-		  tp->step_multi = 0;
-		  break;
-		}
-	    }
-	}
-
-      do_cleanups (cleanups);
-    }
-  else
-    {
-      /* In the case of an asynchronous target things get complicated;
-	 do only one step for now, before returning control to the
-	 event loop.  Let the continuation figure out how many other
-	 steps we need to do, and handle them one at the time, through
-	 step_once.  */
-      step_once (skip_subroutines, single_inst, count, thread);
-
-      /* We are running, and the continuation is installed.  It will
-	 disable the longjmp breakpoint as appropriate.  */
-      discard_cleanups (cleanups);
-    }
+  /* We are running, and the continuation is installed.  It will
+     disable the longjmp breakpoint as appropriate.  */
+  discard_cleanups (cleanups);
 }
 
 struct step_1_continuation_args
@@ -1033,6 +1003,7 @@  step_once (int skip_subroutines, int single_inst, int count, int thread)
 
   if (count > 0)
     {
+      struct step_1_continuation_args *args;
       /* Don't assume THREAD is a valid thread id.  It is set to -1 if
 	 the longjmp breakpoint was not required.  Use the
 	 INFERIOR_PTID thread instead, which is the same thread when
@@ -1116,21 +1087,14 @@  step_once (int skip_subroutines, int single_inst, int count, int thread)
       tp->control.stepping_command = 1;
       proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
 
-      /* For async targets, register a continuation to do any
-	 additional steps.  For sync targets, the caller will handle
-	 further stepping.  */
-      if (target_can_async_p ())
-	{
-	  struct step_1_continuation_args *args;
-
-	  args = xmalloc (sizeof (*args));
-	  args->skip_subroutines = skip_subroutines;
-	  args->single_inst = single_inst;
-	  args->count = count;
-	  args->thread = thread;
+      /* Register a continuation to do any additional steps.  */
+      args = xmalloc (sizeof (*args));
+      args->skip_subroutines = skip_subroutines;
+      args->single_inst = single_inst;
+      args->count = count;
+      args->thread = thread;
 
-	  add_intermediate_continuation (tp, step_1_continuation, args, xfree);
-	}
+      add_intermediate_continuation (tp, step_1_continuation, args, xfree);
     }
 }
 
@@ -1442,7 +1406,7 @@  until_next_command (int from_tty)
 
   proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
 
-  if (target_can_async_p () && is_running (inferior_ptid))
+  if (is_running (inferior_ptid))
     {
       struct until_next_continuation_args *cont_args;
 
@@ -1801,8 +1765,6 @@  finish_forward (struct symbol *function, struct frame_info *frame)
   proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
 
   discard_cleanups (old_chain);
-  if (!target_can_async_p ())
-    do_all_continuations (0);
 }
 
 /* "finish": Set a temporary breakpoint at the place the selected
@@ -2532,8 +2494,7 @@  attach_command_post_wait (char *args, int from_tty, int async_exec)
       /* The user requested a plain `attach', so be sure to leave
 	 the inferior stopped.  */
 
-      if (target_can_async_p ())
-	async_enable_stdin ();
+      async_enable_stdin ();
 
       /* At least the current thread is already stopped.  */
 
@@ -2663,6 +2624,7 @@  attach_command (char *args, int from_tty)
      E.g. Mach 3 or GNU hurd.  */
   if (!target_attach_no_wait)
     {
+      struct attach_command_continuation_args *a;
       struct inferior *inferior = current_inferior ();
 
       /* Careful here.  See comments in inferior.h.  Basically some
@@ -2672,25 +2634,19 @@  attach_command (char *args, int from_tty)
 	 STOP_QUIETLY_NO_SIGSTOP is for.  */
       inferior->control.stop_soon = STOP_QUIETLY_NO_SIGSTOP;
 
-      if (target_can_async_p ())
-	{
-	  /* sync_execution mode.  Wait for stop.  */
-	  struct attach_command_continuation_args *a;
-
-	  a = xmalloc (sizeof (*a));
-	  a->args = xstrdup (args);
-	  a->from_tty = from_tty;
-	  a->async_exec = async_exec;
-	  add_inferior_continuation (attach_command_continuation, a,
-				     attach_command_continuation_free_args);
-
-	  /* Done with ARGS.  */
-	  do_cleanups (args_chain);
-
-	  return;
-	}
-
-      wait_for_inferior ();
+      /* sync_execution mode.  Wait for stop.  */
+      a = xmalloc (sizeof (*a));
+      a->args = xstrdup (args);
+      a->from_tty = from_tty;
+      a->async_exec = async_exec;
+      add_inferior_continuation (attach_command_continuation, a,
+				 attach_command_continuation_free_args);
+      /* Done with ARGS.  */
+      do_cleanups (args_chain);
+
+      if (!target_is_async_p ())
+	mark_infrun_async_event_handler ();
+      return;
     }
 
   /* Done with ARGS.  */
@@ -2731,6 +2687,7 @@  notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
 
   if (is_executing (inferior_ptid))
     {
+      struct attach_command_continuation_args *a;
       struct inferior *inferior = current_inferior ();
 
       /* We're going to install breakpoints, and poke at memory,
@@ -2741,22 +2698,15 @@  notice_new_inferior (ptid_t ptid, int leave_running, int from_tty)
       inferior->control.stop_soon = STOP_QUIETLY_REMOTE;
 
       /* Wait for stop before proceeding.  */
-      if (target_can_async_p ())
-	{
-	  struct attach_command_continuation_args *a;
+      a = xmalloc (sizeof (*a));
+      a->args = xstrdup ("");
+      a->from_tty = from_tty;
+      a->async_exec = async_exec;
+      add_inferior_continuation (attach_command_continuation, a,
+				 attach_command_continuation_free_args);
 
-	  a = xmalloc (sizeof (*a));
-	  a->args = xstrdup ("");
-	  a->from_tty = from_tty;
-	  a->async_exec = async_exec;
-	  add_inferior_continuation (attach_command_continuation, a,
-				     attach_command_continuation_free_args);
-
-	  do_cleanups (old_chain);
-	  return;
-	}
-      else
-	wait_for_inferior ();
+      do_cleanups (old_chain);
+      return;
     }
 
   async_exec = leave_running;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a695f2e..195ee81 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -131,6 +131,14 @@  infrun_async (int enable)
     }
 }
 
+/* See infrun.h.  */
+
+void
+mark_infrun_async_event_handler (void)
+{
+  mark_async_event_handler (infrun_async_inferior_event_token);
+}
+
 /* When set, stop the 'step' command if we enter a function which has
    no line number information.  The normal behavior is that we step
    over such function.  */
@@ -3090,15 +3098,11 @@  proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 
   discard_cleanups (old_chain);
 
-  /* Wait for it to stop (if not standalone)
-     and in any case decode why it stopped, and act accordingly.  */
-  /* Do this only if we are not using the event loop, or if the target
-     does not support asynchronous execution.  */
+  /* Tell the event loop to wait for it to stop.  If the target
+     supports asynchronous execution, it'll do this from within
+     target_resume.  */
   if (!target_can_async_p ())
-    {
-      wait_for_inferior ();
-      normal_stop ();
-    }
+    mark_async_event_handler (infrun_async_inferior_event_token);
 }
 
 
@@ -3762,7 +3766,8 @@  fetch_inferior_event (void *client_data)
   make_cleanup_restore_integer (&execution_direction);
   execution_direction = target_execution_direction ();
 
-  ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, TARGET_WNOHANG);
+  ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws,
+			      target_can_async_p () ? TARGET_WNOHANG : 0);
 
   if (debug_infrun)
     print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
@@ -7512,10 +7517,10 @@  prepare_to_wait (struct execution_control_state *ecs)
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog, "infrun: prepare_to_wait\n");
 
-  /* This is the old end of the while loop.  Let everybody know we
-     want to wait for the inferior some more and get called again
-     soon.  */
   ecs->wait_some_more = 1;
+
+  if (!target_is_async_p ())
+    mark_infrun_async_event_handler ();
 }
 
 /* We are done with the step range of a step/next/si/ni command.
@@ -8808,14 +8813,6 @@  static const struct internalvar_funcs siginfo_funcs =
 static void
 infrun_async_inferior_event_handler (gdb_client_data data)
 {
-  /* If the target is closed while this event source is marked, we
-     will reach here without execution, or a target to call
-     target_wait on, which is an error.  Instead of tracking whether
-     the target has been popped already, or whether we do have threads
-     with pending statutes, simply ignore the event.  */
-  if (!target_is_async_p ())
-    return;
-
   inferior_event_handler (INF_REG_EVENT, NULL);
 }
 
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 6108648..1af64a6 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -192,6 +192,10 @@  enum gdb_signal gdb_signal_from_command (int num);
 /* Enables/disables infrun's async event source in the event loop.  */
 extern void infrun_async (int enable);
 
+/* Call infrun's event handler the next time through the event
+   loop.  */
+extern void mark_infrun_async_event_handler (void);
+
 /* The global queue of threads that need to do a step-over operation
    to get past e.g., a breakpoint.  */
 extern struct thread_info *step_over_queue_head;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index be7a915..fa8e5e3 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -3442,12 +3442,6 @@  linux_nat_wait_1 (struct target_ops *ops,
 			    target_pid_to_str (lp->ptid));
     }
 
-  if (!target_is_async_p ())
-    {
-      /* Causes SIGINT to be passed on to the attached process.  */
-      set_sigint_trap ();
-    }
-
   /* But if we don't find a pending event, we'll have to wait.  Always
      pull all events out of the kernel.  We'll randomly select an
      event LWP out of all that have events, to prevent starvation.  */
@@ -3518,9 +3512,6 @@  linux_nat_wait_1 (struct target_ops *ops,
 
 	  ourstatus->kind = TARGET_WAITKIND_NO_RESUMED;
 
-	  if (!target_is_async_p ())
-	    clear_sigint_trap ();
-
 	  restore_child_signals_mask (&prev_mask);
 	  return minus_one_ptid;
 	}
@@ -3546,9 +3537,6 @@  linux_nat_wait_1 (struct target_ops *ops,
       sigsuspend (&suspend_mask);
     }
 
-  if (!target_is_async_p ())
-    clear_sigint_trap ();
-
   gdb_assert (lp);
 
   status = lp->status;
@@ -4627,17 +4615,6 @@  static int async_terminal_is_ours = 1;
 static void
 linux_nat_terminal_inferior (struct target_ops *self)
 {
-  /* Like target_terminal_inferior, use target_can_async_p, not
-     target_is_async_p, since at this point the target is not async
-     yet.  If it can async, then we know it will become async prior to
-     resume.  */
-  if (!target_can_async_p ())
-    {
-      /* Async mode is disabled.  */
-      child_terminal_inferior (self);
-      return;
-    }
-
   child_terminal_inferior (self);
 
   /* Calls to target_terminal_*() are meant to be idempotent.  */
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 99ce385..bdd8e21 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -309,16 +309,8 @@  mi_execute_command_wrapper (const char *cmd)
 static void
 mi_on_sync_execution_done (void)
 {
-  /* MI generally prints a prompt after a command, indicating it's
-     ready for further input.  However, due to an historical wart, if
-     MI async, and a (CLI) synchronous command was issued, then we
-     will print the prompt right after printing "^running", even if we
-     cannot actually accept any input until the target stops.  See
-     mi_on_resume.  However, if the target is async but MI is sync,
-     then we need to output the MI prompt now, to replicate gdb's
-     behavior when neither the target nor MI are async.  (Note this
-     observer is only called by the asynchronous target event handling
-     code.)  */
+  /* If we MI is sync, then output the MI prompt now, indicating we're
+     ready for further input.  */
   if (!mi_async_p ())
     {
       fputs_unfiltered ("(gdb) \n", raw_stdout);
@@ -333,20 +325,12 @@  mi_execute_command_input_handler (char *cmd)
 {
   mi_execute_command_wrapper (cmd);
 
-  /* MI generally prints a prompt after a command, indicating it's
-     ready for further input.  However, due to an historical wart, if
-     MI is async, and a synchronous command was issued, then we will
-     print the prompt right after printing "^running", even if we
-     cannot actually accept any input until the target stops.  See
-     mi_on_resume.
-
-     If MI is not async, then we print the prompt when the command
-     finishes.  If the target is sync, that means output the prompt
-     now, as in that case executing a command doesn't return until the
-     command is done.  However, if the target is async, we go back to
-     the event loop and output the prompt in the
-     'synchronous_command_done' observer.  */
-  if (!target_is_async_p () || !sync_execution)
+  /* Print a prompt, indicating we're ready for further input, unless
+     we just started a synchronous command.  In that case, we're about
+     to go back to the event loop and will output the prompt in the
+     'synchronous_command_done' observer when the target next
+     stops.  */
+  if (!sync_execution)
     {
       fputs_unfiltered ("(gdb) \n", raw_stdout);
       gdb_flush (raw_stdout);
diff --git a/gdb/target.c b/gdb/target.c
index e41a338..210cc70 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2229,6 +2229,17 @@  target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
   return (current_target.to_wait) (&current_target, ptid, status, options);
 }
 
+/* See target.h.  */
+
+ptid_t
+default_target_wait (ptid_t ptid,
+		     struct target_waitstatus *status,
+		     int options)
+{
+  status->kind = TARGET_WAITKIND_NO_RESUMED;
+  return minus_one_ptid;
+}
+
 char *
 target_pid_to_str (ptid_t ptid)
 {
diff --git a/gdb/target.h b/gdb/target.h
index e283c86..48e6857 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -471,7 +471,7 @@  struct target_ops
     ptid_t (*to_wait) (struct target_ops *,
 		       ptid_t, struct target_waitstatus *,
 		       int TARGET_DEBUG_PRINTER (target_debug_print_options))
-      TARGET_DEFAULT_NORETURN (noprocess ());
+      TARGET_DEFAULT_FUNC (default_to_wait);
     void (*to_fetch_registers) (struct target_ops *, struct regcache *, int)
       TARGET_DEFAULT_IGNORE ();
     void (*to_store_registers) (struct target_ops *, struct regcache *, int)
@@ -1322,6 +1322,12 @@  extern void target_resume (ptid_t ptid, int step, enum gdb_signal signal);
 extern ptid_t target_wait (ptid_t ptid, struct target_waitstatus *status,
 			   int options);
 
+/* The default target_ops::to_wait implementation.  */
+
+extern ptid_t default_target_wait (ptid_t ptid,
+				   struct target_waitstatus *status,
+				   int options);
+
 /* Fetch at least register REGNO, or all regs if regno == -1.  No result.  */
 
 extern void target_fetch_registers (struct regcache *regcache, int regno);
diff --git a/gdb/top.c b/gdb/top.c
index 061b52f..dc4e357 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -368,6 +368,16 @@  check_frame_language_change (void)
 /* See top.h.  */
 
 void
+wait_sync_command_done (void)
+{
+  while (gdb_do_one_event () >= 0)
+    if (!sync_execution)
+      break;
+}
+
+/* See top.h.  */
+
+void
 maybe_wait_sync_command_done (int was_sync)
 {
   /* If the interpreter is in sync mode (we're running a user
@@ -375,11 +385,7 @@  maybe_wait_sync_command_done (int was_sync)
      just ran a synchronous command that started the target, wait
      for that command to end.  */
   if (!interpreter_async && !was_sync && sync_execution)
-    {
-      while (gdb_do_one_event () >= 0)
-	if (!sync_execution)
-	  break;
-    }
+    wait_sync_command_done ();
 }
 
 /* Execute the line P as a command, in the current user context.
diff --git a/gdb/top.h b/gdb/top.h
index 987279b..c95c319 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -50,6 +50,9 @@  extern void execute_command (char *, int);
 
 extern void maybe_wait_sync_command_done (int was_sync);
 
+/* Wait for a synchronous execution command to end.  */
+extern void wait_sync_command_done (void);
+
 extern void check_frame_language_change (void);
 
 /* Prepare for execution of a command.