aboutsummaryrefslogtreecommitdiff
path: root/gdb/mi
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/mi')
-rw-r--r--gdb/mi/mi-interp.c52
-rw-r--r--gdb/mi/mi-main.c77
-rw-r--r--gdb/mi/mi-main.h4
3 files changed, 120 insertions, 13 deletions
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index e1dd97f..52a3a62 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -85,6 +85,7 @@ static void mi_breakpoint_modified (struct breakpoint *b);
static void mi_command_param_changed (const char *param, const char *value);
static void mi_memory_changed (struct inferior *inf, CORE_ADDR memaddr,
ssize_t len, const bfd_byte *myaddr);
+static void mi_on_sync_execution_done (void);
static int report_initial_inferior (struct inferior *inf, void *closure);
@@ -158,6 +159,7 @@ mi_interpreter_init (struct interp *interp, int top_level)
observer_attach_breakpoint_modified (mi_breakpoint_modified);
observer_attach_command_param_changed (mi_command_param_changed);
observer_attach_memory_changed (mi_memory_changed);
+ observer_attach_sync_execution_done (mi_on_sync_execution_done);
/* The initial inferior is created before this function is
called, so we need to report it explicitly. Use iteration in
@@ -304,6 +306,28 @@ mi_execute_command_wrapper (const char *cmd)
mi_execute_command (cmd, stdin == instream);
}
+/* Observer for the synchronous_command_done notification. */
+
+static void
+mi_on_sync_execution_done (void)
+{
+ /* MI generally prints a prompt after a command, indicating it's
+ ready for further input. However, due to an historical wart, if
+ MI async, and a (CLI) synchronous command was issued, then we
+ will print the prompt right after printing "^running", even if we
+ cannot actually accept any input until the target stops. See
+ mi_on_resume. However, if the target is async but MI is sync,
+ then we need to output the MI prompt now, to replicate gdb's
+ behavior when neither the target nor MI are async. (Note this
+ observer is only called by the asynchronous target event handling
+ code.) */
+ if (!mi_async_p ())
+ {
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
+}
+
/* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER. */
static void
@@ -311,8 +335,24 @@ mi_execute_command_input_handler (char *cmd)
{
mi_execute_command_wrapper (cmd);
- fputs_unfiltered ("(gdb) \n", raw_stdout);
- gdb_flush (raw_stdout);
+ /* MI generally prints a prompt after a command, indicating it's
+ ready for further input. However, due to an historical wart, if
+ MI is async, and a synchronous command was issued, then we will
+ print the prompt right after printing "^running", even if we
+ cannot actually accept any input until the target stops. See
+ mi_on_resume.
+
+ If MI is not async, then we print the prompt when the command
+ finishes. If the target is sync, that means output the prompt
+ now, as in that case executing a command doesn't return until the
+ command is done. However, if the target is async, we go back to
+ the event loop and output the prompt in the
+ 'synchronous_command_done' observer. */
+ if (!target_is_async_p () || !sync_execution)
+ {
+ fputs_unfiltered ("(gdb) \n", raw_stdout);
+ gdb_flush (raw_stdout);
+ }
}
static void
@@ -928,10 +968,10 @@ mi_on_resume (ptid_t ptid)
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 earler. */
- /* FIXME: review the use of target_is_async_p here -- is that
- what we want? */
- if (!target_is_async_p ())
+ 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)
fputs_unfiltered ("(gdb) \n", raw_stdout);
}
gdb_flush (raw_stdout);
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 9ab4886..96dfc71 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -54,6 +54,7 @@
#include "ada-lang.h"
#include "linespec.h"
#include "extension.h"
+#include "gdbcmd.h"
#include <ctype.h>
#include <sys/time.h>
@@ -105,6 +106,45 @@ static int register_changed_p (int regnum, struct regcache *,
static void output_register (struct frame_info *, int regnum, int format,
int skip_unavailable);
+/* Controls whether the frontend wants MI in async mode. */
+static int mi_async = 0;
+
+/* The set command writes to this variable. If the inferior is
+ executing, mi_async is *not* updated. */
+static int mi_async_1 = 0;
+
+static void
+set_mi_async_command (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ if (have_live_inferiors ())
+ {
+ mi_async_1 = mi_async;
+ error (_("Cannot change this setting while the inferior is running."));
+ }
+
+ mi_async = mi_async_1;
+}
+
+static void
+show_mi_async_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file,
+ _("Whether MI is in asynchronous mode is %s.\n"),
+ value);
+}
+
+/* A wrapper for target_can_async_p that takes the MI setting into
+ account. */
+
+int
+mi_async_p (void)
+{
+ return mi_async && target_can_async_p ();
+}
+
/* Command implementations. FIXME: Is this libgdb? No. This is the MI
layer that calls libgdb. Any operation used in the below should be
formalized. */
@@ -229,6 +269,8 @@ proceed_thread_callback (struct thread_info *thread, void *arg)
static void
exec_continue (char **argv, int argc)
{
+ prepare_execution_command (&current_target, mi_async_p ());
+
if (non_stop)
{
/* In non-stop mode, 'resume' always resumes a single thread.
@@ -395,8 +437,8 @@ run_one_inferior (struct inferior *inf, void *arg)
switch_to_thread (null_ptid);
set_current_program_space (inf->pspace);
}
- mi_execute_cli_command (run_cmd, target_can_async_p (),
- target_can_async_p () ? "&" : NULL);
+ mi_execute_cli_command (run_cmd, mi_async_p (),
+ mi_async_p () ? "&" : NULL);
return 0;
}
@@ -450,8 +492,8 @@ mi_cmd_exec_run (char *command, char **argv, int argc)
{
const char *run_cmd = start_p ? "start" : "run";
- mi_execute_cli_command (run_cmd, target_can_async_p (),
- target_can_async_p () ? "&" : NULL);
+ mi_execute_cli_command (run_cmd, mi_async_p (),
+ mi_async_p () ? "&" : NULL);
}
}
@@ -1838,11 +1880,10 @@ mi_cmd_list_target_features (char *command, char **argv, int argc)
struct ui_out *uiout = current_uiout;
cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");
- if (target_can_async_p ())
+ if (mi_async_p ())
ui_out_field_string (uiout, NULL, "async");
if (target_can_execute_reverse)
ui_out_field_string (uiout, NULL, "reverse");
-
do_cleanups (cleanup);
return;
}
@@ -2269,7 +2310,7 @@ mi_execute_async_cli_command (char *cli_command, char **argv, int argc)
struct cleanup *old_cleanups;
char *run;
- if (target_can_async_p ())
+ if (mi_async_p ())
run = xstrprintf ("%s %s&", cli_command, argc ? *argv : "");
else
run = xstrprintf ("%s %s", cli_command, argc ? *argv : "");
@@ -2920,3 +2961,25 @@ mi_cmd_trace_frame_collected (char *command, char **argv, int argc)
do_cleanups (old_chain);
}
+
+void
+_initialize_mi_main (void)
+{
+ struct cmd_list_element *c;
+
+ add_setshow_boolean_cmd ("mi-async", class_run,
+ &mi_async_1, _("\
+Set whether MI asynchronous mode is enabled."), _("\
+Show whether MI asynchronous mode is enabled."), _("\
+Tells GDB whether MI should be in asynchronous mode."),
+ set_mi_async_command,
+ show_mi_async_command,
+ &setlist,
+ &showlist);
+
+ /* Alias old "target-async" to "mi-async". */
+ c = add_alias_cmd ("target-async", "mi-async", class_run, 0, &setlist);
+ deprecate_cmd (c, "set mi-async");
+ c = add_alias_cmd ("target-async", "mi-async", class_run, 0, &showlist);
+ deprecate_cmd (c, "show mi-async");
+}
diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h
index c32845d..530aeb7 100644
--- a/gdb/mi/mi-main.h
+++ b/gdb/mi/mi-main.h
@@ -28,6 +28,10 @@ extern void mi_load_progress (const char *section_name,
extern void mi_print_timing_maybe (void);
+/* Whether MI is in async mode. */
+
+extern int mi_async_p (void);
+
extern char *current_token;
extern int running_result_record_printed;