This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC v5 7/8] separate MI and target notions of async


This separates the MI and target notions of "async".

Unlike the CLI, MI chose to treat target-async specially -- setting it
changes the default behavior of commands.  So, we can't get rid of the
option.  Instead we have to make it MI-only.

Rather than make the targets always async, this patch introduces a new
"maint" parameter 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 it sync mode seems unlikely
to go away.

Note that "set target-async" also affects 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 which enable
target-async continue to work properly.  This is unusual but, but it
is a maint command after all, and this behavior is useful.

The hardest part of this patch, to my surprise, was getting the MI
prompt to work properly.  It was reasonably easy, and clean, to get
close to what the test suite expects; but to fix the last remaining
failure (mi-async.exp), I had to resort to a hack.

It seems to me that the MI grammar was never updated to account for
changes implied by async.

Perhaps some future MI can dispense with the prompt entirely.

2014-02-26  Tom Tromey  <tromey@redhat.com>

	* NEWS: Update.
	* infrun.c (set_observer_mode): Use maint_async_permitted.
	* linux-nat.c (linux_nat_is_async_p): Use maint_async_permitted.
	(linux_nat_can_async_p): Likewise.
	* mi/mi-interp.c (thread_command_not_mi): New function.
	(mi_interpreter_prompt_p): Maybe print the MI prompt.
	(mi_execute_command_input_handler): Conditionally print prompt.
	(mi_on_resume): Check sync_execution before printing prompt.
	* mi/mi-main.c (mi_target_can_async_p): New function.
	(exec_continue): Maybe call async_disable_stdin.
	(run_one_inferior, mi_cmd_exec_run, mi_cmd_list_target_features)
	(mi_execute_async_cli_command): Use mi_target_can_async_p.
	* remote.c (remote_open_1, remote_terminal_inferior)
	(remote_terminal_ours, remote_can_async_p, remote_is_async_p):
	Use maint_async_permitted.
	* target.c (target_async_permitted): Update comment.
	(maint_async_permitted, maint_async_permitted_1): New globals.
	(set_maint_async_command, show_maint_async_command): New
	functions.
	(initialize_targets): Register new maint target-async commands.
	* target.h (target_async_permitted): Update comment.
	(maint_async_permitted): Declare.

2014-02-26  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Non-Stop Mode): Remove "set target-async 1"
	from example.
	(Background Execution): Move target-async docs...
	(Asynchronous and non-stop modes): ... here.  Rewrite to
	MI form.
	(Maintenance Commands): Document new "maint" commands.

2013-10-30  Tom Tromey  <tromey@redhat.com>

	* gdb.mi/mi-cli.exp: Don't check "$async".
	* lib/mi-support.exp (mi_expect_stop): Special case for when
	$reason is ".*".
---
 gdb/ChangeLog                    | 25 +++++++++++++++++++++
 gdb/NEWS                         | 10 +++++++++
 gdb/doc/ChangeLog                |  9 ++++++++
 gdb/doc/gdb.texinfo              | 37 ++++++++++++++++---------------
 gdb/infrun.c                     |  2 +-
 gdb/linux-nat.c                  | 10 ++-------
 gdb/mi/mi-interp.c               | 39 +++++++++++++++++++++++++++-----
 gdb/mi/mi-main.c                 | 26 +++++++++++++++++-----
 gdb/remote.c                     | 16 +++++++-------
 gdb/target.c                     | 48 +++++++++++++++++++++++++++++++++++++++-
 gdb/target.h                     |  7 ++++--
 gdb/testsuite/ChangeLog          |  6 +++++
 gdb/testsuite/gdb.mi/mi-cli.exp  | 17 +++-----------
 gdb/testsuite/lib/mi-support.exp |  4 +++-
 14 files changed, 191 insertions(+), 65 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 2a384ba..6d8dca5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -43,6 +43,12 @@ maint ada show ignore-descriptive-types
   the user manual for more details on descriptive types and the intended
   usage of this option.
 
+maint set target-async (on|off)
+maint show target-async
+  This controls whether gdb targets operate in sync or async mode.
+  Normally the default is async, if it is available; but this can be
+  changed to more easily debug problems occurring only in sync mode.
+
 * New features in the GDB remote stub, GDBserver
 
   ** New option --debug-format=option1[,option2,...] allows one to add
@@ -76,6 +82,10 @@ maint ada show ignore-descriptive-types
 
 * The "catch syscall" command now works on s390*-linux* targets.
 
+* "set target-async" is deprecated as a CLI command and now only puts
+  MI into async mode.  Targets which are capable of it use the async
+  mode by default.
+
 * New remote packets
 
 qXfer:btrace:read's annex
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index de5ac63..3f7d99e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -5725,9 +5725,6 @@ To enter non-stop mode, use this sequence of commands before you run
 or attach to your program:
 
 @smallexample
