+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.
#include "observer.h"
#include "inferior.h"
#include "infrun.h"
+#include "top.h"
\f
/* Prototypes for local functions. */
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)
{
{
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. */
{
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. */
/* 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,
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
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
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;
}
}
void
async_disable_stdin (void)
{
- sync_execution = 1;
+ struct ui *ui = current_ui;
+
+ ui->prompt_state = PROMPT_BLOCKED;
}
\f
}
else
{
+ ui->prompt_state = PROMPT_NEEDED;
+
command_handler (cmd);
- display_gdb_prompt (0);
+
+ if (ui->prompt_state != PROMPTED)
+ display_gdb_prompt (0);
}
}
/* 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);
/* 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)
{
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;
}
if (stop_stack_dummy == STOP_STACK_DUMMY)
{
+ struct cleanup *old_chain;
+
/* Done. */
thread_fsm_set_finished (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;
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;
}
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
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);
#include "cli/cli-utils.h"
#include "infcall.h"
#include "thread-fsm.h"
+#include "top.h"
/* Local functions: */
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,
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"))
/* 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"));
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 ();
}
}
/* 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
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;
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. */
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
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,
return;
}
- if (current_ui->command_editing && !sync_execution)
+ if (ui->command_editing && ui->prompt_state != PROMPT_BLOCKED)
gdb_rl_callback_handler_reinstall ();
}
}
}
+/* 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. */
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;
/* 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)))
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
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);
&& 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. */
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);
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. */
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 */
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 ();
{
TRY
{
- int was_sync = sync_execution;
+ int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
command (arg, from_tty);
{
TRY
{
- int was_sync = sync_execution;
+ int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
command (arg, from_tty);
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. */
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
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. */
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);
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);
}
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);
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
wait_sync_command_done (void)
{
while (gdb_do_one_event () >= 0)
- if (!sync_execution)
+ if (current_ui->prompt_state != PROMPT_BLOCKED)
break;
}
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 ();
}
{
const char *cmd = p;
char *arg;
- int was_sync = sync_execution;
+ int was_sync = current_ui->prompt_state == PROMPT_BLOCKED;
line = p;
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
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. */
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);