Replace the sync_execution global with a new enum prompt_state tristate
authorPedro Alves <palves@redhat.com>
Tue, 21 Jun 2016 00:11:51 +0000 (01:11 +0100)
committerPedro Alves <palves@redhat.com>
Tue, 21 Jun 2016 00:11:51 +0000 (01:11 +0100)
When sync_execution (a boolean) is true, it means we're running a
foreground command -- we hide the prompt stop listening to input, give
the inferior the terminal, then go to the event loop waiting for the
target to stop.

With multiple independent UIs, we need to track whether each UI is
synchronously blocked waiting for the target.  IOW, if you do
"continue" in one console, that console stops accepting commands, but
you should still be free to type other commands in the others
consoles.

Just simply making sync_execution be per-UI alone not sufficient,
because of this in fetch_inferior_event:

  /* If the inferior was in sync execution mode, and now isn't,
     restore the prompt (a synchronous execution command has finished,
     and we're ready for input).  */
  if (current_ui->async && was_sync && !sync_execution)
    observer_notify_sync_execution_done ();

We'd have to record at entry the "was_sync" state for each UI, not
just of the current UI.

This patch instead replaces the sync_execution flag by a per-UI
tristate flag indicating the command line prompt state:

 enum prompt_state
 {
   /* The command line is blocked simulating synchronous execution.
      This is used to implement the foreground execution commands
      ('run', 'continue', etc.).  We won't display the prompt and
      accept further commands until the execution is actually over.  */
   PROMPT_BLOCKED,

   /* The command finished; display the prompt before returning back to
      the top level.  */
   PROMPT_NEEDED,

   /* We've displayed the prompt already, ready for input.  */
   PROMPTED,
 ;

I think the end result is _much_ clearer than the current code, and,
it addresses the original motivation too.

gdb/ChangeLog:
2016-06-21  Pedro Alves  <palves@redhat.com>

* annotate.c: Include top.h.
(async_background_execution_p): Delete.
(print_value_flags): Check the UI's prompt state rather then
async_background_execution_p.
* event-loop.c (start_event_loop): Set the prompt state to
PROMPT_NEEDED.
* event-top.c (display_gdb_prompt, async_enable_stdin)
(async_disable_stdin): Check the current UI's prompt state instead
of the sync_execution global.
(command_line_handler): Set the prompt state to PROMPT_NEEDED
before running a command, and display the prompt if still needed
afterwards.
* infcall.c (struct call_thread_fsm) <waiting_ui>: New field.
(new_call_thread_fsm): New parameter 'waiting_ui'.  Store it.
(call_thread_fsm_should_stop): Set the prompt state to
PROMPT_NEEDED.
(run_inferior_call): Adjust to temporarily set the prompt state to
PROMPT_BLOCKED instead of using the sync_execution global.
(call_function_by_hand_dummy): Pass the current UI to
new_call_thread_fsm.
* infcmd.c: Include top.h.
(continue_1): Check the current UI's prompt state instead of the
sync_execution global.
(continue_command): Validate global execution state before calling
prepare_execution_command.
(step_1): Call all_uis_check_sync_execution_done.
(attach_post_wait): Don't call async_enable_stdin here.  Remove
reference to sync_execution.
* infrun.c (sync_execution): Delete global.
(follow_fork_inferior)
(reinstall_readline_callback_handler_cleanup): Check the current
UI's prompt state instead of the sync_execution global.
(check_curr_ui_sync_execution_done)
(all_uis_check_sync_execution_done): New functions.
(fetch_inferior_event): Call all_uis_check_sync_execution_done
instead of trying to determine whether the global sync execution
changed.
(handle_no_resumed): Check the prompt state of all UIs.
(normal_stop): Emit the no unwait-for even to all PROMPT_BLOCKED
UIs.  Emit the "Switching to" notification to all UIs.  Enable
stdin in all UIs.
* infrun.h (sync_execution): Delete.
(all_uis_check_sync_execution_done): Declare.
* main.c (captured_command_loop): Don't call
interp_pre_command_loop if the prompt is blocked.
(catch_command_errors, catch_command_errors_const): Adjust.
(captured_main): Set the initial prompt state to PROMPT_NEEDED.
* mi/mi-interp.c (display_mi_prompt): Set the prompt state to
PROMPTED.
(mi_interpreter_resume): Don't clear sync_execution.  Remove hack
comment.
(mi_execute_command_input_handler): Set the prompt state to
PROMPT_NEEDED before executing the command, and only display the
prompt if the prompt state is PROMPT_NEEDED afterwards.
(mi_on_resume_1): Adjust to check the prompt state.
* target.c (target_terminal_inferior): Adjust to check the prompt
state.
* top.c (wait_sync_command_done, maybe_wait_sync_command_done)
(execute_command): Check the current UI's prompt state instead of
sync_execution.
* top.h (enum prompt_state): New.
(struct ui) <prompt_state>: New field.
(ALL_UIS): New macro.

13 files changed:
gdb/ChangeLog
gdb/annotate.c
gdb/event-loop.c
gdb/event-top.c
gdb/infcall.c
gdb/infcmd.c
gdb/infrun.c
gdb/infrun.h
gdb/main.c
gdb/mi/mi-interp.c
gdb/target.c
gdb/top.c
gdb/top.h

index e3293d15ea37353bd6c579e5054bcb4d2144d8be..edef298a6d4da8bb4b0086709a11761c6fb18f45 100644 (file)
@@ -1,3 +1,69 @@
+2016-06-21  Pedro Alves  <palves@redhat.com>
+
+       * annotate.c: Include top.h.
+       (async_background_execution_p): Delete.
+       (print_value_flags): Check the UI's prompt state rather then
+       async_background_execution_p.
+       * event-loop.c (start_event_loop): Set the prompt state to
+       PROMPT_NEEDED.
+       * event-top.c (display_gdb_prompt, async_enable_stdin)
+       (async_disable_stdin): Check the current UI's prompt state instead
+       of the sync_execution global.
+       (command_line_handler): Set the prompt state to PROMPT_NEEDED
+       before running a command, and display the prompt if still needed
+       afterwards.
+       * infcall.c (struct call_thread_fsm) <waiting_ui>: New field.
+       (new_call_thread_fsm): New parameter 'waiting_ui'.  Store it.
+       (call_thread_fsm_should_stop): Set the prompt state to
+       PROMPT_NEEDED.
+       (run_inferior_call): Adjust to temporarily set the prompt state to
+       PROMPT_BLOCKED instead of using the sync_execution global.
+       (call_function_by_hand_dummy): Pass the current UI to
+       new_call_thread_fsm.
+       * infcmd.c: Include top.h.
+       (continue_1): Check the current UI's prompt state instead of the
+       sync_execution global.
+       (continue_command): Validate global execution state before calling
+       prepare_execution_command.
+       (step_1): Call all_uis_check_sync_execution_done.
+       (attach_post_wait): Don't call async_enable_stdin here.  Remove
+       reference to sync_execution.
+       * infrun.c (sync_execution): Delete global.
+       (follow_fork_inferior)
+       (reinstall_readline_callback_handler_cleanup): Check the current
+       UI's prompt state instead of the sync_execution global.
+       (check_curr_ui_sync_execution_done)
+       (all_uis_check_sync_execution_done): New functions.
+       (fetch_inferior_event): Call all_uis_check_sync_execution_done
+       instead of trying to determine whether the global sync execution
+       changed.
+       (handle_no_resumed): Check the prompt state of all UIs.
+       (normal_stop): Emit the no unwait-for even to all PROMPT_BLOCKED
+       UIs.  Emit the "Switching to" notification to all UIs.  Enable
+       stdin in all UIs.
+       * infrun.h (sync_execution): Delete.
+       (all_uis_check_sync_execution_done): Declare.
+       * main.c (captured_command_loop): Don't call
+       interp_pre_command_loop if the prompt is blocked.
+       (catch_command_errors, catch_command_errors_const): Adjust.
+       (captured_main): Set the initial prompt state to PROMPT_NEEDED.
+       * mi/mi-interp.c (display_mi_prompt): Set the prompt state to
+       PROMPTED.
+       (mi_interpreter_resume): Don't clear sync_execution.  Remove hack
+       comment.
+       (mi_execute_command_input_handler): Set the prompt state to
+       PROMPT_NEEDED before executing the command, and only display the
+       prompt if the prompt state is PROMPT_NEEDED afterwards.
+       (mi_on_resume_1): Adjust to check the prompt state.
+       * target.c (target_terminal_inferior): Adjust to check the prompt
+       state.
+       * top.c (wait_sync_command_done, maybe_wait_sync_command_done)
+       (execute_command): Check the current UI's prompt state instead of
+       sync_execution.
+       * top.h (enum prompt_state): New.
+       (struct ui) <prompt_state>: New field.
+       (ALL_UIS): New macro.
+
 2016-06-21  Pedro Alves  <palves@redhat.com>
 
        * top.c (gdb_secondary_prompt_depth): Delete.
index 117f12203b38b4ec6733df9f05553dc1a43101c6..64175a442b99d2654ed09759dfcbb5dfcfe29150 100644 (file)
@@ -25,6 +25,7 @@
 #include "observer.h"
 #include "inferior.h"
 #include "infrun.h"
+#include "top.h"
 \f
 
 /* Prototypes for local functions.  */
@@ -46,16 +47,6 @@ void (*deprecated_annotate_signal_hook) (void);
 static int frames_invalid_emitted;
 static int breakpoints_invalid_emitted;
 
-/* True if the target can async, and a synchronous execution command
-   is not in progress.  If true, input is accepted, so don't suppress
-   annotations.  */
-
-static int
-async_background_execution_p (void)
-{
-  return (target_can_async_p () && !sync_execution);
-}
-
 static void
 print_value_flags (struct type *t)
 {
@@ -70,7 +61,7 @@ annotate_breakpoints_invalid (void)
 {
   if (annotation_level == 2
       && (!breakpoints_invalid_emitted
-         || async_background_execution_p ()))
+         || current_ui->prompt_state != PROMPT_BLOCKED))
     {
       /* If the inferior owns the terminal (e.g., we're resuming),
         make sure to leave with the inferior still owning it.  */
@@ -217,7 +208,7 @@ annotate_frames_invalid (void)
 {
   if (annotation_level == 2
       && (!frames_invalid_emitted
-         || async_background_execution_p ()))
+         || current_ui->prompt_state != PROMPT_BLOCKED))
     {
       /* If the inferior owns the terminal (e.g., we're resuming),
         make sure to leave with the inferior still owning it.  */
index fe283050507765c5bb2198658bc1c66567e003b2..f94a6fa135f579cf0cdaf2920d3f663ce1dfcf4b 100644 (file)
@@ -381,6 +381,7 @@ start_event_loop (void)
          /* If we long-jumped out of do_one_event, we probably didn't
             get around to resetting the prompt, which leaves readline
             in a messed-up state.  Reset it here.  */
+         current_ui->prompt_state = PROMPT_NEEDED;
          observer_notify_command_error ();
          /* This call looks bizarre, but it is required.  If the user
             entered a command that caused an error,
index 5e42c5605139fbf18b1e63e07c7bb73ce97720e0..c9e754875df007ddc30e10dc1016e42d83dd4b83 100644 (file)
@@ -354,7 +354,11 @@ display_gdb_prompt (const char *new_prompt)
      IE, displayed but not set.  */
   if (! new_prompt)
     {
-      if (sync_execution)
+      struct ui *ui = current_ui;
+
+      if (ui->prompt_state == PROMPTED)
+       internal_error (__FILE__, __LINE__, _("double prompt"));
+      else if (ui->prompt_state == PROMPT_BLOCKED)
        {
          /* This is to trick readline into not trying to display the
             prompt.  Even though we display the prompt using this
@@ -377,10 +381,11 @@ display_gdb_prompt (const char *new_prompt)
          do_cleanups (old_chain);
          return;
        }
-      else
+      else if (ui->prompt_state == PROMPT_NEEDED)
        {
          /* Display the top level prompt.  */
          actual_gdb_prompt = top_level_prompt ();
+         ui->prompt_state = PROMPTED;
        }
     }
   else
@@ -541,14 +546,12 @@ stdin_event_handler (int error, gdb_client_data client_data)
 void
 async_enable_stdin (void)
 {
-  if (sync_execution)
+  struct ui *ui = current_ui;
+
+  if (ui->prompt_state == PROMPT_BLOCKED)
     {
-      /* See NOTE in async_disable_stdin().  */
-      /* FIXME: cagney/1999-09-27: Call this before clearing
-        sync_execution.  Current target_terminal_ours() implementations
-        check for sync_execution before switching the terminal.  */
       target_terminal_ours ();
-      sync_execution = 0;
+      ui->prompt_state = PROMPT_NEEDED;
     }
 }
 
@@ -558,7 +561,9 @@ async_enable_stdin (void)
 void
 async_disable_stdin (void)
 {
-  sync_execution = 1;
+  struct ui *ui = current_ui;
+
+  ui->prompt_state = PROMPT_BLOCKED;
 }
 \f
 
@@ -774,8 +779,12 @@ command_line_handler (char *rl)
     }
   else
     {
+      ui->prompt_state = PROMPT_NEEDED;
+
       command_handler (cmd);
-      display_gdb_prompt (0);
+
+      if (ui->prompt_state != PROMPTED)
+       display_gdb_prompt (0);
     }
 }
 