-# Enable the async interface.  
-set target-async 1
-
 # If using the CLI, pagination breaks non-stop.
 set pagination off
 
@@ -5797,21 +5794,6 @@ the program to report that some thread has stopped before prompting for
 another command.  In background execution, @value{GDBN} immediately gives
 a command prompt so that you can issue other commands while your program runs.
 
-You need to explicitly enable asynchronous mode before you can use
-background execution commands.  You can use these commands to
-manipulate the asynchronous mode setting:
-
-@table @code
-@kindex set target-async
-@item set target-async on
-Enable asynchronous mode.
-@item set target-async off
-Disable asynchronous mode.
-@kindex show target-async
-@item show target-async
-Show the current target-async setting.
-@end table
-
 If the target doesn't support async mode, @value{GDBN} issues an error
 message if you attempt to use the background execution commands.
 
@@ -24713,6 +24695,17 @@ frontend has started the executable or attached to the target, it can
 find if asynchronous execution is enabled using the
 @code{-list-target-features} command.
 
+@table @code
+@kindex -gdb-set target-async
+@item -gdb-set target-async on
+Enable asynchronous mode.  This mode only affects MI commands.
+@item -gdb-set target-async off
+Disable asynchronous mode.
+@kindex -gdb-show target-async
+@item -gdb-show target-async
+Show the current target-async setting.
+@end table
+
 Even if @value{GDBN} can accept a command while target is running,
 many commands that access the target do not work when the target is
 running.  Therefore, asynchronous command execution is most useful
@@ -33421,6 +33414,14 @@ Control whether to show all non zero areas within a 1k block starting
 at thread local base, when using the @samp{info w32 thread-information-block}
 command.
 
+@kindex maint set target-async
+@kindex maint show target-async
+@item maint set target-async
+@itemx maint show target-async
+This controls whether gdb targets operate in sync or async mode.
+Normally the default is async, if it is available; but this can be
+changed to more easily debug problems occurring only in sync mode.
+
 @kindex maint set per-command
 @kindex maint show per-command
 @item maint set per-command
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 188a6e8..05bca8b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -247,7 +247,7 @@ set_observer_mode (char *args, int from_tty,
      going out we leave it that way.  */
   if (observer_mode)
     {
-      target_async_permitted = 1;
+      maint_async_permitted = 1;
       pagination_enabled = 0;
       non_stop = non_stop_1 = 1;
     }
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 5535462..844006d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4514,10 +4514,7 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int))
 static int
 linux_nat_is_async_p (struct target_ops *ops)
 {
-  /* NOTE: palves 2008-03-21: We're only async when the user requests
-     it explicitly with the "set target-async" command.
-     Someday, linux will always be async.  */
-  return target_async_permitted;
+  return maint_async_permitted;
 }
 
 /* target_can_async_p implementation.  */
@@ -4525,10 +4522,7 @@ linux_nat_is_async_p (struct target_ops *ops)
 static int
 linux_nat_can_async_p (struct target_ops *ops)
 {
-  /* NOTE: palves 2008-03-21: We're only async when the user requests
-     it explicitly with the "set target-async" command.
-     Someday, linux will always be async.  */
-  return target_async_permitted;
+  return maint_async_permitted;
 }
 
 static int
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 833e7f1..ef19af6 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -212,6 +212,24 @@ mi_interpreter_exec (void *data, const char *command)
 static int
 mi_interpreter_prompt_p (void *data)
 {
+  if (!interp_quiet_p (NULL))
+    {
+      /* This is a hack.  In order to replicate gdb's behavior from
+	 when target-async was not enabled by default, we need to
+	 print the MI prompt.  We can't return 1 here because that
+	 will invoke the CLI prompt-printing machinery, which is not
+	 what we want.  So, we print the prompt directly.
+	 
+	 We don't print the prompt when MI is in its special async
+	 mode and when the target is async-capable.  In this case the
+	 printing is handled elsewhere.  */
+      if (!target_async_permitted || !target_is_async_p ())
+	{
+	  fputs_unfiltered ("(gdb) \n", raw_stdout);
+	  gdb_flush (raw_stdout);
+	}
+    }
+
   return 0;
 }
 
@@ -303,8 +321,17 @@ 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.  However, if target
+     is async, and a synchronous command was issued, then we will
+     print the prompt elsewhere, after printing "*running".
+     target_is_async_p checks whether the target is async;
+     sync_execution checks whether a synchronous command was
+     issued.  */
+  if (!target_is_async_p () || !sync_execution)
+    {
+      fputs_unfiltered ("(gdb) \n", raw_stdout);
+      gdb_flush (raw_stdout);
+    }
 }
 
 static void
