@@ -25,6 +25,7 @@
#include "observer.h"
#include "inferior.h"
#include "infrun.h"
+#include "top.h"
/* 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. */
@@ -34,6 +34,7 @@
#include "gdb_sys_time.h"
#include "gdb_select.h"
#include "observer.h"
+#include "top.h"
/* Tell create_file_handler what events we are interested in.
This is used by the select version of the event loop. */
@@ -357,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,
@@ -277,7 +277,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
@@ -300,10 +304,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
@@ -445,14 +450,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;
}
}
@@ -462,7 +465,9 @@ async_enable_stdin (void)
void
async_disable_stdin (void)
{
- sync_execution = 1;
+ struct ui *ui = current_ui;
+
+ ui->prompt_state = PROMPT_BLOCKED;
}
@@ -677,8 +682,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);
}
}
@@ -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);
@@ -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 (¤t_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 (¤t_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 ();
}
}
@@ -2687,8 +2701,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
@@ -2862,7 +2874,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;
@@ -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
@@ -3790,7 +3786,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,
@@ -3800,7 +3798,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 ();
}
@@ -3833,6 +3831,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. */
@@ -3860,7 +3888,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;
@@ -3980,14 +4007,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)))
@@ -4674,17 +4699,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
@@ -8240,10 +8280,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. */
@@ -8255,8 +8299,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);
@@ -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 */
@@ -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. */
@@ -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_callback_no_editing;
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);
@@ -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);
@@ -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;
@@ -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
@@ -93,6 +111,9 @@ struct ui
/* The serial object that wraps stdin. */
struct serial *stdin_serial;
+ /* 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. */
@@ -135,6 +156,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. */