index 11f5abacb51da5c9f5a78466ef1ff46c794e53e7..d491f9526fa98da5fa5d37f1420674581a91b17b 100644 (file)
@@ -464,6 +464,10 @@ struct call_thread_fsm
   /* The called function's return value.  This is extracted from the
      target before the dummy frame is popped.  */
   struct value *return_value;
+
+  /* The top level that started the infcall (and is synchronously
+     waiting for it to end).  */
+  struct ui *waiting_ui;
 };
 
 static int call_thread_fsm_should_stop (struct thread_fsm *self);
@@ -484,7 +488,8 @@ static struct thread_fsm_ops call_thread_fsm_ops =
 /* Allocate a new call_thread_fsm object.  */
 
 static struct call_thread_fsm *
-new_call_thread_fsm (struct gdbarch *gdbarch, struct value *function,
+new_call_thread_fsm (struct ui *waiting_ui,
+                    struct gdbarch *gdbarch, struct value *function,
                     struct type *value_type,
                     int struct_return_p, CORE_ADDR struct_addr)
 {
@@ -499,6 +504,8 @@ new_call_thread_fsm (struct gdbarch *gdbarch, struct value *function,
   sm->return_meta_info.struct_return_p = struct_return_p;
   sm->return_meta_info.struct_addr = struct_addr;
 
+  sm->waiting_ui = waiting_ui;
+
   return sm;
 }
 
@@ -511,6 +518,8 @@ call_thread_fsm_should_stop (struct thread_fsm *self)
 
   if (stop_stack_dummy == STOP_STACK_DUMMY)
     {
+      struct cleanup *old_chain;
+
       /* Done.  */
       thread_fsm_set_finished (self);
 
@@ -520,7 +529,13 @@ call_thread_fsm_should_stop (struct thread_fsm *self)
       f->return_value = get_call_return_value (&f->return_meta_info);
 
       /* Break out of wait_sync_command_done.  */
-      async_enable_stdin ();
+      old_chain = make_cleanup (restore_ui_cleanup, current_ui);
+      current_ui = f->waiting_ui;
+      target_terminal_ours ();
+      f->waiting_ui->prompt_state = PROMPT_NEEDED;
+
+      /* This restores the previous UI.  */
+      do_cleanups (old_chain);
     }
 
   return 1;
@@ -558,12 +573,12 @@ run_inferior_call (struct call_thread_fsm *sm,
   struct gdb_exception caught_error = exception_none;
   int saved_in_infcall = call_thread->control.in_infcall;
   ptid_t call_thread_ptid = call_thread->ptid;
-  int saved_sync_execution = sync_execution;
+  enum prompt_state saved_prompt_state = current_ui->prompt_state;
   int was_running = call_thread->state == THREAD_RUNNING;
   int saved_ui_async = current_ui->async;
 
   /* Infcalls run synchronously, in the foreground.  */
-  sync_execution = 1;
+  current_ui->prompt_state = PROMPT_BLOCKED;
   /* So that we don't print the prompt prematurely in
      fetch_inferior_event.  */
   current_ui->async = 0;
@@ -596,11 +611,11 @@ run_inferior_call (struct call_thread_fsm *sm,
     }
   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
+  /* If GDB has the prompt blocked before, then ensure that it remains
+     so.  normal_stop calls async_enable_stdin, so reset the prompt
+     state again here.  In other cases, stdin will be re-enabled by
      inferior_event_handler, when an exception is thrown.  */
-  sync_execution = saved_sync_execution;
+  current_ui->prompt_state = saved_prompt_state;
   current_ui->async = saved_ui_async;
 
   /* At this point the current thread may have changed.  Refresh
@@ -1120,7 +1135,8 @@ call_function_by_hand_dummy (struct value *function,
        not report the stop to the user, and captures the return value
        before the dummy frame is popped.  run_inferior_call registers
        it with the thread ASAP.  */
-    sm = new_call_thread_fsm (gdbarch, function,
+    sm = new_call_thread_fsm (current_ui,
+                             gdbarch, function,
                              values_type,
                              struct_return || hidden_first_param_p,
                              struct_addr);
index 1defb13806d58c5d18c5bc12045dfe4ab5461b64..5c3f212bfe51b57b872405997cc3df65f0e2d15b 100644 (file)
@@ -56,6 +56,7 @@
 #include "cli/cli-utils.h"
 #include "infcall.h"
 #include "thread-fsm.h"
+#include "top.h"
 
 /* Local functions: */
 
@@ -730,7 +731,7 @@ continue_1 (int all_threads)
 
       iterate_over_threads (proceed_thread_callback, NULL);
 
-      if (sync_execution)
+      if (current_ui->prompt_state == PROMPT_BLOCKED)
        {
          /* If all threads in the target were already running,
             proceed_thread_callback ends up never calling proceed,
@@ -775,8 +776,6 @@ continue_command (char *args, int from_tty)
   args = strip_bg_char (args, &async_exec);
   args_chain = make_cleanup (xfree, args);
 
-  prepare_execution_command (&current_target, async_exec);
-
   if (args != NULL)
     {
       if (startswith (args, "-a"))
@@ -840,6 +839,17 @@ continue_command (char *args, int from_tty)
   /* Done with ARGS.  */
   do_cleanups (args_chain);
 
+  ERROR_NO_INFERIOR;
+  ensure_not_tfind_mode ();
+
+  if (!non_stop || !all_threads)
+    {
+      ensure_valid_thread ();
+      ensure_not_running ();
+    }
+
+  prepare_execution_command (&current_target, async_exec);
+
   if (from_tty)
     printf_filtered (_("Continuing.\n"));
 
@@ -1014,11 +1024,15 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
     proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
   else
     {
+      int proceeded;
+
       /* Stepped into an inline frame.  Pretend that we've
         stopped.  */
       thread_fsm_clean_up (thr->thread_fsm);
-      normal_stop ();
-      inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+      proceeded = normal_stop ();
+      if (!proceeded)
+       inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+      all_uis_check_sync_execution_done ();
     }
 }
 
@@ -2710,8 +2724,6 @@ attach_post_wait (char *args, int from_tty, enum attach_post_wait_mode mode)
       /* The user requested a plain `attach', so be sure to leave
         the inferior stopped.  */
 
-      async_enable_stdin ();
-
       /* At least the current thread is already stopped.  */
 
       /* In all-stop, by definition, all threads have to be already
@@ -2885,7 +2897,7 @@ attach_command (char *args, int from_tty)
         STOP_QUIETLY_NO_SIGSTOP is for.  */
       inferior->control.stop_soon = STOP_QUIETLY_NO_SIGSTOP;
 
-      /* sync_execution mode.  Wait for stop.  */
+      /* Wait for stop.  */
       a = XNEW (struct attach_command_continuation_args);
       a->args = xstrdup (args);
       a->from_tty = from_tty;
index 1e9c28ef4f0f203b2c4dfdc4fcbe305702743846..25313b476a9f20df7b36daa1b4efcfe0f8130e55 100644 (file)
@@ -152,10 +152,6 @@ show_step_stop_if_no_debug (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("Mode of the step operation is %s.\n"), value);
 }
 
-/* In asynchronous mode, but simulating synchronous execution.  */
-
-int sync_execution = 0;
-
 /* proceed and normal_stop use this to notify the user when the
    inferior stopped in a different thread than it had been running
    in.  */
@@ -442,7 +438,7 @@ follow_fork_inferior (int follow_child, int detach_fork)
 
   if (has_vforked
       && !non_stop /* Non-stop always resumes both branches.  */
-      && (!target_is_async_p () || sync_execution)
+      && current_ui->prompt_state == PROMPT_BLOCKED
       && !(follow_child || detach_fork || sched_multi))
     {
       /* The parent stays blocked inside the vfork syscall until the
@@ -3802,7 +3798,9 @@ wait_for_inferior (void)
 static void
 reinstall_readline_callback_handler_cleanup (void *arg)
 {
-  if (!current_ui->async)
+  struct ui *ui = current_ui;
+
+  if (!ui->async)
     {
       /* We're not going back to the top level event loop yet.  Don't
         install the readline callback, as it'd prep the terminal,
@@ -3812,7 +3810,7 @@ reinstall_readline_callback_handler_cleanup (void *arg)
       return;
     }
 
-  if (current_ui->command_editing && !sync_execution)
+  if (ui->command_editing && ui->prompt_state != PROMPT_BLOCKED)
     gdb_rl_callback_handler_reinstall ();
 }
 
@@ -3845,6 +3843,36 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
     }
 }
 
+/* Helper for all_uis_check_sync_execution_done that works on the
+   current UI.  */
+
+static void
+check_curr_ui_sync_execution_done (void)
+{
+  struct ui *ui = current_ui;
+
+  if (ui->prompt_state == PROMPT_NEEDED
+      && ui->async
+      && !gdb_in_secondary_prompt_p (ui))
+    {
+      target_terminal_ours ();
+      observer_notify_sync_execution_done ();
+    }
+}
+
+/* See infrun.h.  */
+
+void
+all_uis_check_sync_execution_done (void)
+{
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      check_curr_ui_sync_execution_done ();
+    }
+}
+
 /* A cleanup that restores the execution direction to the value saved
    in *ARG.  */
 
@@ -3872,7 +3900,6 @@ fetch_inferior_event (void *client_data)
   struct execution_control_state *ecs = &ecss;
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
   struct cleanup *ts_old_chain;
-  int was_sync = sync_execution;
   enum exec_direction_kind save_exec_dir = execution_direction;
   int cmd_done = 0;
   ptid_t waiton_ptid = minus_one_ptid;
@@ -3992,14 +4019,12 @@ fetch_inferior_event (void *client_data)
   /* Revert thread and frame.  */
   do_cleanups (old_chain);
 
-  /* If the inferior was in sync execution mode, and now isn't,
-     restore the prompt (a synchronous execution command has finished,
-     and we're ready for input).  */
-  if (current_ui->async && was_sync && !sync_execution)
-    observer_notify_sync_execution_done ();
+  /* If a UI was in sync execution mode, and now isn't, restore its
+     prompt (a synchronous execution command has finished, and we're
+     ready for input).  */
+  all_uis_check_sync_execution_done ();
 
   if (cmd_done
-      && !was_sync
       && exec_done_display_p
       && (ptid_equal (inferior_ptid, null_ptid)
          || !is_running (inferior_ptid)))
@@ -4685,17 +4710,32 @@ handle_no_resumed (struct execution_control_state *ecs)
   struct inferior *inf;
   struct thread_info *thread;
 
-  if (target_can_async_p () && !sync_execution)
+  if (target_can_async_p ())
     {
-      /* There were no unwaited-for children left in the target, but,
-        we're not synchronously waiting for events either.  Just
-        ignore.  */
+      struct ui *ui;
+      int any_sync = 0;
 
-      if (debug_infrun)
-       fprintf_unfiltered (gdb_stdlog,
-                           "infrun: TARGET_WAITKIND_NO_RESUMED " "(ignoring: bg)\n");
-      prepare_to_wait (ecs);
-      return 1;
+      ALL_UIS (ui)
+       {
+         if (ui->prompt_state == PROMPT_BLOCKED)
+           {
+             any_sync = 1;
+             break;
+           }
+       }
+      if (!any_sync)
+       {
+         /* There were no unwaited-for children left in the target, but,
+            we're not synchronously waiting for events either.  Just
+            ignore.  */
+
+         if (debug_infrun)
+           fprintf_unfiltered (gdb_stdlog,
+                               "infrun: TARGET_WAITKIND_NO_RESUMED "
+                               "(ignoring: bg)\n");
+         prepare_to_wait (ecs);
+         return 1;
+       }
     }
 
   /* Otherwise, if we were running a synchronous execution command, we
@@ -8194,6 +8234,7 @@ normal_stop (void)
   ptid_t last_ptid;
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
   ptid_t pid_ptid;
+  struct switch_thru_all_uis state;
 
   get_last_target_status (&last_ptid, &last);
 
@@ -8258,19 +8299,24 @@ normal_stop (void)
       && last.kind != TARGET_WAITKIND_EXITED
       && last.kind != TARGET_WAITKIND_NO_RESUMED)
     {
-      target_terminal_ours_for_output ();
-      printf_filtered (_("[Switching to %s]\n"),
-                      target_pid_to_str (inferior_ptid));
-      annotate_thread_changed ();
+      SWITCH_THRU_ALL_UIS (state)
+       {
+         target_terminal_ours_for_output ();
+         printf_filtered (_("[Switching to %s]\n"),
+                          target_pid_to_str (inferior_ptid));
+         annotate_thread_changed ();
+       }
       previous_inferior_ptid = inferior_ptid;
     }
 
   if (last.kind == TARGET_WAITKIND_NO_RESUMED)
     {
-      gdb_assert (sync_execution || !target_can_async_p ());
-
-      target_terminal_ours_for_output ();
-      printf_filtered (_("No unwaited-for children left.\n"));
+      SWITCH_THRU_ALL_UIS (state)
+       if (current_ui->prompt_state == PROMPT_BLOCKED)
+         {
+           target_terminal_ours_for_output ();
+           printf_filtered (_("No unwaited-for children left.\n"));
+         }
     }
 
   /* Note: this depends on the update_thread_list call above.  */
@@ -8282,8 +8328,10 @@ normal_stop (void)
   if (stopped_by_random_signal)
     disable_current_display ();
 
-  target_terminal_ours ();
-  async_enable_stdin ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      async_enable_stdin ();
+    }
 
   /* Let the user/frontend see the threads as stopped.  */
   do_cleanups (old_chain);
index e79bf2d83dad315868b2fcd719b7fbb645080578..01eff9a1dbd082c5da663eca61dcb923b23b7df0 100644 (file)
@@ -35,11 +35,6 @@ extern int debug_displaced;
    of shared library events by the dynamic linker.  */
 extern int stop_on_solib_events;
 
-/* Are we simulating synchronous execution? This is used in async gdb
-   to implement the 'run', 'continue' etc commands, which will not
-   redisplay the prompt until the execution is actually over.  */
-extern int sync_execution;
-
 /* True if execution commands resume all threads of all processes by
    default; otherwise, resume only threads of the current inferior
    process.  */
@@ -238,4 +233,9 @@ extern struct thread_info *step_over_queue_head;
    is stopped).  On failure, print a message.  */
 extern void maybe_remove_breakpoints (void);
 
+/* If a UI was in sync execution mode, and now isn't, restore its
+   prompt (a synchronous execution command has finished, and we're
+   ready for input).  */
+extern void all_uis_check_sync_execution_done (void);
+
 #endif /* INFRUN_H */
index a1ce327641ba681acfba95bfa15d2b9d21d89837..c45bffd81e6f3b11fe97075ebebdcec4789a6a4f 100644 (file)
@@ -315,8 +315,9 @@ captured_command_loop (void *data)
      here on.  */
   current_ui->async = 1;
 
-  /* Give the interpreter a chance to print a prompt.  */
-  interp_pre_command_loop (top_level_interpreter ());
+  /* Give the interpreter a chance to print a prompt, if necessary  */
+  if (ui->prompt_state != PROMPT_BLOCKED)
+    interp_pre_command_loop (top_level_interpreter ());
 
   /* Now it's time to start the event loop.  */
   start_event_loop ();
@@ -368,7 +369,7 @@ catch_command_errors (catch_command_errors_ftype *command,
 {
   TRY
     {
-      int was_sync = sync_execution;
+      int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
 
       command (arg, from_tty);
 
@@ -395,7 +396,7 @@ catch_command_errors_const (catch_command_errors_const_ftype *command,
 {
   TRY
     {
-      int was_sync = sync_execution;
+      int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
 
       command (arg, from_tty);
 
@@ -519,6 +520,8 @@ captured_main (void *data)
 
   ui->input_fd = fileno (stdin);
 
+  ui->prompt_state = PROMPT_NEEDED;
+
 #ifdef __MINGW32__
   /* Ensure stderr is unbuffered.  A Cygwin pty or pipe is implemented
      as a Windows pipe, and Windows buffers on pipes.  */
index 4376ffa06a8e4d3c3946f4dc1f8d34a84fd9fa07..5db61e14f1f2e3fbcaffedebd8937b8af5041f41 100644 (file)
@@ -93,8 +93,11 @@ static int report_initial_inferior (struct inferior *inf, void *closure);
 static void
 display_mi_prompt (struct mi_interp *mi)
 {
+  struct ui *ui = current_ui;
+
   fputs_unfiltered ("(gdb) \n", mi->raw_stdout);
   gdb_flush (mi->raw_stdout);
+  ui->prompt_state = PROMPTED;
 }
 
 /* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and
@@ -169,13 +172,6 @@ mi_interpreter_resume (void *data)
 
   ui->call_readline = gdb_readline_no_editing_callback;
   ui->input_handler = mi_execute_command_input_handler;
-  /* FIXME: This is a total hack for now.  PB's use of the MI
-     implicitly relies on a bug in the async support which allows
-     asynchronous commands to leak through the commmand loop.  The bug
-     involves (but is not limited to) the fact that sync_execution was
-     erroneously initialized to 0.  Duplicate by initializing it thus
-     here...  */
-  sync_execution = 0;
 
   gdb_stdout = mi->out;
   /* Route error and log output through the MI.  */
@@ -315,6 +311,9 @@ static void
 mi_execute_command_input_handler (char *cmd)
 {
   struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+  struct ui *ui = current_ui;
+
+  ui->prompt_state = PROMPT_NEEDED;
 
   mi_execute_command_wrapper (cmd);
 
@@ -323,7 +322,7 @@ mi_execute_command_input_handler (char *cmd)
      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)
+  if (ui->prompt_state == PROMPT_NEEDED)
     display_mi_prompt (mi);
 }
 
@@ -1139,12 +1138,10 @@ mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
   if (!running_result_record_printed && mi_proceeded)
     {
       running_result_record_printed = 1;
-      /* This is what gdb used to do historically -- printing prompt even if
-        it cannot actually accept any input.  This will be surely removed
-        for MI3, and may be removed even earlier.  SYNC_EXECUTION is
-        checked here because we only need to emit a prompt if a
-        synchronous command was issued when the target is async.  */
-      if (!target_can_async_p () || sync_execution)
+      /* This is what gdb used to do historically -- printing prompt
+        even if it cannot actually accept any input.  This will be
+        surely removed for MI3, and may be removed even earlier.  */
+      if (current_ui->prompt_state == PROMPT_BLOCKED)
        fputs_unfiltered ("(gdb) \n", mi->raw_stdout);
     }
   gdb_flush (mi->raw_stdout);
index 8a83fbac70c9ec70110d7f39435d104bfa266522..6f69ac37a1f4538fedbaaa2291a3d454ee641e77 100644 (file)
@@ -482,10 +482,8 @@ target_terminal_inferior (void)
   struct ui *ui = current_ui;
 
   /* A background resume (``run&'') should leave GDB in control of the
-     terminal.  Use target_can_async_p, not target_is_async_p, since at
-     this point the target is not async yet.  However, if sync_execution
-     is not set, we know it will become async prior to resume.  */
-  if (target_can_async_p () && !sync_execution)
+     terminal.  */
+  if (ui->prompt_state != PROMPT_BLOCKED)
     return;
 
   /* Always delete the current UI's input file handler, regardless of
index 79f4293556ba827bbf2b6de54dd8e9036702e6c9..e40835b7e7382d449c3e868e55157adfc84f0d93 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -391,7 +391,7 @@ void
 wait_sync_command_done (void)
 {
   while (gdb_do_one_event () >= 0)
-    if (!sync_execution)
+    if (current_ui->prompt_state != PROMPT_BLOCKED)
       break;
 }
 
@@ -404,7 +404,9 @@ maybe_wait_sync_command_done (int was_sync)
      command's list, running command hooks or similars), and we
      just ran a synchronous command that started the target, wait
      for that command to end.  */
-  if (!current_ui->async && !was_sync && sync_execution)
+  if (!current_ui->async
+      && !was_sync
+      && current_ui->prompt_state == PROMPT_BLOCKED)
     wait_sync_command_done ();
 }
 
@@ -441,7 +443,7 @@ execute_command (char *p, int from_tty)
     {
       const char *cmd = p;
       char *arg;
-      int was_sync = sync_execution;
+      int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
 
       line = p;
 
index 2aa44080c9b57327d123c0f604e35166ef73e205..df96baa16729337ded733bfae9956cfa8fedd06e 100644 (file)
--- a/gdb/top.h
+++ b/gdb/top.h
 
 struct tl_interp_info;
 
+/* Prompt state.  */
+
+enum prompt_state
+{
+  /* The command line is blocked simulating synchronous execution.
+     This is used to implement the foreground execution commands
+     ('run', 'continue', etc.).  We won't display the prompt and
+     accept further commands until the execution is actually over.  */
+  PROMPT_BLOCKED,
+
+  /* The command finished; display the prompt before returning back to
+     the top level.  */
+  PROMPT_NEEDED,
+
+  /* We've displayed the prompt already, ready for input.  */
+  PROMPTED,
+};
+
 /* All about a user interface instance.  Each user interface has its
    own I/O files/streams, readline state, its own top level
    interpreter (for the main UI, this is the interpreter specified
@@ -91,6 +109,9 @@ struct ui
      it with the event loop.  */
   int input_fd;
 
+  /* See enum prompt_state's description.  */
+  enum prompt_state prompt_state;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
@@ -145,6 +166,10 @@ extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
        switch_thru_all_uis_cond (&STATE);              \
        switch_thru_all_uis_next (&STATE))
 
+/* Traverse over all UIs.  */
+#define ALL_UIS(UI)                            \
+  for (UI = ui_list; UI; UI = UI->next)                \
+
 /* Cleanup that restores the current UI.  */
 extern void restore_ui_cleanup (void *data);