@@ -816,10 +843,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 earler.  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 161307a..8b061d5 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -104,6 +104,15 @@ static int register_changed_p (int regnum, struct regcache *,
 static void output_register (struct frame_info *, int regnum, int format,
 			     int skip_unavailable);
 
+/* A wrapper for target_can_async_p that takes the MI setting into
+   account.  */
+
+static int
+mi_target_can_async_p (void)
+{
+  return target_async_permitted && 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.  */
@@ -260,6 +269,11 @@ exec_continue (char **argv, int argc)
     {
       struct cleanup *back_to = make_cleanup_restore_integer (&sched_multi);
 
+      /* If MI is in sync mode but the target is async, then
+	 normal_stop enabled stdin.  We undo the change here.  */
+      if (!target_async_permitted && target_can_async_p ())
+	async_disable_stdin ();
+
       if (current_context->all)
 	{
 	  sched_multi = 1;
@@ -394,8 +408,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_target_can_async_p (),
+			  mi_target_can_async_p () ? "&" : NULL);
   return 0;
 }
 
@@ -449,8 +463,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_target_can_async_p (),
+			      mi_target_can_async_p () ? "&" : NULL);
     }
 }
 
@@ -1837,7 +1851,7 @@ 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_target_can_async_p ())
 	ui_out_field_string (uiout, NULL, "async");
       if (target_can_execute_reverse)
 	ui_out_field_string (uiout, NULL, "reverse");
@@ -2268,7 +2282,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_target_can_async_p ())
     run = xstrprintf ("%s %s&", cli_command, argc ? *argv : "");
   else
     run = xstrprintf ("%s %s", cli_command, argc ? *argv : "");
diff --git a/gdb/remote.c b/gdb/remote.c
index e03d3bf..94c7165 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -4263,7 +4263,7 @@ remote_open_1 (char *name, int from_tty,
 	   "(e.g. /dev/ttyS0, /dev/ttya, COM1, etc.)."));
 
   /* See FIXME above.  */
-  if (!target_async_permitted)
+  if (!maint_async_permitted)
     wait_forever_enabled_p = 1;
 
   /* If we're connected to a running target, target_preopen will kill it.
@@ -4350,7 +4350,7 @@ remote_open_1 (char *name, int from_tty,
   rs->use_threadinfo_query = 1;
   rs->use_threadextra_query = 1;
 
-  if (target_async_permitted)
+  if (maint_async_permitted)
     {
       /* With this target we start out by owning the terminal.  */
       remote_async_terminal_ours_p = 1;
@@ -4399,13 +4399,13 @@ remote_open_1 (char *name, int from_tty,
 	   already before throwing the exception.  */
 	if (rs->remote_desc != NULL)
 	  remote_unpush_target ();
-	if (target_async_permitted)
+	if (maint_async_permitted)
 	  wait_forever_enabled_p = 1;
 	throw_exception (ex);
       }
   }
 
-  if (target_async_permitted)
+  if (maint_async_permitted)
     wait_forever_enabled_p = 1;
 }
 
