aboutsummaryrefslogtreecommitdiff
path: root/gdb/mi
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-05-29 19:58:57 +0100
committerPedro Alves <palves@redhat.com>2014-05-29 14:38:02 +0100
commit329ea57934a9d4b250a0b417af1ec47bc2d0ceb6 (patch)
tree8f395e9024ad1dc97fc953b88baa87ed1dbbafa3 /gdb/mi
parent92bcb5f949b1d1f14df079bbe9fd3941c1e09919 (diff)
downloadgdb-329ea57934a9d4b250a0b417af1ec47bc2d0ceb6.zip
gdb-329ea57934a9d4b250a0b417af1ec47bc2d0ceb6.tar.gz
gdb-329ea57934a9d4b250a0b417af1ec47bc2d0ceb6.tar.bz2
enable target async by default; separate MI and target notions of async
This finally makes background execution commands possible by default. However, in order to do that, there's one last thing we need to do -- we need to separate the MI and target notions of "async". Unlike the CLI, where the user explicitly requests foreground vs background execution in the execution command itself (c vs c&), MI chose to treat "set target-async" specially -- setting it changes the default behavior of execution commands. So, we can't simply "set target-async" default to on, as that would affect MI frontends. Instead we have to make the setting MI-specific, and teach MI about sync commands on top of an async target. Because the "target" word in "set target-async" ends up as a potential source of confusion, the patch adds a "set mi-async" option, and makes "set target-async" a deprecated alias. Rather than make the targets always async, this patch introduces a new "maint set target-async" option so that the GDB developer can control whether the target is async. This makes it simpler to debug issues arising only in the synchronous mode; important because sync mode seems unlikely to go away. Unlike in previous revisions, "set target-async" does not affect this new maint parameter. The rationale for this is that then one can easily run the test suite in the "maint set target-async off" mode and have tests that enable mi-async fail just like they fail on non-async-capable targets. This emulation is exactly the point of the maint option. I had asked Tom in a previous iteration to split the actual change of the target async default to a separate patch, but it turns out that that is quite awkward in this version of the patch, because with MI async and target async decoupled (unlike in previous versions), if we don't flip the default at the same time, then just "set target-async on" alone never actually manages to do anything. It's best to not have that transitory state in the tree. Given "set target-async on" now only has effect for MI, the patch goes through the testsuite removing it from non-MI tests. MI tests are adjusted to use the new and less confusing "mi-async" spelling. 2014-05-29 Pedro Alves <palves@redhat.com> Tom Tromey <tromey@redhat.com> * NEWS: Mention "maint set target-async", "set mi-async", and that background execution commands are now always available. * target.h (target_async_permitted): Update comment. * target.c (target_async_permitted, target_async_permitted_1): Default to 1. (set_target_async_command): Rename to ... (maint_set_target_async_command): ... this. (show_target_async_command): Rename to ... (maint_show_target_async_command): ... this. (_initialize_target): Adjust. * infcmd.c (prepare_execution_command): Make extern. * inferior.h (prepare_execution_command): Declare. * infrun.c (set_observer_mode): Leave target async alone. * mi/mi-interp.c (mi_interpreter_init): Install mi_on_sync_execution_done as sync_execution_done observer. (mi_on_sync_execution_done): New function. (mi_execute_command_input_handler): Don't print the prompt if we just started a synchronous command with an async target. (mi_on_resume): Check sync_execution before printing prompt. * mi/mi-main.h (mi_async_p): Declare. * mi/mi-main.c: Include gdbcmd.h. (mi_async_p): New function. (mi_async, mi_async_1): New globals. (set_mi_async_command, show_mi_async_command, mi_async): New functions. (exec_continue): Call prepare_execution_command. (run_one_inferior, mi_cmd_exec_run, mi_cmd_list_target_features) (mi_execute_async_cli_command): Use mi_async_p. (_initialize_mi_main): Install "set mi-async". Make "target-async" a deprecated alias. 2014-05-29 Pedro Alves <palves@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.texinfo (Non-Stop Mode): Remove "set target-async 1" from example. (Asynchronous and non-stop modes): Document '-gdb-set mi-async'. Mention that target-async is now deprecated. (Maintenance Commands): Document maint set/show target-async. 2014-05-29 Pedro Alves <palves@redhat.com> Tom Tromey <tromey@redhat.com> * gdb.base/async-shell.exp: Don't enable target-async. * gdb.base/async.exp * gdb.base/corefile.exp (corefile_test_attach): Remove 'async' parameter. Adjust. (top level): Don't test with "target-async". * gdb.base/dprintf-non-stop.exp: Don't enable target-async. * gdb.base/gdb-sigterm.exp: Don't test with "target-async". * gdb.base/inferior-died.exp: Don't enable target-async. * gdb.base/interrupt-noterm.exp: Likewise. * gdb.mi/mi-async.exp: Use "mi-async" instead of "target-async". * gdb.mi/mi-nonstop-exit.exp: Likewise. * gdb.mi/mi-nonstop.exp: Likewise. * gdb.mi/mi-ns-stale-regcache.exp: Likewise. * gdb.mi/mi-nsintrall.exp: Likewise. * gdb.mi/mi-nsmoribund.exp: Likewise. * gdb.mi/mi-nsthrexec.exp: Likewise. * gdb.mi/mi-watch-nonstop.exp: Likewise. * gdb.multi/watchpoint-multi.exp: Adjust comment. * gdb.python/py-evsignal.exp: Don't enable target-async. * gdb.python/py-evthreads.exp: Likewise. * gdb.python/py-prompt.exp: Likewise. * gdb.reverse/break-precsave.exp: Don't test with "target-async". * gdb.server/solib-list.exp: Don't enable target-async. * gdb.threads/thread-specific-bp.exp: Likewise. * lib/mi-support.exp: Adjust to use mi-async.
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;