[PATCH v2 18/25] Replace the sync_execution global with a new enum prompt_state tristate

Pedro Alves
2016-03-21T15:22:13Z

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/annotate.c | 15 ++------
gdb/event-loop.c | 1 +
gdb/event-top.c | 29 +++++++++-----
gdb/infcall.c | 27 +++++++++-----
gdb/infcmd.c | 28 ++++++++++----
gdb/infrun.c | 108 +++++++++++++++++++++++++++++++++++++++--------------
gdb/infrun.h | 10 ++---
gdb/main.c | 11 ++++--
gdb/mi/mi-interp.c | 26 ++++++-------
gdb/target.c | 6 +--
gdb/top.c | 8 ++--
gdb/top.h | 25 +++++++++++++
12 files changed, 197 insertions(+), 97 deletions(-)

diff --git a/gdb/annotate.c b/gdb/annotate.c
index 117f122..64175a4 100644
--- a/gdb/annotate.c
+++ b/gdb/annotate.c
@@ -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. */
diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index c7062eb..6360eff 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -358,6 +358,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,
diff --git a/gdb/event-top.c b/gdb/event-top.c
index db4cb5e..436edf7 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -275,7 +275,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
@@ -298,10 +302,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
@@ -444,14 +449,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;
}
}

@@ -461,7 +464,9 @@ async_enable_stdin (void)
void
async_disable_stdin (void)
{
- sync_execution = 1;
+ struct ui *ui = current_ui;
+
+ ui->prompt_state = PROMPT_BLOCKED;
}
\f

@@ -678,8 +683,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);
}
}

diff --git a/gdb/infcall.c b/gdb/infcall.c
index 11f5aba..29ac605 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -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;
}

@@ -520,7 +527,8 @@ 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 ();
+ target_terminal_ours ();
+ f->waiting_ui->prompt_state = PROMPT_NEEDED;
}

return 1;
@@ -558,12 +566,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 +604,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 +1128,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);
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index d687116..b812c1a 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -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 ();
}
}

@@ -2691,8 +2705,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
@@ -2866,7 +2878,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;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b6524068..39a8940 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -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
@@ -3791,7 +3787,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,
@@ -3801,7 +3799,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 ();
}

@@ -3834,6 +3832,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. */

@@ -3861,7 +3889,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;
@@ -3981,14 +4008,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)))
@@ -4675,17 +4700,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
@@ -8259,10 +8299,14 @@ normal_stop (void)

if (last.kind == TARGET_WAITKIND_NO_RESUMED)
{
- gdb_assert (sync_execution || !target_can_async_p ());
+ struct switch_thru_all_uis state;

- 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. */
@@ -8274,8 +8318,16 @@ normal_stop (void)
if (stopped_by_random_signal)
disable_current_display ();

- target_terminal_ours ();
- async_enable_stdin ();
+ {
+ struct switch_thru_all_uis state;
+
+ target_terminal_ours ();
+
+ SWITCH_THRU_ALL_UIS (state)
+ {
+ async_enable_stdin ();
+ }
+ }

/* Let the user/frontend see the threads as stopped. */
do_cleanups (old_chain);
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 61d3b20..fae633e 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -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. */
@@ -234,4 +229,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 */
diff --git a/gdb/main.c b/gdb/main.c
index 1139487..e107f60 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -313,8 +313,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 ();
@@ -366,7 +367,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);

@@ -393,7 +394,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);

@@ -518,6 +519,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. */
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 6d4936b..e13716a 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -90,8 +90,11 @@ static int report_initial_inferior (struct inferior *inf, void *closure);
static void
display_mi_prompt (void)
{
+ struct ui *ui = current_ui;
+
fputs_unfiltered ("(gdb) \n", raw_stdout);
gdb_flush (raw_stdout);
+ ui->prompt_state = PROMPTED;
}

static struct mi_interp *
@@ -165,13 +168,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. */
@@ -310,6 +306,10 @@ mi_on_sync_execution_done (void)
static void
mi_execute_command_input_handler (char *cmd)
{
+ struct ui *ui = current_ui;
+
+ ui->prompt_state = PROMPT_NEEDED;
+
mi_execute_command_wrapper (cmd);

/* Print a prompt, indicating we're ready for further input, unless
@@ -317,7 +317,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 ();
}

@@ -1051,12 +1051,10 @@ mi_on_resume_1 (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_is_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", raw_stdout);
}
gdb_flush (raw_stdout);
diff --git a/gdb/target.c b/gdb/target.c
index 81bcca1..746894f 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -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;

delete_file_handler (ui->input_fd);
diff --git a/gdb/top.c b/gdb/top.c
index dfbd911..2941dbd 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -376,7 +376,7 @@ void
wait_sync_command_done (void)
{
while (gdb_do_one_event () >= 0)
- if (!sync_execution)
+ if (current_ui->prompt_state != PROMPT_BLOCKED)
break;
}

@@ -389,7 +389,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 ();
}

@@ -426,7 +428,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;

diff --git a/gdb/top.h b/gdb/top.h
index e43875e..29deb3f 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -25,6 +25,24 @@

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
@@ -90,6 +108,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. */
@@ -132,6 +153,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) \
+
extern void restore_ui_cleanup (void *data);

/* From top.c. */
--
2.5.0