@@ -5135,7 +5135,7 @@ Give up (and stop debugging it)? ")))
 static void
 remote_terminal_inferior (struct target_ops *self)
 {
-  if (!target_async_permitted)
+  if (!maint_async_permitted)
     /* Nothing to do.  */
     return;
 
@@ -5158,7 +5158,7 @@ remote_terminal_inferior (struct target_ops *self)
 static void
 remote_terminal_ours (struct target_ops *self)
 {
-  if (!target_async_permitted)
+  if (!maint_async_permitted)
     /* Nothing to do.  */
     return;
 
@@ -11536,7 +11536,7 @@ remote_can_async_p (struct target_ops *ops)
 {
   struct remote_state *rs = get_remote_state ();
 
-  if (!target_async_permitted)
+  if (!maint_async_permitted)
     /* We only enable async when the user specifically asks for it.  */
     return 0;
 
@@ -11549,7 +11549,7 @@ remote_is_async_p (struct target_ops *ops)
 {
   struct remote_state *rs = get_remote_state ();
 
-  if (!target_async_permitted)
+  if (!maint_async_permitted)
     /* We only enable async when the user specifically asks for it.  */
     return 0;
 
diff --git a/gdb/target.c b/gdb/target.c
index 40a2a39..6711bd7 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4199,7 +4199,38 @@ maintenance_print_target_stack (char *cmd, int from_tty)
     }
 }
 
-/* Controls if async mode is permitted.  */
+/* Controls if targets can report that they are async.  This is just
+   for maintainers to use when debugging gdb.  */
+int maint_async_permitted = 0;
+
+/* The set command writes to this variable.  If the inferior is
+   executing, maint_async_permitted is *not* updated.  */
+static int maint_async_permitted_1 = 0;
+
+static void
+set_maint_async_command (char *args, int from_tty,
+			  struct cmd_list_element *c)
+{
+  if (have_live_inferiors ())
+    {
+      maint_async_permitted_1 = maint_async_permitted;
+      error (_("Cannot change this setting while the inferior is running."));
+    }
+
+  maint_async_permitted = maint_async_permitted_1;
+}
+
+static void
+show_maint_async_command (struct ui_file *file, int from_tty,
+			   struct cmd_list_element *c,
+			   const char *value)
+{
+  fprintf_filtered (file,
+		    _("Controlling the inferior in "
+		      "asynchronous mode is %s.\n"), value);
+}
+
+/* Controls if async mode is permitted.  This is used only by MI.  */
 int target_async_permitted = 0;
 
 /* The set command writes to this variable.  If the inferior is
@@ -4217,6 +4248,12 @@ set_target_async_command (char *args, int from_tty,
     }
 
   target_async_permitted = target_async_permitted_1;
+  /* Sometimes it is handy to run the test suite with "maint set
+     target-async off".  But, in this case, if the test suite uses
+     "set target-async on" we want to replicate the old behavior of
+     turning on target-async.  Hence we set these variables here.  */
+  maint_async_permitted = target_async_permitted_1;
+  maint_async_permitted_1 = target_async_permitted_1;
 }
 
 static void
@@ -4331,6 +4368,15 @@ Tells gdb whether to control the inferior in asynchronous mode."),
 			   show_target_async_command,
 			   &setlist,
 			   &showlist);
+  add_setshow_boolean_cmd ("target-async", no_class,
+			   &maint_async_permitted_1, _("\
+Set whether gdb controls the inferior in asynchronous mode."), _("\
+Show whether gdb controls the inferior in asynchronous mode."), _("\
+Tells gdb whether to control the inferior in asynchronous mode."),
+			   set_maint_async_command,
+			   show_maint_async_command,
+			   &maintenance_set_cmdlist,
+			   &maintenance_show_cmdlist);
 
   add_setshow_boolean_cmd ("may-write-registers", class_support,
 			   &may_write_registers_1, _("\
diff --git a/gdb/target.h b/gdb/target.h
index 871cc95..703af3a 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1612,10 +1612,13 @@ extern int default_child_has_execution (struct target_ops *ops,
 #define target_can_lock_scheduler \
      (current_target.to_has_thread_control & tc_schedlock)
 
-/* Should the target enable async mode if it is supported?  Temporary
-   cludge until async mode is a strict superset of sync mode.  */
+/* Should MI operate in async mode?  */
 extern int target_async_permitted;
 
+/* A maint setting so async-capable targets can enter sync mode for
+   debugging.  */
+extern int maint_async_permitted;
+
 /* Can the target support asynchronous execution?  */
 #define target_can_async_p() (current_target.to_can_async_p (&current_target))
 
diff --git a/gdb/testsuite/gdb.mi/mi-cli.exp b/gdb/testsuite/gdb.mi/mi-cli.exp
index e158b7e..8cfab3b 100644
--- a/gdb/testsuite/gdb.mi/mi-cli.exp
+++ b/gdb/testsuite/gdb.mi/mi-cli.exp
@@ -134,20 +134,9 @@ mi_gdb_test "500-stack-select-frame 0" \
   {500\^done} \
   "-stack-select-frame 0"
 
-# When a CLI command is entered in MI session, the respose is different in
-# sync and async modes. In sync mode normal_stop is called when current
-# interpreter is CLI. So:
-#   - print_stop_reason prints stop reason in CLI uiout, and we don't show it
-#     in MI
-#   - The stop position is printed, and appears in MI 'console' channel.
-#
-# In async mode the stop event is processed when we're back to MI interpreter,
-# so the stop reason is printed into MI uiout an.
-if {$async} {
-    set reason "end-stepping-range"
-} else {
-    set reason ""
-}
+# Allow a reason, or not.  Which we get depends at least on whether
+# the target being tested supports async.
+set reason ".*"
 
 mi_execute_to "interpreter-exec console step" $reason "callee4" "" ".*basics.c" $line_callee4_next \
     "" "check *stopped from CLI command"
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 213073a..16c7951 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1096,7 +1096,9 @@ proc mi_expect_stop { reason func args file line extra test } {
     }
 
     set r ""
-    if { $reason != "" } {
+    if { $reason == ".*" } {
+	set r "(?:reason=\".*\",)?"
+    } elseif { $reason != "" } {
 	set r "reason=\"$reason\","
     }
 
-- 
1.8.1.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]